',ko.innerHTML.indexOf(\"
\")>0}var vn=Object.f"
+ "reeze({}),mn=Object.prototype.toString,gn=u(\"slot,component\",!0),yn=u(\"key,ref,slot,slot-scope,is"
+ "\"),_n=Object.prototype.hasOwnProperty,bn=/-(\\w)/g,wn=p(function(t){return t.replace(bn,function(t,"
+ "e){return e?e.toUpperCase():\"\"})}),$n=p(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),"
+ "xn=/\\B([A-Z])/g,kn=p(function(t){return t.replace(xn,\"-$1\").toLowerCase()}),Cn=function(t,e,n){re"
+ "turn!1},An=function(t){return t},Sn=\"data-server-rendered\",On=[\"component\",\"directive\",\"filte"
+ "r\"],Tn=[\"beforeCreate\",\"created\",\"beforeMount\",\"mounted\",\"beforeUpdate\",\"updated\",\"bef"
+ "oreDestroy\",\"destroyed\",\"activated\",\"deactivated\",\"errorCaptured\"],jn={optionMergeStrategie"
+ "s:Object.create(null),silent:!1,productionTip:!1,devtools:!1,performance:!1,errorHandler:null,warnHa"
+ "ndler:null,ignoredElements:[],keyCodes:Object.create(null),isReservedTag:Cn,isReservedAttr:Cn,isUnkn"
+ "ownElement:Cn,getTagNamespace:g,parsePlatformTagName:An,mustUseProp:Cn,_lifecycleHooks:Tn},En=/[^\\w"
+ ".$]/,Ln=\"__proto__\"in{},In=\"undefined\"!=typeof window,Dn=\"undefined\"!=typeof WXEnvironment&&!!"
+ "WXEnvironment.platform,Fn=Dn&&WXEnvironment.platform.toLowerCase(),Nn=In&&window.navigator.userAgent"
+ ".toLowerCase(),Pn=Nn&&/msie|trident/.test(Nn),Mn=Nn&&Nn.indexOf(\"msie 9.0\")>0,Rn=Nn&&Nn.indexOf(\""
+ "edge/\")>0,Bn=Nn&&Nn.indexOf(\"android\")>0||\"android\"===Fn,Un=Nn&&/iphone|ipad|ipod|ios/.test(Nn)"
+ "||\"ios\"===Fn,Hn=(Nn&&/chrome\\/\\d+/.test(Nn),{}.watch),Vn=!1;if(In)try{var zn={};Object.definePro"
+ "perty(zn,\"passive\",{get:function(){Vn=!0}}),window.addEventListener(\"test-passive\",null,zn)}catc"
+ "h(t){}var Wn,qn,Jn=function(){return void 0===Wn&&(Wn=!In&&\"undefined\"!=typeof global&&\"server\"="
+ "==global.process.env.VUE_ENV),Wn},Kn=In&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,Xn=\"undefined\"!=typeo"
+ "f Symbol&&x(Symbol)&&\"undefined\"!=typeof Reflect&&x(Reflect.ownKeys);qn=\"undefined\"!=typeof Set&"
+ "&x(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){"
+ "return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){thi"
+ "s.set=Object.create(null)},t}();var Gn=g,Zn=0,Yn=function(){this.id=Zn++,this.subs=[]};Yn.prototype."
+ "addSub=function(t){this.subs.push(t)},Yn.prototype.removeSub=function(t){l(this.subs,t)},Yn.prototyp"
+ "e.depend=function(){Yn.target&&Yn.target.addDep(this)},Yn.prototype.notify=function(){for(var t=this"
+ ".subs.slice(),e=0,n=t.length;e
Sr&&$r[n].id>t.id;)n--;$r.splice(n+1,0,t)}else $r.push(t"
+ ");Cr||(Cr=!0,z(ut))}}(this)},Tr.prototype.run=function(){if(this.active){var t=this.get();if(t!==thi"
+ "s.value||i(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}c"
+ "atch(t){B(t,this.vm,'callback for watcher \"'+this.expression+'\"')}else this.cb.call(this.vm,t,e)}}"
+ "},Tr.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},Tr.prototype.depend=function"
+ "(){for(var t=this.deps.length;t--;)this.deps[t].depend()},Tr.prototype.teardown=function(){if(this.a"
+ "ctive){this.vm._isBeingDestroyed||l(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.dep"
+ "s[t].removeSub(this);this.active=!1}};var jr={enumerable:!0,configurable:!0,get:g,set:g},Er={lazy:!0"
+ "};Ct(At.prototype);var Lr={init:function(t,n,r,i){if(!t.componentInstance||t.componentInstance._isDe"
+ "stroyed)(t.componentInstance=function(t,n,o,a){var s={_isComponent:!0,parent:wr,_parentVnode:t,_pare"
+ "ntElm:r||null,_refElm:i||null},c=t.data.inlineTemplate;return e(c)&&(s.render=c.render,s.staticRende"
+ "rFns=c.staticRenderFns),new t.componentOptions.Ctor(s)}(t)).$mount(n?t.elm:void 0,n);else if(t.data."
+ "keepAlive){var o=t;Lr.prepatch(o,o)}},prepatch:function(t,e){var n=e.componentOptions;!function(t,e,"
+ "n,r,i){var o=!!(i||t.$options._renderChildren||r.data.scopedSlots||t.$scopedSlots!==vn);if(t.$option"
+ "s._parentVnode=r,t.$vnode=r,t._vnode&&(t._vnode.parent=r),t.$options._renderChildren=i,t.$attrs=r.da"
+ "ta&&r.data.attrs||vn,t.$listeners=n||vn,e&&t.$options.props){ar.shouldConvert=!1;for(var a=t._props,"
+ "s=t.$options._propKeys||[],c=0;c1?h(n):n;for(var r=h(arguments,1),i=0"
+ ",o=n.length;iparseInt(this.max)&&Ft(a,s[0],s,"
+ "this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={};e.get=function(){return"
+ " jn},Object.defineProperty(t,\"config\",e),t.util={warn:Gn,extend:v,mergeOptions:F,defineReactive:O}"
+ ",t.set=T,t.delete=j,t.nextTick=z,t.options=Object.create(null),On.forEach(function(e){t.options[e+\""
+ "s\"]=Object.create(null)}),t.options._base=t,v(t.options.components,Br),t.use=function(t){var e=this"
+ "._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=h(arguments,1);"
+ "return n.unshift(this),\"function\"==typeof t.install?t.install.apply(t,n):\"function\"==typeof t&&t"
+ ".apply(null,n),e.push(t),this},t.mixin=function(t){return this.options=F(this.options,t),this},funct"
+ "ion(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,i=t._Ctor||(t._Ctor={});if(i["
+ "r])return i[r];var o=t.name||n.options.name,a=function(t){this._init(t)};return(a.prototype=Object.c"
+ "reate(n.prototype)).constructor=a,a.cid=e++,a.options=F(n.options,t),a.super=n,a.options.props&&func"
+ "tion(t){var e=t.options.props;for(var n in e)lt(t.prototype,\"_props\",n)}(a),a.options.computed&&fu"
+ "nction(t){var e=t.options.computed;for(var n in e)ft(t.prototype,n,e[n])}(a),a.extend=n.extend,a.mix"
+ "in=n.mixin,a.use=n.use,On.forEach(function(t){a[t]=n[t]}),o&&(a.options.components[o]=a),a.superOpti"
+ "ons=n.options,a.extendOptions=t,a.sealedOptions=v({},a.options),i[r]=a,a}}(t),n=t,On.forEach(functio"
+ "n(t){n[t]=function(e,n){return n?(\"component\"===t&&o(n)&&(n.name=n.name||e,n=this.options._base.ex"
+ "tend(n)),\"directive\"===t&&\"function\"==typeof n&&(n={bind:n,update:n}),this.options[t+\"s\"][e]=n"
+ ",n):this.options[t+\"s\"][e]}});var n}(Et),Object.defineProperty(Et.prototype,\"$isServer\",{get:Jn}"
+ "),Object.defineProperty(Et.prototype,\"$ssrContext\",{get:function(){return this.$vnode&&this.$vnode"
+ ".ssrContext}}),Et.version=\"2.5.13\";var Ur,Hr,Vr,zr,Wr,qr,Jr,Kr,Xr=u(\"style,class\"),Gr=u(\"input,"
+ "textarea,option,select,progress\"),Zr=function(t,e,n){return\"value\"===n&&Gr(t)&&\"button\"!==e||\""
+ "selected\"===n&&\"option\"===t||\"checked\"===n&&\"input\"===t||\"muted\"===n&&\"video\"===t},Yr=u("
+ "\"contenteditable,draggable,spellcheck\"),Qr=u(\"allowfullscreen,async,autofocus,autoplay,checked,co"
+ "mpact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,fo"
+ "rmnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,"
+ "novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,tran"
+ "slate,truespeed,typemustmatch,visible\"),ti=\"http://www.w3.org/1999/xlink\",ei=function(t){return\""
+ ":\"===t.charAt(5)&&\"xlink\"===t.slice(0,5)},ni=function(t){return ei(t)?t.slice(6,t.length):\"\"},r"
+ "i=function(t){return null==t||!1===t},ii={svg:\"http://www.w3.org/2000/svg\",math:\"http://www.w3.or"
+ "g/1998/Math/MathML\"},oi=u(\"html,body,base,head,link,meta,style,title,address,article,aside,footer,"
+ "header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol"
+ ",p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,st"
+ "rong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscr"
+ "ipt,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,labe"
+ "l,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,"
+ "content,element,shadow,template,blockquote,iframe,tfoot\"),ai=u(\"svg,animate,circle,clippath,cursor"
+ ",defs,desc,ellipse,filter,font-face,foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,"
+ "pattern,polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view\",!0),si=function(t){return"
+ " oi(t)||ai(t)},ci=Object.create(null),ui=u(\"text,number,password,search,email,tel,url\"),li=Object."
+ "freeze({createElement:function(t,e){var n=document.createElement(t);return\"select\"!==t?n:(e.data&&"
+ "e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute(\"multiple\",\"multiple\"),n)},createEl"
+ "ementNS:function(t,e){return document.createElementNS(ii[t],e)},createTextNode:function(t){return do"
+ "cument.createTextNode(t)},createComment:function(t){return document.createComment(t)},insertBefore:f"
+ "unction(t,e,n){t.insertBefore(e,n)},removeChild:function(t,e){t.removeChild(e)},appendChild:function"
+ "(t,e){t.appendChild(e)},parentNode:function(t){return t.parentNode},nextSibling:function(t){return t"
+ ".nextSibling},tagName:function(t){return t.tagName},setTextContent:function(t,e){t.textContent=e},se"
+ "tAttribute:function(t,e,n){t.setAttribute(e,n)}}),fi={create:function(t,e){Ut(e)},update:function(t,"
+ "e){t.data.ref!==e.data.ref&&(Ut(t,!0),Ut(e))},destroy:function(t){Ut(t,!0)}},pi=new tr(\"\",{},[]),d"
+ "i=[\"create\",\"activate\",\"update\",\"remove\",\"destroy\"],hi={create:zt,update:zt,destroy:functi"
+ "on(t){zt(t,pi)}},vi=Object.create(null),mi=[fi,hi],gi={create:Jt,update:Jt},yi={create:Xt,update:Xt}"
+ ",_i=/[\\w).+\\-_$\\]]/,bi=\"__r\",wi=\"__c\",$i={create:de,update:de},xi={create:he,update:he},ki=p("
+ "function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\\))/g).forEach(function(t){if(t){var r=t.sp"
+ "lit(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}}),e}),Ci=/^--/,Ai=/\\s*!important$/,Si=function(t,e"
+ ",n){if(Ci.test(e))t.style.setProperty(e,n);else if(Ai.test(n))t.style.setProperty(e,n.replace(Ai,\""
+ "\"),\"important\");else{var r=Ti(e);if(Array.isArray(n))for(var i=0,o=n.length;id?h(n,t(i[_+1])?null:i[_+1].elm,i,p,_,o):p>_&&m(0,r,f,d)}(c,p,d,o,s):e"
+ "(d)?(e(r.text)&&C.setTextContent(c,\"\"),h(c,null,d,0,d.length-1,o)):e(p)?m(0,p,0,p.length-1):e(r.te"
+ "xt)&&C.setTextContent(c,\"\"):r.text!==i.text&&C.setTextContent(c,i.text),e(l)&&e(u=l.hook)&&e(u=u.p"
+ "ostpatch)&&u(r,i)}}}function _(t,r,i){if(n(i)&&e(t.parent))t.parent.data.pendingInsert=r;else for(va"
+ "r o=0;o-1?ci[t]=e.constructor===window"
+ ".HTMLUnknownElement||e.constructor===window.HTMLElement:ci[t]=/HTMLUnknownElement/.test(e.toString()"
+ ")},v(Et.options.directives,Vi),v(Et.options.components,Ji),Et.prototype.__patch__=In?Ui:g,Et.prototy"
+ "pe.$mount=function(t,e){return function(t,e,n){t.$el=e,t.$options.render||(t.$options.render=nr),ct("
+ "t,\"beforeMount\");return new Tr(t,function(){t._update(t._render(),n)},g,null,!0),n=!1,null==t.$vno"
+ "de&&(t._isMounted=!0,ct(t,\"mounted\")),t}(this,t=t&&In?Bt(t):void 0,e)},Et.nextTick(function(){jn.d"
+ "evtools&&Kn&&Kn.emit(\"init\",Et)},0);var Ki,Xi=/\\{\\{((?:.|\\n)+?)\\}\\}/g,Gi=/[-.*+?^${}()|[\\]"
+ "\\/\\\\]/g,Zi=p(function(t){var e=t[0].replace(Gi,\"\\\\$&\"),n=t[1].replace(Gi,\"\\\\$&\");return n"
+ "ew RegExp(e+\"((?:.|\\\\n)+?)\"+n,\"g\")}),Yi={staticKeys:[\"staticClass\"],transformNode:function(t"
+ ",e){e.warn;var n=ie(t,\"class\");n&&(t.staticClass=JSON.stringify(n));var r=re(t,\"class\",!1);r&&(t"
+ ".classBinding=r)},genData:function(t){var e=\"\";return t.staticClass&&(e+=\"staticClass:\"+t.static"
+ "Class+\",\"),t.classBinding&&(e+=\"class:\"+t.classBinding+\",\"),e}},Qi={staticKeys:[\"staticStyle"
+ "\"],transformNode:function(t,e){e.warn;var n=ie(t,\"style\");n&&(t.staticStyle=JSON.stringify(ki(n))"
+ ");var r=re(t,\"style\",!1);r&&(t.styleBinding=r)},genData:function(t){var e=\"\";return t.staticStyl"
+ "e&&(e+=\"staticStyle:\"+t.staticStyle+\",\"),t.styleBinding&&(e+=\"style:(\"+t.styleBinding+\"),\"),"
+ "e}},to=u(\"area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"
+ "\"),eo=u(\"colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source\"),no=u(\"address,article,aside,b"
+ "ase,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,foot"
+ "er,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,r"
+ "p,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track\"),ro=/^\\s*([^\\s\"'<>\\/=]+)(?:"
+ "\\s*(=)\\s*(?:\"([^\"]*)\"+|'([^']*)'+|([^\\s\"'=<>`]+)))?/,io=\"[a-zA-Z_][\\\\w\\\\-\\\\.]*\",oo=\""
+ "((?:\"+io+\"\\\\:)?\"+io+\")\",ao=new RegExp(\"^<\"+oo),so=/^\\s*(\\/?)>/,co=new RegExp(\"^<\\\\/\"+"
+ "oo+\"[^>]*>\"),uo=/^]+>/i,lo=/^/g,\"$1\").replace(//g,\"$1\")),Lo(p,n)&&(n=n.slice(1)"
+ "),e.chars&&e.chars(n),\"\"});l+=t.length-h.length,t=h,r(p,l-f,l)}else{var v=t.indexOf(\"<\");if(0==="
+ "v){if(lo.test(t)){var m=t.indexOf(\"--\\x3e\");if(m>=0){e.shouldKeepComment&&e.comment(t.substring(4"
+ ",m)),n(m+3);continue}}if(fo.test(t)){var g=t.indexOf(\"]>\");if(g>=0){n(g+2);continue}}var y=t.match"
+ "(uo);if(y){n(y[0].length);continue}var _=t.match(co);if(_){var b=l;n(_[0].length),r(_[1],b,l);contin"
+ "ue}var w=function(){var e=t.match(ao);if(e){var r={tagName:e[1],attrs:[],start:l};n(e[0].length);for"
+ "(var i,o;!(i=t.match(so))&&(o=t.match(ro));)n(o[0].length),r.attrs.push(o);if(i)return r.unarySlash="
+ "i[1],n(i[0].length),r.end=l,r}}();if(w){!function(t){var n=t.tagName,i=t.unarySlash;s&&(\"p\"===o&&n"
+ "o(n)&&r(o),u(n)&&o===n&&r(n));for(var l=c(n)||!!i,f=t.attrs.length,p=new Array(f),d=0;d=0){for(x=t.slice(v);!(co.test(x)||ao.test(x)||lo.test(x)||fo.test(x)||(k"
+ "=x.indexOf(\"<\",1))<0);)v+=k,x=t.slice(v);$=t.substring(0,v),n(v)}v<0&&($=t,t=\"\"),e.chars&&$&&e.c"
+ "hars($)}if(t===i){e.chars&&e.chars(t);break}}r()}(t,{warn:ho,expectHTML:e.expectHTML,isUnaryTag:e.is"
+ "UnaryTag,canBeLeftOpenTag:e.canBeLeftOpenTag,shouldDecodeNewlines:e.shouldDecodeNewlines,shouldDecod"
+ "eNewlinesForHref:e.shouldDecodeNewlinesForHref,shouldKeepComment:e.comments,start:function(t,a,u){va"
+ "r l=i&&i.ns||wo(t);Pn&&\"svg\"===l&&(a=function(t){for(var e=[],n=0;nc&&(s.push(o=t.slice("
+ "c,i)),a.push(JSON.stringify(o)));var u=Gt(r[1].trim());a.push(\"_s(\"+u+\")\"),s.push({\"@binding\":"
+ "u}),c=i+r[0].length}return c1?1:0:1:t?Math.min(t,2):0;va"
+ "r n}(e,n.length)]?n[e].trim():t}function a(t){return JSON.parse(JSON.stringify(t))}function s(t){for"
+ "(var n=arguments,r=Object(t),i=1;i=97&&e<=122||e>=65&&e<=90?\"ident\":e>=49&&e<=57?\"number\":\"else\"}funct"
+ "ion d(t){var e=t.trim();return(\"0\"!==t.charAt(0)||!isNaN(t))&&(n=e,N.test(n)?function(t){var e=t.c"
+ "harCodeAt(0);return e!==t.charCodeAt(t.length-1)||34!==e&&39!==e?t:t.slice(1,-1)}(e):\"*\"+e);var n}"
+ "var h,v=Object.prototype.toString,m=\"[object Object]\",g=Object.prototype.hasOwnProperty,y=\"undefi"
+ "ned\"!=typeof Intl&&void 0!==Intl.DateTimeFormat,_=\"undefined\"!=typeof Intl&&void 0!==Intl.NumberF"
+ "ormat,b={beforeCreate:function(){var t=this.$options;if(t.i18n=t.i18n||(t.__i18n?{}:null),t.i18n){if"
+ "(t.i18n instanceof M){if(t.__i18n)try{var e={};t.__i18n.forEach(function(t){e=s(e,JSON.parse(t))}),O"
+ "bject.keys(e).forEach(function(n){t.i18n.mergeLocaleMessage(n,e[n])})}catch(t){}this._i18n=t.i18n,th"
+ "is._i18nWatcher=this._i18n.watchI18nData(),this._i18n.subscribeDataChanging(this),this._subscribing="
+ "!0}else if(n(t.i18n)){if(this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof M&&(t.i18n.root=t"
+ "his.$root.$i18n,t.i18n.fallbackLocale=this.$root.$i18n.fallbackLocale,t.i18n.silentTranslationWarn=t"
+ "his.$root.$i18n.silentTranslationWarn),t.__i18n)try{var r={};t.__i18n.forEach(function(t){r=s(r,JSON"
+ ".parse(t))}),t.i18n.messages=r}catch(t){}this._i18n=new M(t.i18n),this._i18nWatcher=this._i18n.watch"
+ "I18nData(),this._i18n.subscribeDataChanging(this),this._subscribing=!0,(void 0===t.i18n.sync||t.i18n"
+ ".sync)&&(this._localeWatcher=this.$i18n.watchLocale())}}else this.$root&&this.$root.$i18n&&this.$roo"
+ "t.$i18n instanceof M?(this._i18n=this.$root.$i18n,this._i18n.subscribeDataChanging(this),this._subsc"
+ "ribing=!0):t.parent&&t.parent.$i18n&&t.parent.$i18n instanceof M&&(this._i18n=t.parent.$i18n,this._i"
+ "18n.subscribeDataChanging(this),this._subscribing=!0)},beforeDestroy:function(){this._i18n&&(this._s"
+ "ubscribing&&(this._i18n.unsubscribeDataChanging(this),delete this._subscribing),this._i18nWatcher&&("
+ "this._i18nWatcher(),delete this._i18nWatcher),this._localeWatcher&&(this._localeWatcher(),delete thi"
+ "s._localeWatcher),this._i18n=null)}},w={name:\"i18n\",functional:!0,props:{tag:{type:String,default:"
+ "\"span\"},path:{type:String,required:!0},locale:{type:String},places:{type:[Array,Object]}},render:f"
+ "unction(e,n){var r=n.props,i=n.data,o=n.children,a=n.parent.$i18n;if(o=(o||[]).filter(function(t){re"
+ "turn t.tag||(t.text=t.text.trim())}),!a)return o;var s=r.path,c=r.locale,u={},l=r.places||{},f=Array"
+ ".isArray(l)?l.length>0:Object.keys(l).length>0,p=o.every(function(t){if(t.data&&t.data.attrs){var e="
+ "t.data.attrs.place;return void 0!==e&&\"\"!==e}});return f&&o.length>0&&!p&&t(\"If places prop is se"
+ "t, all child elements must have place prop set.\"),Array.isArray(l)?l.forEach(function(t,e){u[e]=t})"
+ ":Object.keys(l).forEach(function(t){u[t]=l[t]}),o.forEach(function(t,e){var n=p?\"\"+t.data.attrs.pl"
+ "ace:\"\"+e;u[n]=t}),e(r.tag,i,a.i(s,c,u))}},$=function(){this._caches=Object.create(null)};$.prototy"
+ "pe.interpolate=function(t,n){var r=this._caches[t];return r||(r=function(t){for(var e=[],n=0,r=\"\";"
+ "n0)f--,l=j,h[C]();else{if(f=0,!1===(n=d(n)))return!1;h[A]()}};null!==l;)if"
+ "(u++,\"\\\\\"!==(e=t[u])||!function(){var e=t[u+1];if(l===E&&\"'\"===e||l===L&&'\"'===e)return u++,r"
+ "=\"\\\\\"+e,h[C](),!0}()){if(i=p(e),(o=(s=F[l])[i]||s.else||D)===D)return;if(l=o[0],(a=h[o[1]])&&(r="
+ "o[2],r=void 0===r?e:r,!1===a()))return;if(l===I)return c}}(t))&&(this._cache[t]=e),e||[]},P.prototyp"
+ "e.getPathValue=function(t,n){if(!e(t))return null;var r=this.parsePath(n);if(i=r,Array.isArray(i)&&0"
+ "===i.length)return null;for(var i,o=r.length,a=t,s=0;s-1)t.splice(n,1)}}(this._dataListene"
+ "rs,t)},M.prototype.watchI18nData=function(){var t=this;return this._vm.$watch(\"$data\",function(){f"
+ "or(var e=t._dataListeners.length;e--;)h.nextTick(function(){t._dataListeners[e]&&t._dataListeners[e]"
+ ".$forceUpdate()})},{deep:!0})},M.prototype.watchLocale=function(){if(!this._sync||!this._root)return"
+ " null;var t=this._vm;return this._root.vm.$watch(\"locale\",function(e){t.$set(t,\"locale\",e),t.$fo"
+ "rceUpdate()},{immediate:!0})},R.vm.get=function(){return this._vm},R.messages.get=function(){return "
+ "a(this._getMessages())},R.dateTimeFormats.get=function(){return a(this._getDateTimeFormats())},R.num"
+ "berFormats.get=function(){return a(this._getNumberFormats())},R.locale.get=function(){return this._v"
+ "m.locale},R.locale.set=function(t){this._vm.$set(this._vm,\"locale\",t)},R.fallbackLocale.get=functi"
+ "on(){return this._vm.fallbackLocale},R.fallbackLocale.set=function(t){this._vm.$set(this._vm,\"fallb"
+ "ackLocale\",t)},R.missing.get=function(){return this._missing},R.missing.set=function(t){this._missi"
+ "ng=t},R.formatter.get=function(){return this._formatter},R.formatter.set=function(t){this._formatter"
+ "=t},R.silentTranslationWarn.get=function(){return this._silentTranslationWarn},R.silentTranslationWa"
+ "rn.set=function(t){this._silentTranslationWarn=t},M.prototype._getMessages=function(){return this._v"
+ "m.messages},M.prototype._getDateTimeFormats=function(){return this._vm.dateTimeFormats},M.prototype."
+ "_getNumberFormats=function(){return this._vm.numberFormats},M.prototype._warnDefault=function(t,e,n,"
+ "i){return r(n)?(this.missing&&this.missing.apply(null,[t,e,i]),e):n},M.prototype._isFallbackRoot=fun"
+ "ction(t){return!t&&!r(this._root)&&this._fallbackRoot},M.prototype._interpolate=function(t,e,i,o,a,s"
+ "){if(!e)return null;var c=this._path.getPathValue(e,i);if(Array.isArray(c))return c;var u;if(r(c)){i"
+ "f(!n(e))return null;if(\"string\"!=typeof(u=e[i]))return null}else{if(\"string\"!=typeof c)return nu"
+ "ll;u=c}return u.indexOf(\"@:\")>=0&&(u=this._link(t,e,u,o,a,s)),s?this._render(u,a,s):u},M.prototype"
+ "._link=function(t,e,n,r,i,o){var a=n,s=a.match(/(@:[\\w\\-_|.]+)/g);for(var c in s)if(s.hasOwnProper"
+ "ty(c)){var u=s[c],l=u.substr(2),f=this._interpolate(t,e,l,r,\"raw\"===i?\"string\":i,\"raw\"===i?voi"
+ "d 0:o);if(this._isFallbackRoot(f)){if(!this._root)throw Error(\"unexpected error\");var p=this._root"
+ ";f=p._translate(p._getMessages(),p.locale,p.fallbackLocale,l,r,i,o)}a=(f=this._warnDefault(t,l,f,r))"
+ "?a.replace(u,f):a}return a},M.prototype._render=function(t,e,n){var r=this._formatter.interpolate(t,"
+ "n);return\"string\"===e?r.join(\"\"):r},M.prototype._translate=function(t,e,n,i,o,a,s){var c=this._i"
+ "nterpolate(e,t[e],i,o,a,s);return r(c)?r(c=this._interpolate(n,t[n],i,o,a,s))?null:c:c},M.prototype."
+ "_t=function(t,e,n,r){for(var o=[],a=arguments.length-4;a-- >0;)o[a]=arguments[a+4];if(!t)return\"\";"
+ "var s=i.apply(void 0,o),c=s.locale||e,u=this._translate(n,c,this.fallbackLocale,t,r,\"string\",s.par"
+ "ams);if(this._isFallbackRoot(u)){if(!this._root)throw Error(\"unexpected error\");return(l=this._roo"
+ "t).t.apply(l,[t].concat(o))}return this._warnDefault(c,t,u,r);var l},M.prototype.t=function(t){for(v"
+ "ar e=[],n=arguments.length-1;n-- >0;)e[n]=arguments[n+1];return(r=this)._t.apply(r,[t,this.locale,th"
+ "is._getMessages(),null].concat(e));var r},M.prototype._i=function(t,e,n,r,i){var o=this._translate(n"
+ ",e,this.fallbackLocale,t,r,\"raw\",i);if(this._isFallbackRoot(o)){if(!this._root)throw Error(\"unexp"
+ "ected error\");return this._root.i(t,e,i)}return this._warnDefault(e,t,o,r)},M.prototype.i=function("
+ "t,e,n){return t?(\"string\"!=typeof e&&(e=this.locale),this._i(t,e,this._getMessages(),null,n)):\"\""
+ "},M.prototype._tc=function(t,e,n,r,i){for(var a=[],s=arguments.length-5;s-- >0;)a[s]=arguments[s+5];"
+ "return t?(void 0===i&&(i=1),o((c=this)._t.apply(c,[t,e,n,r].concat(a)),i)):\"\";var c},M.prototype.t"
+ "c=function(t,e){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];return(i=this)._tc.app"
+ "ly(i,[t,this.locale,this._getMessages(),null,e].concat(n));var i},M.prototype._te=function(t,e,n){fo"
+ "r(var r=[],o=arguments.length-3;o-- >0;)r[o]=arguments[o+3];var a=i.apply(void 0,r).locale||e;return"
+ " this._exist(n[a],t)},M.prototype.te=function(t,e){return this._te(t,this.locale,this._getMessages()"
+ ",e)},M.prototype.getLocaleMessage=function(t){return a(this._vm.messages[t]||{})},M.prototype.setLoc"
+ "aleMessage=function(t,e){this._vm.messages[t]=e},M.prototype.mergeLocaleMessage=function(t,e){this._"
+ "vm.messages[t]=h.util.extend(this._vm.messages[t]||{},e)},M.prototype.getDateTimeFormat=function(t){"
+ "return a(this._vm.dateTimeFormats[t]||{})},M.prototype.setDateTimeFormat=function(t,e){this._vm.date"
+ "TimeFormats[t]=e},M.prototype.mergeDateTimeFormat=function(t,e){this._vm.dateTimeFormats[t]=h.util.e"
+ "xtend(this._vm.dateTimeFormats[t]||{},e)},M.prototype._localizeDateTime=function(t,e,n,i,o){var a=e,"
+ "s=i[a];if((r(s)||r(s[o]))&&(a=n,s=i[a]),r(s)||r(s[o]))return null;var c=s[o],u=a+\"__\"+o,l=this._da"
+ "teTimeFormatters[u];return l||(l=this._dateTimeFormatters[u]=new Intl.DateTimeFormat(a,c)),l.format("
+ "t)},M.prototype._d=function(t,e,n){if(!n)return new Intl.DateTimeFormat(e).format(t);var r=this._loc"
+ "alizeDateTime(t,e,this.fallbackLocale,this._getDateTimeFormats(),n);if(this._isFallbackRoot(r)){if(!"
+ "this._root)throw Error(\"unexpected error\");return this._root.d(t,n,e)}return r||\"\"},M.prototype."
+ "d=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=this.locale,o=null"
+ ";return 1===n.length?\"string\"==typeof n[0]?o=n[0]:e(n[0])&&(n[0].locale&&(i=n[0].locale),n[0].key&"
+ "&(o=n[0].key)):2===n.length&&(\"string\"==typeof n[0]&&(o=n[0]),\"string\"==typeof n[1]&&(i=n[1])),t"
+ "his._d(t,i,o)},M.prototype.getNumberFormat=function(t){return a(this._vm.numberFormats[t]||{})},M.pr"
+ "ototype.setNumberFormat=function(t,e){this._vm.numberFormats[t]=e},M.prototype.mergeNumberFormat=fun"
+ "ction(t,e){this._vm.numberFormats[t]=h.util.extend(this._vm.numberFormats[t]||{},e)},M.prototype._lo"
+ "calizeNumber=function(t,e,n,i,o){var a=e,s=i[a];if((r(s)||r(s[o]))&&(a=n,s=i[a]),r(s)||r(s[o]))retur"
+ "n null;var c=s[o],u=a+\"__\"+o,l=this._numberFormatters[u];return l||(l=this._numberFormatters[u]=ne"
+ "w Intl.NumberFormat(a,c)),l.format(t)},M.prototype._n=function(t,e,n){if(!n)return new Intl.NumberFo"
+ "rmat(e).format(t);var r=this._localizeNumber(t,e,this.fallbackLocale,this._getNumberFormats(),n);if("
+ "this._isFallbackRoot(r)){if(!this._root)throw Error(\"unexpected error\");return this._root.n(t,n,e)"
+ "}return r||\"\"},M.prototype.n=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments["
+ "r+1];var i=this.locale,o=null;return 1===n.length?\"string\"==typeof n[0]?o=n[0]:e(n[0])&&(n[0].loca"
+ "le&&(i=n[0].locale),n[0].key&&(o=n[0].key)):2===n.length&&(\"string\"==typeof n[0]&&(o=n[0]),\"strin"
+ "g\"==typeof n[1]&&(i=n[1])),this._n(t,i,o)},Object.defineProperties(M.prototype,R),M.availabilities="
+ "{dateTimeFormat:y,numberFormat:_},M.install=function t(e){(h=e).version&&Number(h.version.split(\"."
+ "\")[0]),t.installed=!0,Object.defineProperty(h.prototype,\"$i18n\",{get:function(){return this._i18n"
+ "}}),n=h,Object.defineProperty(n.prototype,\"$t\",{get:function(){var t=this;return function(e){for(v"
+ "ar n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=t.$i18n;return i._t.apply(i,[e,i.loca"
+ "le,i._getMessages(),t].concat(n))}}}),Object.defineProperty(n.prototype,\"$tc\",{get:function(){var "
+ "t=this;return function(e,n){for(var r=[],i=arguments.length-2;i-- >0;)r[i]=arguments[i+2];var o=t.$i"
+ "18n;return o._tc.apply(o,[e,o.locale,o._getMessages(),t,n].concat(r))}}}),Object.defineProperty(n.pr"
+ "ototype,\"$te\",{get:function(){var t=this;return function(e,n){var r=t.$i18n;return r._te(e,r.local"
+ "e,r._getMessages(),n)}}}),Object.defineProperty(n.prototype,\"$d\",{get:function(){var t=this;return"
+ " function(e){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(i=t.$i18n).d.apply"
+ "(i,[e].concat(n));var i}}}),Object.defineProperty(n.prototype,\"$n\",{get:function(){var t=this;retu"
+ "rn function(e){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(i=t.$i18n).n.app"
+ "ly(i,[e].concat(n));var i}}}),h.mixin(b),h.directive(\"t\",{bind:c,update:u}),h.component(w.name,w);"
+ "var n,r=h.config.optionMergeStrategies;r.i18n=r.methods},M.version=\"7.3.3\",\"undefined\"!=typeof w"
+ "indow&&window.Vue&&window.Vue.use(M),M});var messages={en:{title:\"Stairs\",systemID:\"System ID\",f"
+ "irmwareVersion:\"Firmware version: \",copyright:\"Copyright © 2017 Mark van Renswoude\",loading:\"Pl"
+ "ease wait, loading configuration...\",applyButton:\"Apply\",applyButtonSaving:\"Saving...\",wifiStat"
+ "us:{accesspoint:{title:\"AP: \",disabled:\"Disabled\"},stationmode:{title:\"WiFi: \",disabled:\"Disa"
+ "bled\",idle:\"Idle\",noSSID:\"SSID not found\",scanCompleted:\"Scan completed\",connectFailed:\"Fail"
+ "ed to connect\",connectionLost:\"Connection lost\",disconnected:\"Disconnected\"}},status:{tabTitle:"
+ "\"Status\",title:\"Current status\"},triggers:{tabTitle:\"Triggers\",timeTitle:\"Time\",motionTitle:"
+ "\"Motion\"},connection:{tabTitle:\"Connection\",title:\"Connection parameters\",accesspoint:\"Enable"
+ " access point\",accesspointHint:\"Allows for a direct connection from your device to this Stairs mod"
+ "ule for configuration purposes. The Stairs configuration is available on http://192.168.1.4/ when yo"
+ "u are connected to it. Turn it off as soon as station mode is configured, as it is not secured in an"
+ "y way. You can always turn this option back on by pushing the access point button until the LED ligh"
+ "ts up.\",stationmode:\"Enable station mode\",stationmodeHint:\"Connect this Stairs module to your ow"
+ "n WiFi router. Please enter the SSID, password and further configuration below.\",ssid:\"SSID\",pass"
+ "word:\"Password\",dhcp:\"Use DHCP\",dhcpHint:\"Automatically assigns an IP address to this Stairs mo"
+ "dule. You probably want to keep this on unless you know what you're doing.\",ipaddress:\"IP address"
+ "\",subnetmask:\"Subnet mask\",gateway:\"Gateway\",hostname:\"Hostname\",hostnamePlaceholder:\"Defaul"
+ "t: mac address\"}},nl:{title:\"Trap\",systemID:\"Systeem ID\",firmwareVersion:\"Firmware versie: \","
+ "copyright:\"Copyright © 2017 Mark van Renswoude\",loading:\"Een ogenblik geduld, bezig met laden van"
+ " configuratie...\",applyButton:\"Apply\",applyButtonSaving:\"Saving...\",wifiStatus:{accesspoint:{ti"
+ "tle:\"AP: \",disabled:\"Uitgeschakeld\"},stationmode:{title:\"WiFi: \",disabled:\"Uitgeschakeld\",id"
+ "le:\"Slaapstand\",noSSID:\"SSID niet gevonden\",scanCompleted:\"Scan afgerond\",connectFailed:\"Kan "
+ "geen verbinding maken\",connectionLost:\"Verbinding verloren\",disconnected:\"Niet verbonden\"}},sta"
+ "tus:{tabTitle:\"Status\",title:\"Huidige status\"},triggers:{tabTitle:\"Triggers\",timeTitle:\"Tijd"
+ "\",motionTitle:\"Beweging\"},connection:{tabTitle:\"Verbinding\",title:\"Verbinding configuratie\",a"
+ "ccesspoint:\"Access point inschakelen\",accesspointhint:\"Maakt het mogelijk om een directe connecti"
+ "e vanaf een apparaat naar deze Trap module te maken om de module te configureren. De Trap module is "
+ "te benaderen via http://192.168.1.4/ nadat je connectie hebt gemaakt. Schakel deze optie uit na het "
+ "configureren, aangezien deze niet beveiligd is. Je kunt deze optie ook inschakelen door op de Access"
+ " point knop te drukken totdat de LED aan gaat.\",stationmode:\"Verbinding met WiFi maken\",stationmo"
+ "dehint:\"Verbind deze Trap module aan je eigen WiFi router. Vul hieronder het SSID en wachtwoord in,"
+ " en configureer eventuel de overige opties.\",ssid:\"SSID\",password:\"Wachtwoord\",dhcp:\"Gebruik D"
+ "HCP\",dhcphint:\"Automatisch een IP adres toewijzen aan deze Trap module. Waarschijnlijk wil je deze"
+ " optie aan laten, tenzij je weet waar je mee bezig bent.\",ipaddress:\"IP adres\",subnetmask:\"Subne"
+ "t masker\",gateway:\"Gateway\",hostname:\"Hostnaam\",hostnamePlaceholder:\"Standaard: mac adres\"}}}"
+ ";function startApp(){var t=new VueI18n({locale:navigator.language,fallbackLocale:\"en\",messages:mes"
+ "sages});new Vue({el:\"#app\",i18n:t,data:{loading:!0,saving:!1,loadingIndicator:\"|\",activeTab:\"st"
+ "atus\",version:{systemID:\"loading...\",version:\"loading...\"},wifiStatus:{ap:{enabled:!1,ip:\"0.0."
+ "0.0\"},station:{enabled:!1,status:0,ip:\"0.0.0.0\"}},connection:{hostname:null,accesspoint:!0,statio"
+ "n:!1,ssid:null,password:null,dhcp:!0,ip:null,subnetmask:null,gateway:null},steps:[{value:50},{value:"
+ "0},{value:0},{value:0},{value:0},{value:70},{value:0},{value:0},{value:0},{value:0},{value:25},{valu"
+ "e:0},{value:0},{value:0}]},created:function(){var e=this;document.title=t.t(\"title\"),e.startLoadin"
+ "gIndicator(),e.updateWiFiStatus(),setInterval(e.updateWiFiStatus,5e3),axios.get(\"/api/version\").th"
+ "en(function(t){\"object\"==typeof t.data&&(e.version=t.data)}).catch(function(t){console.log(t)}),ax"
+ "ios.all([axios.get(\"/api/connection\").then(function(t){\"object\"==typeof t.data&&(e.connection=t."
+ "data)}).catch(function(t){console.log(t)})]).then(axios.spread(function(t,n){e.stopLoadingIndicator("
+ "),e.loading=!1}))},methods:{applyConnection:function(){var t=this;t.saving||(t.saving=!0,axios.post("
+ "\"/api/connection\",{hostname:t.connection.hostname,accesspoint:t.connection.accesspoint,station:t.c"
+ "onnection.station,ssid:t.connection.ssid,password:t.connection.password,dhcp:t.connection.dhcp,ip:t."
+ "connection.ip,subnetmask:t.connection.subnetmask,gateway:t.connection.gateway}).then(function(t){})."
+ "catch(function(t){console.log(t)}).then(function(){t.saving=!1}))},startLoadingIndicator:function(){"
+ "var t=this;t.loadingStage=0,t.loadingTimer=setInterval(function(){switch(t.loadingStage++,console.lo"
+ "g(t.loadingStage),t.loadingStage){case 1:t.loadingIndicator=\"/\";break;case 2:t.loadingIndicator=\""
+ "-\";break;case 3:t.loadingIndicator=\"\\\\\";break;case 4:t.loadingIndicator=\"|\",t.loadingStage=0}"
+ "},250)},stopLoadingIndicator:function(){clearInterval(this.loadingTimer)},getWiFiStationStatus:funct"
+ "ion(){if(!this.wifiStatus.station.enabled)return\"disconnected\";switch(this.wifiStatus.station.stat"
+ "us){case 0:case 2:return\"connecting\";case 1:case 4:case 5:return\"error\";case 3:return\"connected"
+ "\";case 6:default:return\"disconnected\"}},getWiFiStationStatusText:function(){if(!this.wifiStatus.s"
+ "tation.enabled)return t.t(\"wifiStatus.stationmode.disabled\");switch(this.wifiStatus.station.status"
+ "){case 0:return t.t(\"wifiStatus.stationmode.idle\");case 1:return t.t(\"wifiStatus.stationmode.noSS"
+ "ID\");case 2:return t.t(\"wifiStatus.stationmode.scanCompleted\");case 3:return this.wifiStatus.stat"
+ "ion.ip;case 4:return t.t(\"wifiStatus.stationmode.connectFailed\");case 5:return t.t(\"wifiStatus.st"
+ "ationmode.connectionLost\");case 6:default:return t.t(\"wifiStatus.stationmode.disconnected\")}},upd"
+ "ateWiFiStatus:function(){var t=this;t.saving||axios.get(\"/api/connection/status\").then(function(e)"
+ "{\"object\"==typeof e.data&&(t.wifiStatus=e.data)}).catch(function(t){console.log(t)})}}})}";
+
+#endif
diff --git a/src/assets/version.h b/src/assets/version.h
new file mode 100644
index 0000000..76ae8d0
--- /dev/null
+++ b/src/assets/version.h
@@ -0,0 +1,14 @@
+#ifndef __assets_version
+#define __assets_version
+
+const uint8_t VersionMajor = 2;
+const uint8_t VersionMinor = 0;
+const uint8_t VersionPatch = 0;
+const uint8_t VersionMetadata = 0;
+const char VersionBranch[] = "release/2.0";
+const char VersionSha[] = "3099dd8a0e2e5fa771e6a864a1daa83de5998df0";
+const char VersionSemVer[] = "2.0.0-beta.1";
+const char VersionFullSemVer[] = "2.0.0-beta.1+0";
+const char VersionCommitDate[] = "2017-10-05";
+
+#endif
diff --git a/src/charproperties.cpp b/src/charproperties.cpp
new file mode 100644
index 0000000..9c651e6
--- /dev/null
+++ b/src/charproperties.cpp
@@ -0,0 +1,26 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#include "charproperties.h"
+#include
+#include
+#include "debug.h"
+
+void CharProperties::assignChar(char** field, const char* newValue)
+{
+ if (*field != NULL)
+ delete *field;
+
+ if (newValue != NULL)
+ {
+ // Include the terminating null character
+ size_t length = strlen(newValue) + 1;
+ *field = new char[length];
+ strncpy(*field, newValue, length);
+ }
+ else
+ *field = NULL;
+}
\ No newline at end of file
diff --git a/src/charproperties.h b/src/charproperties.h
new file mode 100644
index 0000000..3ef9df4
--- /dev/null
+++ b/src/charproperties.h
@@ -0,0 +1,18 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#ifndef __charproperties
+#define __charproperties
+
+#include
+
+class CharProperties
+{
+ protected:
+ void assignChar(char** field, const char* newValue);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/config.h b/src/config.h
index c7ee869..c0569d5 100644
--- a/src/config.h
+++ b/src/config.h
@@ -1,26 +1,20 @@
-#ifndef __Config
-#define __Config
+#ifndef __config
+#define __config
-#include
#include
-#include "credentials.h"
+
+#define SerialDebug
+static const uint32_t SerialDebugBaudrate = 115200;
+static const uint32_t SerialDebugStartupDelay = 2000;
-//#define SerialDebug
-
-
-// The name of this device on the network
-static const char* WiFiHostname = "Stairs";
-
-
-// The number of steps (assumed to be <= 16, as the code currently only controls 1 PCA9685 board)
-static const uint8_t StepCount = 14;
-
-
-// The port number on which the UDP server listens
-static const uint16_t UDPPort = 3126;
+static const char* ConnectionSettingsFile = "/settings.json";
+static const char* DefaultAPSSIDPrefix = "Stairs-";
+
+static const uint32_t StationModeTimeout = 30000;
+/*
// Pins for the I2C bus
static const uint8_t PinSDA = 13;
static const uint8_t PinSCL = 12;
@@ -29,28 +23,6 @@ static const uint8_t PinSCL = 12;
// I2C address and PWM frequency of the PCA9685 board
static const uint8_t PWMDriverAddress = 0x40;
static const uint16_t PWMDriverPWMFrequency = 1600;
-
-
-// Determines if OTA firmware updates are enabled
-// 0 - Disabled
-// 1 - Enabled (fixed URL)
-// 2 - Enabled (use URL in command)
-static const uint8_t OTAUpdateEnabled = 2;
-
-static const char* OTAUpdateFixedHost = "";
-static const uint16_t OTAUpdateFixedPort = 80;
-static const char* OTAUpdateFixedPath = "/";
-
-// The minimum amount of time (in milliseconds) between update requests
-static const uint32_t OTAUpdateThrottle = 5000;
-
-
-#ifdef SerialDebug
-#define _d(msg) Serial.print(msg)
-#define _dln(msg) Serial.println(msg)
-#else
-#define _d(msg) do { } while (0)
-#define _dln(msg) do { } while (0)
-#endif
+*/
#endif
\ No newline at end of file
diff --git a/src/credentials.example.h b/src/credentials.example.h
deleted file mode 100644
index b77597e..0000000
--- a/src/credentials.example.h
+++ /dev/null
@@ -1,3 +0,0 @@
-// Create a copy of this file called "credentials.h"
-static const char* WiFiSSID = "example";
-static const char* WiFiPassword = "example";
\ No newline at end of file
diff --git a/src/debug.cpp b/src/debug.cpp
new file mode 100644
index 0000000..a43be50
--- /dev/null
+++ b/src/debug.cpp
@@ -0,0 +1,17 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#include "debug.h"
+
+
+void _dinit()
+{
+ #ifdef SerialDebug
+ Serial.begin(SerialDebugBaudrate);
+ Serial.setDebugOutput(true);
+ delay(SerialDebugStartupDelay);
+ #endif
+}
\ No newline at end of file
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..f722331
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,24 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#ifndef __serialdebug
+#define __serialdebug
+
+#include "config.h"
+#include
+
+void _dinit();
+
+#ifdef SerialDebug
+ #define _d(msg) Serial.print(msg)
+ #define _dln(msg) Serial.println(msg)
+#else
+ #define _d(msg) do { } while (0)
+ #define _dln(msg) do { } while (0)
+#endif
+
+
+#endif
\ No newline at end of file
diff --git a/src/global.cpp b/src/global.cpp
new file mode 100644
index 0000000..ed8fd77
--- /dev/null
+++ b/src/global.cpp
@@ -0,0 +1,15 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#include "global.h"
+
+ConnectionSettings* connectionSettings = new ConnectionSettings();
+bool connectionSettingsChanged = false;
+
+uint32_t currentTime;
+
+
+IPAddress emptyIP(0, 0, 0, 0);
diff --git a/src/global.h b/src/global.h
new file mode 100644
index 0000000..1931b61
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,21 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#ifndef __global
+#define __global
+
+#include
+#include
+#include
+#include "settings/connection.h"
+
+extern ConnectionSettings* connectionSettings;
+extern bool connectionSettingsChanged;
+extern uint32_t currentTime;
+
+extern IPAddress emptyIP;
+
+#endif
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index e5b5fd1..24198fb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,28 +1,225 @@
/*
* Stairs lighting
* Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
*/
-#include
-#include
+#include
#include
-#include
-#include
+#include
+#include
+
+extern "C" {
+ #include
+}
#include "config.h"
-#include "protocol.h"
-#include "components\PCA9685.h"
-//#include "modes\adc.h"
-#include "modes\alternate.h"
-#include "modes\custom.h"
-#include "modes\slide.h"
-#include "modes\static.h"
-#include "stairs.h"
-#include "version.h"
+#include "debug.h"
+#include "settings/connection.h"
+#include "global.h"
+#include "server/static.h"
+#include "server/api.h"
-PCA9685* pwmDriver;
-Stairs* stairs;
-WiFiUDP udpServer;
+ADC_MODE(ADC_VCC);
+
+// Forward declarations
+void initWiFi();
+#ifdef SerialDebug
+void wifiEvent(WiFiEvent_t event);
+#endif
+void updateLED();
+
+void startServer();
+void stopServer();
+void handleNotFound(AsyncWebServerRequest* request);
+
+
+AsyncWebServer server(80);
+bool accessPoint = false;
+bool stationMode = false;
+bool forceAccessPoint = false;
+
+uint32_t stationModeStart = 0;
+
+
+void setup()
+{
+ _dinit();
+ currentTime = millis();
+
+ if (!SPIFFS.begin())
+ _dln("Setup :: failed to mount file system");
+
+ connectionSettings->read();
+
+ _dln("Setup :: initializing WiFi");
+ WiFi.persistent(false);
+ WiFi.mode(WIFI_OFF);
+
+ #ifdef SerialDebug
+ // onEvent is already deprecated, but since I'm only using it
+ // for debug purposes we'll see how long it lasts...
+ WiFi.onEvent(wifiEvent);
+ _d("WiFi :: MAC address: ");
+ _dln(WiFi.macAddress());
+ #endif
+
+ initWiFi();
+
+ _dln("Setup :: registering routes");
+ registerStaticRoutes(&server);
+ registerAPIRoutes(&server);
+
+ _dln("Setup :: starting HTTP server");
+ server.onNotFound(handleNotFound);
+ server.begin();
+}
+
+
+void loop()
+{
+ currentTime = millis();
+
+ if (connectionSettingsChanged)
+ {
+ _dln("Loop :: connection settings changed");
+ initWiFi();
+ connectionSettingsChanged = false;
+ }
+
+
+ if (stationModeStart > 0)
+ {
+ bool isConnected = WiFi.status() == WL_CONNECTED;
+
+ if (isConnected)
+ {
+ _d("WiFi :: connected, IP address: ");
+ _dln(WiFi.localIP());
+
+ stationModeStart = 0;
+ }
+ else if (stationMode && accessPoint &&
+ currentTime - stationModeStart >= StationModeTimeout)
+ {
+ _dln("WiFi :: unable to connect, switching off station mode, status:");
+ _dln(WiFi.status());
+
+ #ifdef SerialDebug
+ WiFi.printDiag(Serial);
+ #endif
+
+ // Connecting to access point is taking too long and is blocking
+ // the access point mode, stop trying
+ stationMode = false;
+ WiFi.disconnect();
+ WiFi.mode(WIFI_AP);
+ }
+ }
+
+ updateLED();
+}
+
+
+void initWiFi()
+{
+ WiFi.disconnect();
+ WiFi.softAPdisconnect();
+
+ accessPoint = connectionSettings->flag(AccessPoint) || forceAccessPoint;
+ stationMode = connectionSettings->flag(StationMode) && connectionSettings->ssid() != NULL;
+
+ WiFi.mode(accessPoint && stationMode ? WIFI_AP_STA :
+ accessPoint ? WIFI_AP :
+ stationMode ? WIFI_STA :
+ WIFI_OFF);
+
+ if (accessPoint)
+ {
+ _dln("WiFi :: starting access point");
+ String ssidString = DefaultAPSSIDPrefix + String(ESP.getChipId(), HEX);
+ if (WiFi.softAP((const char *)ssidString.c_str()))
+ {
+ _d("WiFi :: IP address: ");
+ _dln(WiFi.softAPIP());
+ }
+ else
+ _d("WiFi :: failed to start soft access point");
+ }
+
+ if (stationMode)
+ {
+ _d("WiFi :: starting station mode to: ");
+ _dln(connectionSettings->ssid());
+
+ stationModeStart = currentTime;
+
+ if (WiFi.begin(connectionSettings->ssid(), connectionSettings->password()))
+ {
+ if (connectionSettings->flag(DHCP))
+ // I've had the same issue as described here with config(0, 0, 0):
+ // https://stackoverflow.com/questions/40069654/how-to-clear-static-ip-configuration-and-start-dhcp
+ wifi_station_dhcpc_start();
+ else
+ WiFi.config(connectionSettings->ip(), connectionSettings->gateway(), connectionSettings->subnetMask());
+ }
+ else
+ _d("WiFi :: failed to start station mode");
+ }
+}
+
+
+#ifdef SerialDebug
+void wifiEvent(WiFiEvent_t event)
+{
+ switch (event)
+ {
+ case WIFI_EVENT_STAMODE_CONNECTED:
+ _dln("WiFi:: station mode: connected"); break;
+
+ case WIFI_EVENT_STAMODE_DISCONNECTED:
+ _dln("WiFi:: station mode: disconnected"); break;
+
+ case WIFI_EVENT_STAMODE_AUTHMODE_CHANGE:
+ _dln("WiFi:: station mode: authmode change"); break;
+
+ case WIFI_EVENT_STAMODE_GOT_IP:
+ _dln("WiFi:: station mode: got IP");
+ _dln(WiFi.localIP());
+ break;
+
+ case WIFI_EVENT_STAMODE_DHCP_TIMEOUT:
+ _dln("WiFi:: station mode: DHCP timeout"); break;
+
+ case WIFI_EVENT_SOFTAPMODE_STACONNECTED:
+ _dln("WiFi:: soft AP mode: station connected"); break;
+
+ case WIFI_EVENT_SOFTAPMODE_STADISCONNECTED:
+ _dln("WiFi:: soft AP mode: station disconnected"); break;
+ }
+}
+#endif
+
+
+void updateLED()
+{
+ //while (WiFi.status() != WL_CONNECTED)
+ //{
+
+ //}
+}
+
+
+void handleNotFound(AsyncWebServerRequest *request)
+{
+ _d("HTTP :: not found: "); _dln(request->url());
+ request->send(404);
+}
+
+
+
+/*
uint8_t currentModeIdentifier;
IMode* currentMode;
@@ -362,4 +559,5 @@ void setCurrentMode(IMode* mode, uint8_t identifier)
void handleCurrentMode()
{
currentMode->tick(stairs, currentTime);
-}
\ No newline at end of file
+}
+*/
\ No newline at end of file
diff --git a/src/modes/alternate.cpp b/src/modes/alternate.cpp
deleted file mode 100644
index 29e119a..0000000
--- a/src/modes/alternate.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "alternate.h"
-#include
-
-
-void AlternateMode::init(IStairs* stairs, uint32_t currentTime)
-{
- stairs->setAll(0);
-
- this->lastChange = currentTime;
- this->even = false;
-}
-
-
-void AlternateMode::tick(IStairs* stairs, uint32_t currentTime)
-{
- if (currentTime - this->lastChange < this->parameters.interval)
- return;
-
- this->lastChange = currentTime;
- this->even = !this->even;
-
- uint8_t stepCount = stairs->getCount();
- for (uint8_t step = 0; step < stepCount; step++)
- {
- stairs->set(step, ((step % 2) == 0) == this->even ? this->parameters.brightness : 0);
- }
-}
\ No newline at end of file
diff --git a/src/modes/alternate.h b/src/modes/alternate.h
deleted file mode 100644
index 70c2c1f..0000000
--- a/src/modes/alternate.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __AlternateMode
-#define __AlternateMode
-
-#include
-#include "base.h"
-#include "../config.h"
-
-
-struct AlternateModeParameters
-{
- uint16_t interval;
- uint16_t brightness;
-};
-
-
-class AlternateMode : public BaseMode
-{
- private:
- uint32_t lastChange;
- bool even = false;
-
- public:
- AlternateMode()
- {
- parameters.interval = 500;
- parameters.brightness = IStairs::On;
- }
-
- void init(IStairs* stairs, uint32_t currentTime);
- void tick(IStairs* stairs, uint32_t currentTime);
-};
-
-#endif
\ No newline at end of file
diff --git a/src/modes/base.h b/src/modes/base.h
deleted file mode 100644
index 255756e..0000000
--- a/src/modes/base.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __BaseMode
-#define __BaseMode
-
-#include
-#include
-#include "../config.h"
-#include "../mode.h"
-
-
-template
-class BaseMode : public IMode
-{
- protected:
- T parameters;
-
- public:
- virtual void read(uint8_t* data)
- {
- _d("Reading parameters, size ");
- _dln(sizeof(T));
- memcpy(&this->parameters, data, sizeof(T));
- }
-
- virtual void write(Stream* stream)
- {
- _d("Writing parameters, size ");
- _dln(sizeof(T));
- stream->write((uint8_t*)&this->parameters, sizeof(T));
- }
-};
-
-#endif
\ No newline at end of file
diff --git a/src/modes/custom.cpp b/src/modes/custom.cpp
deleted file mode 100644
index 49119e2..0000000
--- a/src/modes/custom.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "custom.h"
-#include
-
-
-void CustomMode::read(uint8_t* data)
-{
- // The packet is zeroed before we get our hands on it and
- // the size should also be larger as noted in main.cpp,
- // so a straight-up copy should be safe.
- memcpy(this->values, data, sizeof(this->values));
-}
-
-
-void CustomMode::write(Stream* stream)
-{
- stream->write((uint8_t*)&this->values, sizeof(this->values));
-}
-
-
-void CustomMode::init(IStairs* stairs, uint32_t currentTime)
-{
- for (uint8_t step = 0; step < StepCount; step++)
- stairs->set(step, this->values[step]);
-}
-
-
-void CustomMode::tick(IStairs* stairs, uint32_t currentTime)
-{
-}
diff --git a/src/modes/custom.h b/src/modes/custom.h
deleted file mode 100644
index dd3a23e..0000000
--- a/src/modes/custom.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __CustomMode
-#define __CustomMode
-
-#include
-#include "base.h"
-#include "../config.h"
-
-class CustomMode : public IMode
-{
- private:
- uint16_t values[StepCount];
-
- public:
- void read(uint8_t* data);
- void write(Stream* stream);
-
- void init(IStairs* stairs, uint32_t currentTime);
- void tick(IStairs* stairs, uint32_t currentTime);
-};
-
-#endif
\ No newline at end of file
diff --git a/src/modes/slide.h b/src/modes/slide.h
deleted file mode 100644
index 26885ad..0000000
--- a/src/modes/slide.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __SlideMode
-#define __SlideMode
-
-#include
-#include "base.h"
-#include "../config.h"
-
-class SlideMode : public IMode
-{
- private:
- uint16_t interval;
- bool up;
-};
-
-#endif
\ No newline at end of file
diff --git a/src/modes/static.cpp b/src/modes/static.cpp
deleted file mode 100644
index 7398bf2..0000000
--- a/src/modes/static.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "static.h"
-
-void StaticMode::init(IStairs* stairs, uint32_t currentTime)
-{
- _dln("Initializing static mode:");
- _d("currentBrightness: "); _dln(this->currentBrightness);
- _d("brightness: "); _dln(this->parameters.brightness);
- _d("easeTime: "); _dln(this->parameters.easeTime);
-
- if (this->parameters.easeTime > 0 && this->parameters.brightness != this->currentBrightness)
- {
- _dln("Easing...");
-
- this->easeStartTime = currentTime;
- this->easeStartBrightness = currentBrightness;
-
- if (this->parameters.brightness > this->currentBrightness)
- this->easeState = Up;
- else
- this->easeState = Down;
- }
- else
- {
- _dln("Updating immediately...");
- this->easeState = None;
-
- stairs->setAll(this->parameters.brightness);
- this->currentBrightness = this->parameters.brightness;
- }
-}
-
-
-void StaticMode::tick(IStairs* stairs, uint32_t currentTime)
-{
- if (this->easeState == None)
- return;
-
- uint32_t elapsedTime = currentTime - this->easeStartTime;
- uint32_t diff = this->easeState == Up ? this->parameters.brightness - this->easeStartBrightness : this->easeStartBrightness - this->parameters.brightness;
- uint32_t delta = (diff * elapsedTime) / this->parameters.easeTime;
-
- this->currentBrightness = this->easeState == Up ? this->easeStartBrightness + delta : this->easeStartBrightness - delta;
-
-
- if (elapsedTime >= this->parameters.easeTime)
- {
- this->currentBrightness = this->parameters.brightness;
- this->easeState = None;
- }
-
- stairs->setAll(this->currentBrightness);
-}
\ No newline at end of file
diff --git a/src/modes/static.h b/src/modes/static.h
deleted file mode 100644
index 5ee9472..0000000
--- a/src/modes/static.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef __StaticMode
-#define __StaticMode
-
-#include
-#include "base.h"
-#include "../config.h"
-
-
-struct StaticModeParameters
-{
- uint16_t brightness;
- uint16_t easeTime;
-};
-
-enum EaseState
-{
- None,
- Up,
- Down
-};
-
-
-class StaticMode : public BaseMode
-{
- private:
- uint16_t currentBrightness;
- uint32_t easeStartTime;
- uint16_t easeStartBrightness;
- EaseState easeState;
-
- public:
- StaticMode()
- {
- parameters.brightness = 0;
- parameters.easeTime = 0;
-
- easeState = None;
- currentBrightness = 0;
- }
-
- void init(IStairs* stairs, uint32_t currentTime);
- void tick(IStairs* stairs, uint32_t currentTime);
-};
-
-#endif
\ No newline at end of file
diff --git a/src/server/api.cpp b/src/server/api.cpp
new file mode 100644
index 0000000..a8e743b
--- /dev/null
+++ b/src/server/api.cpp
@@ -0,0 +1,101 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#include "api.h"
+#include
+#include
+#include
+#include "../assets/version.h"
+#include "../debug.h"
+#include "../global.h"
+#include "../settings/connection.h"
+
+
+void handleVersion(AsyncWebServerRequest *request)
+{
+ _dln("API :: version");
+
+ DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(2));
+
+ JsonObject& root = jsonBuffer.createObject();
+ root["systemID"] = String(ESP.getChipId(), HEX);
+ root["version"] = String(VersionFullSemVer) + " sha." + String(VersionSha);
+
+ AsyncResponseStream *response = request->beginResponseStream("application/json");
+ root.printTo(*response);
+
+ request->send(response);
+}
+
+
+void handleConnectionStatus(AsyncWebServerRequest *request)
+{
+ _dln("API :: connection status");
+
+ WiFiMode_t mode = WiFi.getMode();
+
+
+ DynamicJsonBuffer jsonBuffer((2 * JSON_OBJECT_SIZE(2)) + JSON_OBJECT_SIZE(3));
+
+ JsonObject& root = jsonBuffer.createObject();
+ JsonObject& ap = root.createNestedObject("ap");
+ ap["enabled"] = (mode == WIFI_AP || mode == WIFI_AP_STA);
+ ap["ip"] = WiFi.softAPIP().toString();
+
+ JsonObject& station = root.createNestedObject("station");
+ station["enabled"] = (mode == WIFI_STA || mode == WIFI_AP_STA);
+ station["status"] = (uint8_t)WiFi.status();
+ station["ip"] = WiFi.localIP().toString();
+
+ AsyncResponseStream *response = request->beginResponseStream("application/json");
+ root.printTo(*response);
+
+ request->send(response);
+}
+
+
+void handleGetConnection(AsyncWebServerRequest *request)
+{
+ _dln("API :: get connection");
+
+ AsyncResponseStream *response = request->beginResponseStream("application/json");
+ connectionSettings->toJson(*response);
+ request->send(response);
+}
+
+
+void handlePostConnection(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
+{
+ _dln("API :: post connection");
+
+ bool changed;
+ if (connectionSettings->fromJson((char*)data, &changed))
+ {
+ connectionSettings->write();
+
+ if (changed)
+ connectionSettingsChanged = true;
+
+ request->send(200);
+ }
+ else
+ request->send(400);
+}
+
+
+void devNullRequest(AsyncWebServerRequest *request) { }
+void devNullFileUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { }
+
+
+void registerAPIRoutes(AsyncWebServer* server)
+{
+ server->on("/api/version", HTTP_GET, handleVersion);
+
+ server->on("/api/connection/status", HTTP_GET, handleConnectionStatus);
+
+ server->on("/api/connection", HTTP_GET, handleGetConnection);
+ server->on("/api/connection", HTTP_POST, devNullRequest, devNullFileUpload, handlePostConnection);
+}
\ No newline at end of file
diff --git a/src/server/api.h b/src/server/api.h
new file mode 100644
index 0000000..4de41f8
--- /dev/null
+++ b/src/server/api.h
@@ -0,0 +1,13 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#ifndef __server_api
+#define __server_api
+#include
+
+void registerAPIRoutes(AsyncWebServer* server);
+
+#endif
\ No newline at end of file
diff --git a/src/server/static.cpp b/src/server/static.cpp
new file mode 100644
index 0000000..8864355
--- /dev/null
+++ b/src/server/static.cpp
@@ -0,0 +1,35 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#include "static.h"
+#include "../debug.h"
+#include "../assets/html.h"
+#include "../assets/js.h"
+#include "../assets/css.h"
+#include "../assets/images.h"
+
+
+void handleStatic(AsyncWebServerRequest *request, const String& contentType, PGM_P content)
+{
+ _d("HTTP :: static: "); _dln(request->url());
+ request->send_P(200, contentType, content);
+}
+
+
+void registerStaticRoutes(AsyncWebServer* server)
+{
+ server->on("/", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/html", EmbeddedIndex); });
+
+ server->on("/bundle.js", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/javascript", EmbeddedBundleJS); });
+ server->on("/bundle.css", HTTP_GET, [](AsyncWebServerRequest *request) { handleStatic(request, "text/css", EmbeddedBundleCSS); });
+
+ server->on("/logo.png", HTTP_GET, [](AsyncWebServerRequest *request)
+ {
+ _d("HTTP :: static: "); _dln(request->url());
+ AsyncWebServerResponse *response = request->beginResponse_P(200, "image/png", EmbeddedLogo, sizeof(EmbeddedLogo));
+ request->send(response);
+ });
+}
\ No newline at end of file
diff --git a/src/server/static.h b/src/server/static.h
new file mode 100644
index 0000000..285ea37
--- /dev/null
+++ b/src/server/static.h
@@ -0,0 +1,14 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#ifndef __server_static
+#define __server_static
+
+#include
+
+void registerStaticRoutes(AsyncWebServer* server);
+
+#endif
\ No newline at end of file
diff --git a/src/settings/connection.cpp b/src/settings/connection.cpp
new file mode 100644
index 0000000..32bdaf1
--- /dev/null
+++ b/src/settings/connection.cpp
@@ -0,0 +1,149 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#include "connection.h"
+#include
+#include
+#include "../debug.h"
+#include "../global.h"
+#include "../config.h"
+
+
+
+void ConnectionSettings::read()
+{
+ _dln("ConnectionSettings :: opening file");
+ File settingsFile = SPIFFS.open(ConnectionSettingsFile, "r");
+ if (!settingsFile)
+ {
+ _dln("ConnectionSettings :: failed to open file");
+ return;
+ }
+
+ size_t size = settingsFile.size();
+ if (size > 1024)
+ {
+ _dln("ConnectionSettings :: file size is too large");
+ return;
+ }
+
+ if (size == 0)
+ {
+ _dln("ConnectionSettings :: zero size file");
+ return;
+ }
+
+ std::unique_ptr buf(new char[size]);
+ settingsFile.readBytes(buf.get(), size);
+
+ _dln(buf.get());
+
+ if (fromJson(buf.get()))
+ _dln("ConnectionSettings :: read from file");
+ else
+ _dln("ConnectionSettings :: failed to parse file");
+}
+
+
+void ConnectionSettings::write()
+{
+ _dln("ConnectionSettings :: opening file for writing");
+ File settingsFile = SPIFFS.open(ConnectionSettingsFile, "w");
+ if (!settingsFile)
+ {
+ _dln("ConnectionSettings:: failed to open file for writing");
+ return;
+ }
+
+ toJson(settingsFile);
+ _dln("ConnectionSettings:: written to file");
+}
+
+
+void ConnectionSettings::toJson(Print &print)
+{
+ DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(9));
+
+ JsonObject& root = jsonBuffer.createObject();
+ root["hostname"] = hostname();
+ root["accesspoint"] = flag(AccessPoint);
+ root["station"] = flag(StationMode);
+ root["ssid"] = ssid();
+ root["password"] = password();
+ root["dhcp"] = flag(DHCP);
+ root["ip"] = ip() != 0 ? ip().toString() : "";
+ root["subnetmask"] = subnetMask() != 0 ? subnetMask().toString() : "";
+ root["gateway"] = gateway() != 0 ? gateway().toString() : "";
+
+ root.printTo(print);
+}
+
+
+bool ConnectionSettings::fromJson(char* data)
+{
+ return fromJson(data, NULL);
+}
+
+
+bool ConnectionSettings::fromJson(char* data, bool* changed)
+{
+ if (changed != NULL)
+ *changed = false;
+
+ DynamicJsonBuffer jsonBuffer(JSON_OBJECT_SIZE(9) + 250);
+ JsonObject& root = jsonBuffer.parseObject(data);
+
+ if (!root.success())
+ return false;
+
+ IPAddress jsonIP;
+ IPAddress jsonSubnetMask;
+ IPAddress jsonGateway;
+
+ const char* jsonHostname = root["hostname"];
+ bool jsonAccessPoint = root["accesspoint"];
+ bool jsonStation = root["station"];
+ const char* jsonSSID = root["ssid"];
+ const char* jsonPassword = root["password"];
+ bool jsonDHCP = root["dhcp"];
+ const char* jsonIPText = root["ip"];
+ const char* jsonSubnetMaskText = root["subnetmask"];
+ const char* jsonGatewayText = root["gateway"];
+
+ if (jsonIPText == NULL || !jsonIP.fromString(jsonIPText)) jsonIP = emptyIP;
+ if (jsonSubnetMaskText == NULL || !jsonSubnetMask.fromString(jsonSubnetMaskText)) jsonSubnetMask = emptyIP;
+ if (jsonGatewayText == NULL || !jsonGateway.fromString(jsonGatewayText)) jsonGateway = emptyIP;
+
+
+ if (!(jsonAccessPoint || jsonStation))
+ jsonAccessPoint = true;
+
+ if ((jsonHostname != hostname()) ||
+ (jsonAccessPoint != flag(AccessPoint)) ||
+ (jsonStation != flag(StationMode)) ||
+ (jsonSSID != ssid()) ||
+ (jsonPassword != password()) ||
+ (jsonDHCP != flag(DHCP)) ||
+ (jsonIP != ip()) ||
+ (jsonSubnetMask != subnetMask()) ||
+ (jsonGateway != gateway()))
+ {
+ hostname(jsonHostname);
+ flag(AccessPoint, jsonAccessPoint);
+ flag(StationMode, jsonStation);
+ ssid(jsonSSID);
+ password(jsonPassword);
+ flag(DHCP, jsonDHCP);
+ ip(jsonIP);
+ subnetMask(jsonSubnetMask);
+ gateway(jsonGateway);
+
+ if (changed != NULL)
+ *changed = true;
+ }
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/settings/connection.h b/src/settings/connection.h
new file mode 100644
index 0000000..a7dd4d8
--- /dev/null
+++ b/src/settings/connection.h
@@ -0,0 +1,73 @@
+/*
+ * Stairs
+ * Copyright 2017 (c) Mark van Renswoude
+ *
+ * https://git.x2software.net/pub/Stairs
+*/
+#ifndef __settingsconnection
+#define __settingsconnection
+
+#include
+#include
+#include
+#include "../charproperties.h"
+
+
+enum ConnectionSettingsFlags
+{
+ AccessPoint = 1,
+ StationMode = 2,
+ DHCP = 4
+};
+
+
+class ConnectionSettings : CharProperties
+{
+ private:
+ char* mHostname = NULL;
+ uint8_t mFlags = AccessPoint | DHCP;
+ char* mSSID = NULL;
+ char* mPassword = NULL;
+ IPAddress mIP = (uint32_t)0;
+ IPAddress mSubnetMask = (uint32_t)0;
+ IPAddress mGateway = (uint32_t)0;
+
+ public:
+ void read();
+ void write();
+
+
+ void toJson(Print &print);
+ bool fromJson(char* data);
+ bool fromJson(char* data, bool* changed);
+
+
+ char* hostname() { return mHostname; }
+ void hostname(const char* value) { assignChar(&mHostname, value); }
+
+ bool flag(ConnectionSettingsFlags flag) { return (mFlags & flag) != 0; }
+ void flag(ConnectionSettingsFlags flag, bool enabled)
+ {
+ if (enabled)
+ mFlags |= flag;
+ else
+ mFlags &= ~flag;
+ }
+
+ char* ssid() { return mSSID; }
+ void ssid(const char* value) { assignChar(&mSSID, value); }
+
+ char* password() { return mPassword; }
+ void password(const char* value) { assignChar(&mPassword, value); }
+
+ IPAddress ip() { return mIP; }
+ void ip(IPAddress value) { mIP = value; }
+
+ IPAddress subnetMask() { return mSubnetMask; }
+ void subnetMask(IPAddress value) { mSubnetMask = value; }
+
+ IPAddress gateway() { return mGateway; }
+ void gateway(IPAddress value) { mGateway = value; }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/stairs.cpp b/src/stairs.cpp
index 0653b36..559a7ad 100644
--- a/src/stairs.cpp
+++ b/src/stairs.cpp
@@ -1,6 +1,7 @@
+#include "stairs.h"
#include
#include
-#include "stairs.h"
+#include "debug.h"
@@ -19,11 +20,13 @@ void Stairs::init(PCA9685* pwmDriver)
{
this->useScaling = false;
+/*
for (uint8_t i = 0; i < StepCount; i++)
{
this->ranges[i].start = IStairs::Off;
this->ranges[i].end = IStairs::On;
}
+ */
this->pwmDriver = pwmDriver;
@@ -35,7 +38,7 @@ void Stairs::init(PCA9685* pwmDriver)
uint8_t Stairs::getCount()
{
- return StepCount;
+ return 0;//StepCount;
}
@@ -49,8 +52,10 @@ void Stairs::setAll(uint16_t brightness)
{
//pwmDriver->setAll(this->getPWMValue(brightness));
+/*
for (uint8_t step = 0; step < StepCount; step++)
pwmDriver->setPWM(step, this->getPWMValue(step, brightness));
+ */
}
@@ -63,7 +68,7 @@ uint16_t Stairs::getPWMValue(uint8_t step, uint16_t brightness)
return brightness;
}
- if (step < 0 || step >= StepCount)
+ if (step < 0 || step >= getCount())
{
_dln("Step out of bounds, returning input");
return brightness;
@@ -141,7 +146,7 @@ void Stairs::writeRange()
Header header;
header.version = 1;
header.useScaling = this->useScaling;
- header.rangeCount = StepCount;
+ header.rangeCount = getCount();
f.write((uint8_t*)&header, sizeof(Header));
f.write((uint8_t*)&this->ranges, sizeof(this->ranges));
diff --git a/src/stairs.h b/src/stairs.h
index e98a171..a61c6d0 100644
--- a/src/stairs.h
+++ b/src/stairs.h
@@ -2,8 +2,8 @@
#define __Stairs
#include "components/PCA9685.h"
-#include "modes/base.h"
#include "config.h"
+#include "mode.h"
struct Range
@@ -19,7 +19,7 @@ class Stairs : public IStairs
PCA9685* pwmDriver;
bool useScaling;
- Range ranges[StepCount];
+ Range ranges[16];
protected:
void readRange();
diff --git a/updateversion.ps1 b/updateversion.ps1
deleted file mode 100644
index b183a54..0000000
--- a/updateversion.ps1
+++ /dev/null
@@ -1,23 +0,0 @@
-$output = & GitVersion /output json /nofetch
-if ($LASTEXITCODE -ne 0) {
- Write-Verbose "$output"
- throw "GitVersion failed with exit code: $LASTEXITCODE"
-}
-
-$version = $output | ConvertFrom-Json
-
-@"
-#ifndef __Version
-#define __Version
-
-static const char* FirmwareVersion = "{0}";
-
-#endif
-"@ -f $version.FullSemVer | Out-File -Encoding UTF8 .\src\version.h
-
-@"
-module.exports =
-{{
- Version: "{0}"
-}};
-"@ -f $version.FullSemVer | Out-File -Encoding UTF8 .\web\version.js
diff --git a/upload.ps1 b/upload.ps1
deleted file mode 100644
index 32ed813..0000000
--- a/upload.ps1
+++ /dev/null
@@ -1,2 +0,0 @@
-& .\updateversion.ps1
-& platformio run --target upload
\ No newline at end of file
diff --git a/web/.bowerrc b/web/.bowerrc
deleted file mode 100644
index d058d74..0000000
--- a/web/.bowerrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "directory": "static/bower_components"
-}
\ No newline at end of file
diff --git a/web/app.js b/web/app.js
index 2e52159..0f9421c 100644
--- a/web/app.js
+++ b/web/app.js
@@ -1,160 +1,248 @@
-var fs = require('fs');
-var md5File = require('md5-file');
-var express = require('express');
-var semverUtils = require('semver-utils')
-var client = require('./client');
-
-var httpPort = 3127;
-
-var stairsHost = '10.138.2.25';
-var stairsUdpPort = 3126;
-
-var firmwareFile = './update/firmware.bin';
-var alwaysUpdate = true;
-
-
-function requireNoCache(filename)
+function startApp()
{
- delete require.cache[require.resolve(filename)];
- return require(filename);
-}
-
-
-function isNewer(version1, version2)
-{
- if (alwaysUpdate) return true;
-
- if (version1.major > version2.major) return true;
- if (version1.major < version2.major) return false;
-
- if (version1.minor > version2.minor) return true;
- if (version1.minor < version2.minor) return false;
-
- if (version1.patch > version2.patch) return true;
- if (version1.patch < version2.patch) return false;
-
- if (parseInt(version1.build, 10) > parseInt(version2.build, 10)) return true;
- return false;
-}
-
-
-client.init(stairsHost, stairsUdpPort);
-
-
-var app = express();
-
-app.get('/ping', function(req, res)
-{
- client.ping(function(data, error)
- {
- if (error)
- res.status(500);
-
- res.send(data);
+ var i18n = new VueI18n({
+ locale: navigator.language,
+ fallbackLocale: 'en',
+ messages: messages
});
-});
-app.get('/getMode', function(req, res)
-{
- client.getMode(function(data, error)
- {
- if (error)
- res.status(500);
+ var app = new Vue({
+ el: '#app',
- res.send(data);
- });
-});
+ i18n: i18n,
-app.get('/setMode/:mode', function(req, res)
-{
- client.setMode(req.params.mode, req.query, function(data, error)
- {
- if (error)
- res.status(500);
+ data: {
+ loading: true,
+ saving: false,
+ loadingIndicator: '|',
- res.send(data);
- });
-});
+ activeTab: 'status',
-app.get('/getRange', function(req, res)
-{
- client.getRange(function(data, error)
- {
- if (error)
- res.status(500);
+ version: {
+ systemID: 'loading...',
+ version: 'loading...',
+ },
- res.send(data);
- });
-});
+ wifiStatus: {
+ ap: {
+ enabled: false,
+ ip: '0.0.0.0'
+ },
+ station: {
+ enabled: false,
+ status: 0,
+ ip: '0.0.0.0'
+ }
+ },
-app.get('/setRange', function(req, res)
-{
- client.setRange(req.query, function(data, error)
- {
- if (error)
- res.status(500);
+ connection: {
+ hostname: null,
+ accesspoint: true,
+ station: false,
+ ssid: null,
+ password: null,
+ dhcp: true,
+ ip: null,
+ subnetmask: null,
+ gateway: null
+ },
- res.send(data);
- });
-});
+ steps: [
+ { value: 50 },
+ { value: 0 },
+ { value: 0 },
+ { value: 0 },
+ { value: 0 },
+ { value: 70 },
+ { value: 0 },
+ { value: 0 },
+ { value: 0 },
+ { value: 0 },
+ { value: 25 },
+ { value: 0 },
+ { value: 0 },
+ { value: 0 }
+ ]
+ },
-app.get('/updateFirmware', function(req, res)
-{
- client.updateFirmware(req.query, function(data, error)
- {
- if (error)
- res.status(500);
-
- res.send(data);
- });
-})
-
-app.get('/checkUpdate', function(req, res)
-{
- if (!fs.existsSync(firmwareFile))
- {
- console.log('checkUpdate: ' + firmwareFile + ' not found!');
- res.sendStatus(304);
- return;
- }
-
- var version = requireNoCache('./version.js');
- var deviceVersion = semverUtils.parse(req.headers['x-esp8266-version']);
- var localVersion = semverUtils.parse(version.Version);
-
- console.log('checkUpdate:');
- console.log(' Device version = ' + semverUtils.stringify(deviceVersion));
- console.log(' Local version = ' + semverUtils.stringify(localVersion));
-
- if (isNewer(localVersion, deviceVersion))
- {
- console.log('Sending update');
-
- md5File(firmwareFile, function(err, hash)
+ created: function()
{
- if (err)
+ var self = this;
+
+ document.title = i18n.t('title');
+ self.startLoadingIndicator();
+
+ self.updateWiFiStatus();
+ setInterval(self.updateWiFiStatus, 5000);
+
+ axios.get('/api/version')
+ .then(function(response)
+ {
+ if (typeof response.data == 'object')
+ self.version = response.data;
+ })
+ .catch(function(error)
+ {
+ console.log(error);
+ });
+
+ axios.all([
+ axios.get('/api/connection')
+ .then(function(response)
+ {
+ if (typeof response.data == 'object')
+ self.connection = response.data;
+ })
+ .catch(function(error)
+ {
+ console.log(error);
+ })/*,
+
+ axios.get('/api/actions')
+ .then(function(response)
+ {
+ if (typeof response.data == 'object')
+ self.actions = response.data;
+ })
+ .catch(function(error)
+ {
+ console.log(error);
+ })*/
+ ])
+ .then(axios.spread(function(acct, perms) {
+ self.stopLoadingIndicator();
+ self.loading = false;
+ }));
+ },
+
+ methods: {
+ applyConnection: function()
{
- res.sendStatus(500);
- return;
+ var self = this;
+ if (self.saving) return;
+
+ self.saving = true;
+
+ axios.post('/api/connection', {
+ hostname: self.connection.hostname,
+ accesspoint: self.connection.accesspoint,
+ station: self.connection.station,
+ ssid: self.connection.ssid,
+ password: self.connection.password,
+ dhcp: self.connection.dhcp,
+ ip: self.connection.ip,
+ subnetmask: self.connection.subnetmask,
+ gateway: self.connection.gateway,
+ })
+ .then(function(response)
+ {
+ })
+ .catch(function(error)
+ {
+ console.log(error);
+ })
+ .then(function()
+ {
+ self.saving = false;
+ })
+ },
+
+ startLoadingIndicator: function()
+ {
+ var self = this;
+
+ self.loadingStage = 0;
+ self.loadingTimer = setInterval(function()
+ {
+ self.loadingStage++;
+ console.log(self.loadingStage);
+ switch (self.loadingStage)
+ {
+ case 1: self.loadingIndicator = '/'; break;
+ case 2: self.loadingIndicator = '-'; break;
+ case 3: self.loadingIndicator = '\\'; break;
+ case 4: self.loadingIndicator = '|'; self.loadingStage = 0; break;
+ }
+ }, 250);
+ },
+
+ stopLoadingIndicator: function()
+ {
+ clearInterval(this.loadingTimer);
+ },
+
+ getWiFiStationStatus: function()
+ {
+ if (!this.wifiStatus.station.enabled)
+ return 'disconnected';
+
+ switch (this.wifiStatus.station.status)
+ {
+ case 0: // WL_IDLE_STATUS
+ case 2: // WL_SCAN_COMPLETED
+ return 'connecting';
+
+ case 1: // WL_NO_SSID_AVAIL
+ case 4: // WL_CONNECT_FAILED
+ case 5: // WL_CONNECTION_LOST
+ return 'error';
+
+ case 3: // WL_CONNECTED
+ return 'connected';
+
+ case 6: // WL_DISCONNECTED
+ default:
+ return 'disconnected';
+ }
+ },
+
+ getWiFiStationStatusText: function()
+ {
+ if (!this.wifiStatus.station.enabled)
+ return i18n.t('wifiStatus.stationmode.disabled');
+
+ switch (this.wifiStatus.station.status)
+ {
+ case 0: // WL_IDLE_STATUS
+ return i18n.t('wifiStatus.stationmode.idle');
+
+ case 1: // WL_NO_SSID_AVAIL
+ return i18n.t('wifiStatus.stationmode.noSSID');
+
+ case 2: // WL_SCAN_COMPLETED
+ return i18n.t('wifiStatus.stationmode.scanCompleted');
+
+ case 3: // WL_CONNECTED
+ return this.wifiStatus.station.ip;
+
+ case 4: // WL_CONNECT_FAILED
+ return i18n.t('wifiStatus.stationmode.connectFailed');
+
+ case 5: // WL_CONNECTION_LOST
+ return i18n.t('wifiStatus.stationmode.connectionLost');
+
+ case 6: // WL_DISCONNECTED
+ default:
+ return i18n.t('wifiStatus.stationmode.disconnected');
+ }
+ },
+
+ updateWiFiStatus: function()
+ {
+ var self = this;
+ if (self.saving) return;
+
+ axios.get('/api/connection/status')
+ .then(function(response)
+ {
+ if (typeof response.data == 'object')
+ self.wifiStatus = response.data;
+ })
+ .catch(function(error)
+ {
+ console.log(error);
+ });
}
-
- res.set('Content-Length', fs.statSync(firmwareFile).size);
- res.set('x-MD5', hash);
- res.download(firmwareFile);
- });
- }
- else
- {
- console.log('No update required');
- res.sendStatus(304);
- }
-});
-
-app.use(express.static(__dirname + '/static'));
-
-
-
-app.listen(httpPort, function ()
-{
- console.log('Stairs ReST service running on port ' + httpPort);
-});
\ No newline at end of file
+ }
+ });
+}
\ No newline at end of file
diff --git a/web/bower.json b/web/bower.json
deleted file mode 100644
index f60658d..0000000
--- a/web/bower.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "stairs",
- "description": "Stairs lighting project",
- "main": "index.html",
- "authors": [
- "Mark van Renswoude"
- ],
- "license": "ISC",
- "homepage": "",
- "private": true,
- "ignore": [
- "**/.*",
- "node_modules",
- "src/bower_components"
- ],
- "dependencies": {
- "knockout": "^3.4.2",
- "jquery": "^3.2.1",
- "crossroads": "^0.12.2",
- "hasher": "^1.2.0",
- "requirejs": "^2.3.3",
- "text": "requirejs/text#^2.0.15",
- "bootstrap": "v4.0.0-alpha.6",
- "nprogress": "^0.2.0"
- }
-}
diff --git a/web/client.js b/web/client.js
deleted file mode 100644
index 5762db1..0000000
--- a/web/client.js
+++ /dev/null
@@ -1,342 +0,0 @@
-var dgram = require('dgram');
-var protocol = require('./protocol');
-var BufferReader = require('buffer-reader');
-
-
-var responseHandlers = {};
-
-function registerResponseHandler(command, callback)
-{
- if (!responseHandlers.hasOwnProperty(command))
- responseHandlers[command] = [callback];
- else
- responseHandlers[command].push(callback);
-}
-
-
-function callResponseHandlers(command, reader, error)
-{
- if (!responseHandlers.hasOwnProperty(command))
- return;
-
- newHandlers = [];
- responseHandlers[command].forEach(function(callback)
- {
- if (!callback(reader, error))
- newHandlers.push(callback);
- });
-
- responseHandlers[command] = newHandlers;
-}
-
-
-var serverHost = '';
-var serverPort = 0;
-
-var client = dgram.createSocket('udp4');
-client.on('message', function (message, remote)
-{
- console.log(message.toString('hex'));
- if (message.length < 2)
- return;
-
- var reader = new BufferReader(message);
-
- if (reader.nextInt8() !== protocol.Command.Reply)
- return;
-
- var command = reader.nextInt8();
- if (command === protocol.Command.Error)
- callResponseHandlers(reader.nextInt8(), reader, true)
- else
- callResponseHandlers(command, reader, false);
-});
-
-
-function requestResponse(buffer, callback, withTimeout)
-{
- if (buffer === null || buffer.length == 0) return;
- console.log('> ' + buffer.toString('hex'));
-
- var command = buffer.readInt8(0);
- var cancelled = false;
-
- if (typeof(withTimeout) == 'undefined') withTimeout = true;
- if (withTimeout)
- {
- var timeout = setTimeout(function()
- {
- cancelled = true;
- callback(null, true);
- clearTimeout(timeout);
- }, 2000);
- }
-
- registerResponseHandler(command, function(reader, error)
- {
- if (cancelled) return;
- if (withTimeout) clearTimeout(timeout);
-
- callback(reader, error);
- return true;
- });
-
- client.send(buffer, 0, buffer.length, serverPort, serverHost, function(err, bytes)
- {
- if (err)
- onError();
- });
-}
-
-
-function readModeData(mode, reader)
-{
- switch (mode)
- {
- case protocol.Mode.Static:
- return {
- brightness: reader.nextInt16LE(),
- easeTime: reader.nextInt16LE()
- };
-
- case protocol.Mode.Custom:
- var values = [];
- while (reader.tell() < reader.buf.length)
- values.push(reader.nextInt16LE());
-
- return {
- brightness: values
- };
-
- case protocol.Mode.Alternate:
- return {
- interval: reader.nextInt16LE(),
- brightness: reader.nextInt16LE()
- };
-
- case protocol.Mode.Slide:
- return {
- interval: reader.nextInt16LE(),
- brightness: reader.nextInt16LE(),
- direction: reader.nextInt8(),
- fadeOutTime: reader.nextInt16LE()
- };
- }
-
- return null;
-}
-
-
-function readRangeData(reader)
-{
- var data = { useScaling: reader.nextInt8() == 1, values: [] };
-
- while (reader.tell() < reader.buf.length)
- data.values.push({ start: reader.nextInt16LE(), end: reader.nextInt16LE() });
-
- return data;
-}
-
-
-function lsb(value) { return value & 0xFF; }
-function msb(value) { return (value >> 8) & 0xFF; }
-
-
-function getBrightness(value)
-{
- if (typeof(value) == 'string' && value.substr(-1) === '%')
- return (Number(value.substr(0, value.length - 1)) * 4096 / 100);
-
- return Number(value) || 0;
-}
-
-
-function writeModeData(mode, data)
-{
- switch (mode)
- {
- case protocol.Mode.Static:
- var brightness = getBrightness(data.brightness);
-
- return new Buffer([protocol.Command.SetMode, mode, lsb(brightness), msb(brightness), lsb(500), msb(500)]);
-
- case protocol.Mode.Custom:
- var brightness = typeof(data.brightness) !== 'undefined' ? data.brightness.split(',') : [];
-
- var valueCount = Math.min(16, brightness.length);
- var buffer = Buffer.alloc(2 + (valueCount * 2));
- buffer.writeUInt8(protocol.Command.SetMode, 0);
- buffer.writeUInt8(mode, 1);
-
- for (var index = 0; index < valueCount; index++)
- buffer.writeUInt16LE(getBrightness(brightness[index]), 2 + (index * 2));
-
- return buffer;
-
- case protocol.Mode.Alternate:
- var brightness = getBrightness(data.brightness);
- if (typeof(data.interval) == 'undefined') data.interval = 500;
-
- return new Buffer([protocol.Command.SetMode, mode,
- lsb(data.interval), msb(data.interval),
- lsb(brightness), msb(brightness)]);
-
- case protocol.Mode.Slide:
- var brightness = getBrightness(data.brightness);
- if (typeof(data.interval) == 'undefined') data.interval = 500;
- if (typeof(data.direction) == 'undefined') data.direction = 0;
- if (typeof(data.fadeOutTime) == 'undefined') data.fadeOutTime = 0;
-
- return new Buffer([protocol.Command.SetMode, mode,
- lsb(data.interval), msb(data.interval),
- lsb(brightness), msb(brightness),
- data.direction,
- lsb(data.fadeOutTime), msb(data.fadeOutTime)]);
- }
-}
-
-
-function writeRangeData(data)
-{
- var start = typeof(data.start) !== 'undefined' ? data.start.split(',') : [];
- var end = typeof(data.end) !== 'undefined' ? data.end.split(',') : [];
-
- var valueCount = Math.min(16, start.length, end.length);
- var buffer = Buffer.alloc(2 + (valueCount * 4));
- buffer.writeUInt8(protocol.Command.SetRange, 0);
- buffer.writeUInt8(data.useScaling ? 1 : 0, 1);
-
- for (var index = 0; index < valueCount; index++)
- {
- buffer.writeUInt16LE(getBrightness(start[index]), 2 + (index * 4));
- buffer.writeUInt16LE(getBrightness(end[index]), 4 + (index * 4));
- }
-
- return buffer;
-}
-
-
-module.exports =
-{
- init: function(host, port)
- {
- serverHost = host;
- serverPort = port;
- },
-
-
- ping: function(callback)
- {
- requestResponse(new Buffer([protocol.Command.Ping]),
- function(reader, error)
- {
- if (!error)
- {
- callback(
- {
- stepCount: reader.nextInt8()
- }, false);
- }
- else
- callback(null, true);
- });
- },
-
- getMode: function(callback)
- {
- requestResponse(new Buffer([protocol.Command.GetMode]),
- function(reader, error)
- {
- if (!error)
- {
- var data = { mode: reader.nextInt8() };
- data.data = readModeData(data.mode, reader);
- callback(data, false);
- }
- else
- callback(null, true);
- });
- },
-
- setMode: function(mode, data, callback)
- {
- if (!protocol.Mode.hasOwnProperty(mode))
- return;
-
- requestResponse(writeModeData(protocol.Mode[mode], data),
- function(reader, error)
- {
- if (!error)
- {
- var data = { mode: reader.nextInt8() };
- data.data = readModeData(data.mode, reader);
- callback(data, false);
- }
- else
- callback(null, true);
- });
- },
-
- getRange: function(callback)
- {
- requestResponse(new Buffer([protocol.Command.GetRange]),
- function(reader, error)
- {
- if (!error)
- {
- callback(readRangeData(reader), false);
- }
- else
- callback(null, true);
- });
- },
-
- setRange: function(data, callback)
- {
- requestResponse(writeRangeData(data),
- function(reader, error)
- {
- if (!error)
- {
- callback(readRangeData(reader), false);
- }
- else
- callback(null, true);
- });
- },
-
- updateFirmware: function(data, callback)
- {
- if (typeof(data.host) == 'undefined') data.host = '';
- if (typeof(data.port) == 'undefined') data.port = 80;
- if (typeof(data.path) == 'undefined') data.path = '';
-
- var buffer = Buffer.alloc(1 + (data.host.length + 1) + 2 + (data.path.length + 1));
- buffer.writeUInt8(protocol.Command.UpdateFirmware, 0);
- var position = 1;
-
- buffer.writeUInt16LE(data.port, position);
- position += 2;
-
- buffer.write(data.host, position);
- position += data.host.length;
- buffer.writeUInt8(0, position);
- position++;
-
- buffer.write(data.path, position);
- position += data.path.length;
- buffer.writeUInt8(0, position);
-
- requestResponse(buffer,
- function(reader, error)
- {
- if (!error)
- {
- var data = { hasUpdates: reader.nextInt8() == 1 };
- callback(data, false);
- }
- else
- callback(null, true);
- }, false);
- }
-}
\ No newline at end of file
diff --git a/web/dist/bundle.css b/web/dist/bundle.css
new file mode 100644
index 0000000..60286a2
--- /dev/null
+++ b/web/dist/bundle.css
@@ -0,0 +1 @@
+*,:after,:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;font-family:Roboto,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:.3rem solid #404040;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote :last-child{margin-bottom:0}.button,button,input[type=button],input[type=reset],input[type=submit]{background-color:#06f;border:.1rem solid #06f;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type=button]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]:focus,input[type=submit]:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type=button][disabled],input[type=reset][disabled],input[type=submit][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type=button][disabled]:focus,input[type=button][disabled]:hover,input[type=reset][disabled]:focus,input[type=reset][disabled]:hover,input[type=submit][disabled]:focus,input[type=submit][disabled]:hover{background-color:#06f;border-color:#06f}.button.button-outline,button.button-outline,input[type=button].button-outline,input[type=reset].button-outline,input[type=submit].button-outline{background-color:transparent;color:#06f}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type=button].button-outline:focus,input[type=button].button-outline:hover,input[type=reset].button-outline:focus,input[type=reset].button-outline:hover,input[type=submit].button-outline:focus,input[type=submit].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type=button].button-outline[disabled]:focus,input[type=button].button-outline[disabled]:hover,input[type=reset].button-outline[disabled]:focus,input[type=reset].button-outline[disabled]:hover,input[type=submit].button-outline[disabled]:focus,input[type=submit].button-outline[disabled]:hover{border-color:inherit;color:#06f}.button.button-clear,button.button-clear,input[type=button].button-clear,input[type=reset].button-clear,input[type=submit].button-clear{background-color:transparent;border-color:transparent;color:#06f}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type=button].button-clear:focus,input[type=button].button-clear:hover,input[type=reset].button-clear:focus,input[type=reset].button-clear:hover,input[type=submit].button-clear:focus,input[type=submit].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type=button].button-clear[disabled]:focus,input[type=button].button-clear[disabled]:hover,input[type=reset].button-clear[disabled]:focus,input[type=reset].button-clear[disabled]:hover,input[type=submit].button-clear[disabled]:focus,input[type=submit].button-clear[disabled]:hover{color:#06f}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:.3rem solid #06f;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:.1rem solid #f4f5f6;margin:3rem 0}input[type=email],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=url],select,textarea{appearance:none;background-color:transparent;border:.1rem solid #404040;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1rem;width:100%}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,select:focus,textarea:focus{border-color:#06f;outline:0}select{background:url('data:image/svg+xml;utf8, ') center right no-repeat;padding-right:3rem}select:focus{background-image:url('data:image/svg+xml;utf8, ')}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type=checkbox],input[type=radio]{display:inline}.label-inline{display:inline-block;font-weight:400;margin-left:.5rem}.container{margin:0 auto;max-width:112rem;padding:0 2rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width:40rem){.row{flex-direction:row;margin-left:-1rem;width:calc(100% + 2rem)}.row .column{margin-bottom:inherit;padding:0 1rem}}a{color:#06f;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;width:100%}td,th{border-bottom:.1rem solid #e1e1e1;padding:1.2rem 1.5rem;text-align:left}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}b,strong{font-weight:700}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right}[v-cloak]{display:none}body{background-color:#000;color:#fff;font-family:Verdana,Arial,sans-serif;font-size:10pt;padding-bottom:3rem}@media screen and (min-width:768px){body{padding-top:3rem}}input,textarea{color:#fff}#container{background-color:#202020;margin-top:2rem;padding:1rem;box-shadow:0 0 50px #fcf6cf;border:solid 1px #000}@media screen and (min-width:768px){#container{width:768px;margin-left:auto;margin-right:auto}}.header{position:relative}.header img{float:left;margin-right:1rem}.header .wifistatus{position:absolute;right:0;top:0}.header .wifistatus .indicator{display:inline-block;width:1rem;height:1rem;border-radius:50%;margin-right:.5rem}.header .wifistatus .indicator[data-status=connected]{background-color:#396}.header .wifistatus .indicator[data-status=disconnected]{border:solid 1px grey}.header .wifistatus .indicator[data-status=connecting]{background-color:#f93}.header .wifistatus .indicator[data-status=error]{background-color:#c00}h1{font-size:16pt;margin:0}h2{color:silver;font-size:10pt;margin:0}h3{color:grey;background-color:#282828;font-size:14pt;border-bottom:solid 1px grey}.version{color:grey;font-size:8pt;text-align:center;margin-top:2rem}.tabs{clear:both;margin-top:3rem}.tabs .button{background-color:#404040;color:#fff!important;border-color:grey}.tabs .button.button-outline{background-color:transparent}input[disabled]{cursor:not-allowed;color:grey;background-color:#262626}.label-inline{margin-right:2rem}.hint{display:block;font-size:8pt;color:grey;margin-bottom:1.5rem}.loading{margin-top:3rem;text-align:center}.suboptions{margin-left:5rem}.buttons{text-align:center}.slider{-webkit-appearance:none;width:100%;height:.5rem;border-radius:.25rem;background:#404040;outline:0}.slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:2rem;height:2rem;border-radius:50%;background:#fcf6cf;cursor:pointer}.slider::-moz-range-thumb{width:2rem;height:2rem;border-radius:50%;background:#fcf6cf;cursor:pointer}
\ No newline at end of file
diff --git a/web/dist/bundle.js b/web/dist/bundle.js
new file mode 100644
index 0000000..6ded72a
--- /dev/null
+++ b/web/dist/bundle.js
@@ -0,0 +1 @@
+!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.axios=e():t.axios=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return t[r].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){t.exports=n(1)},function(t,e,n){"use strict";function r(t){var e=new a(t),n=o(a.prototype.request,e);return i.extend(n,a.prototype,e),i.extend(n,e),n}var i=n(2),o=n(3),a=n(5),s=n(6),c=r(s);c.Axios=a,c.create=function(t){return r(i.merge(s,t))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(20),c.all=function(t){return Promise.all(t)},c.spread=n(25),t.exports=c,t.exports.default=c},function(t,e,n){"use strict";function r(t){return"[object Array]"===u.call(t)}function i(t){return null!==t&&"object"==typeof t}function o(t){return"[object Function]"===u.call(t)}function a(t,e){if(null!==t&&void 0!==t)if("object"!=typeof t&&(t=[t]),r(t))for(var n=0,i=t.length;n=200&&t<300}};s.headers={common:{Accept:"application/json, text/plain, */*"}},i.forEach(["delete","get","head"],function(t){s.headers[t]={}}),i.forEach(["post","put","patch"],function(t){s.headers[t]=i.merge(a)}),t.exports=s},function(t,e,n){"use strict";var r=n(2);t.exports=function(t,e){r.forEach(t,function(n,r){r!==e&&r.toUpperCase()===e.toUpperCase()&&(t[e]=n,delete t[r])})}},function(t,e,n){"use strict";var r=n(2),i=n(9),o=n(12),a=n(13),s=n(14),c=n(10),u="undefined"!=typeof window&&window.btoa&&window.btoa.bind(window)||n(15);t.exports=function(t){return new Promise(function(e,l){var f=t.data,p=t.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest,h="onreadystatechange",v=!1;if("undefined"==typeof window||!window.XDomainRequest||"withCredentials"in d||s(t.url)||(d=new window.XDomainRequest,h="onload",v=!0,d.onprogress=function(){},d.ontimeout=function(){}),t.auth){var m=t.auth.username||"",g=t.auth.password||"";p.Authorization="Basic "+u(m+":"+g)}if(d.open(t.method.toUpperCase(),o(t.url,t.params,t.paramsSerializer),!0),d.timeout=t.timeout,d[h]=function(){if(d&&(4===d.readyState||v)&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?a(d.getAllResponseHeaders()):null,r={data:t.responseType&&"text"!==t.responseType?d.response:d.responseText,status:1223===d.status?204:d.status,statusText:1223===d.status?"No Content":d.statusText,headers:n,config:t,request:d};i(e,l,r),d=null}},d.onerror=function(){l(c("Network Error",t,null,d)),d=null},d.ontimeout=function(){l(c("timeout of "+t.timeout+"ms exceeded",t,"ECONNABORTED",d)),d=null},r.isStandardBrowserEnv()){var y=n(16),_=(t.withCredentials||s(t.url))&&t.xsrfCookieName?y.read(t.xsrfCookieName):void 0;_&&(p[t.xsrfHeaderName]=_)}if("setRequestHeader"in d&&r.forEach(p,function(t,e){void 0===f&&"content-type"===e.toLowerCase()?delete p[e]:d.setRequestHeader(e,t)}),t.withCredentials&&(d.withCredentials=!0),t.responseType)try{d.responseType=t.responseType}catch(e){if("json"!==t.responseType)throw e}"function"==typeof t.onDownloadProgress&&d.addEventListener("progress",t.onDownloadProgress),"function"==typeof t.onUploadProgress&&d.upload&&d.upload.addEventListener("progress",t.onUploadProgress),t.cancelToken&&t.cancelToken.promise.then(function(t){d&&(d.abort(),l(t),d=null)}),void 0===f&&(f=null),d.send(f)})}},function(t,e,n){"use strict";var r=n(10);t.exports=function(t,e,n){var i=n.config.validateStatus;n.status&&i&&!i(n.status)?e(r("Request failed with status code "+n.status,n.config,null,n.request,n)):t(n)}},function(t,e,n){"use strict";var r=n(11);t.exports=function(t,e,n,i,o){var a=new Error(t);return r(a,e,n,i,o)}},function(t,e){"use strict";t.exports=function(t,e,n,r,i){return t.config=e,n&&(t.code=n),t.request=r,t.response=i,t}},function(t,e,n){"use strict";function r(t){return encodeURIComponent(t).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var i=n(2);t.exports=function(t,e,n){if(!e)return t;var o;if(n)o=n(e);else if(i.isURLSearchParams(e))o=e.toString();else{var a=[];i.forEach(e,function(t,e){null!==t&&void 0!==t&&(i.isArray(t)&&(e+="[]"),i.isArray(t)||(t=[t]),i.forEach(t,function(t){i.isDate(t)?t=t.toISOString():i.isObject(t)&&(t=JSON.stringify(t)),a.push(r(e)+"="+r(t))}))}),o=a.join("&")}return o&&(t+=(-1===t.indexOf("?")?"?":"&")+o),t}},function(t,e,n){"use strict";var r=n(2),i=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];t.exports=function(t){var e,n,o,a={};return t?(r.forEach(t.split("\n"),function(t){if(o=t.indexOf(":"),e=r.trim(t.substr(0,o)).toLowerCase(),n=r.trim(t.substr(o+1)),e){if(a[e]&&i.indexOf(e)>=0)return;a[e]="set-cookie"===e?(a[e]?a[e]:[]).concat([n]):a[e]?a[e]+", "+n:n}}),a):a}},function(t,e,n){"use strict";var r=n(2);t.exports=r.isStandardBrowserEnv()?function(){function t(t){var e=t;return n&&(i.setAttribute("href",e),e=i.href),i.setAttribute("href",e),{href:i.href,protocol:i.protocol?i.protocol.replace(/:$/,""):"",host:i.host,search:i.search?i.search.replace(/^\?/,""):"",hash:i.hash?i.hash.replace(/^#/,""):"",hostname:i.hostname,port:i.port,pathname:"/"===i.pathname.charAt(0)?i.pathname:"/"+i.pathname}}var e,n=/(msie|trident)/i.test(navigator.userAgent),i=document.createElement("a");return e=t(window.location.href),function(n){var i=r.isString(n)?t(n):n;return i.protocol===e.protocol&&i.host===e.host}}():function(){return!0}},function(t,e){"use strict";function n(){this.message="String contains an invalid character"}var r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";n.prototype=new Error,n.prototype.code=5,n.prototype.name="InvalidCharacterError",t.exports=function(t){for(var e,i,o=String(t),a="",s=0,c=r;o.charAt(0|s)||(c="=",s%1);a+=c.charAt(63&e>>8-s%1*8)){if((i=o.charCodeAt(s+=.75))>255)throw new n;e=e<<8|i}return a}},function(t,e,n){"use strict";var r=n(2);t.exports=r.isStandardBrowserEnv()?{write:function(t,e,n,i,o,a){var s=[];s.push(t+"="+encodeURIComponent(e)),r.isNumber(n)&&s.push("expires="+new Date(n).toGMTString()),r.isString(i)&&s.push("path="+i),r.isString(o)&&s.push("domain="+o),!0===a&&s.push("secure"),document.cookie=s.join("; ")},read:function(t){var e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},function(t,e,n){"use strict";function r(){this.handlers=[]}var i=n(2);r.prototype.use=function(t,e){return this.handlers.push({fulfilled:t,rejected:e}),this.handlers.length-1},r.prototype.eject=function(t){this.handlers[t]&&(this.handlers[t]=null)},r.prototype.forEach=function(t){i.forEach(this.handlers,function(e){null!==e&&t(e)})},t.exports=r},function(t,e,n){"use strict";function r(t){t.cancelToken&&t.cancelToken.throwIfRequested()}var i=n(2),o=n(19),a=n(20),s=n(6),c=n(21),u=n(22);t.exports=function(t){r(t),t.baseURL&&!c(t.url)&&(t.url=u(t.baseURL,t.url)),t.headers=t.headers||{},t.data=o(t.data,t.headers,t.transformRequest),t.headers=i.merge(t.headers.common||{},t.headers[t.method]||{},t.headers||{}),i.forEach(["delete","get","head","post","put","patch","common"],function(e){delete t.headers[e]});return(t.adapter||s.adapter)(t).then(function(e){return r(t),e.data=o(e.data,e.headers,t.transformResponse),e},function(e){return a(e)||(r(t),e&&e.response&&(e.response.data=o(e.response.data,e.response.headers,t.transformResponse))),Promise.reject(e)})}},function(t,e,n){"use strict";var r=n(2);t.exports=function(t,e,n){return r.forEach(n,function(n){t=n(t,e)}),t}},function(t,e){"use strict";t.exports=function(t){return!(!t||!t.__CANCEL__)}},function(t,e){"use strict";t.exports=function(t){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(t)}},function(t,e){"use strict";t.exports=function(t,e){return e?t.replace(/\/+$/,"")+"/"+e.replace(/^\/+/,""):t}},function(t,e){"use strict";function n(t){this.message=t}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,t.exports=n},function(t,e,n){"use strict";function r(t){if("function"!=typeof t)throw new TypeError("executor must be a function.");var e;this.promise=new Promise(function(t){e=t});var n=this;t(function(t){n.reason||(n.reason=new i(t),e(n.reason))})}var i=n(23);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var t;return{token:new r(function(e){t=e}),cancel:t}},t.exports=r},function(t,e){"use strict";t.exports=function(t){return function(e){return t.apply(null,e)}}}])}),function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Vue=e()}(this,function(){"use strict";function t(t){return void 0===t||null===t}function e(t){return void 0!==t&&null!==t}function n(t){return!0===t}function r(t){return"string"==typeof t||"number"==typeof t||"symbol"==typeof t||"boolean"==typeof t}function i(t){return null!==t&&"object"==typeof t}function o(t){return"[object Object]"===mn.call(t)}function a(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function s(t){return null==t?"":"object"==typeof t?JSON.stringify(t,null,2):String(t)}function c(t){var e=parseFloat(t);return isNaN(e)?t:e}function u(t,e){for(var n=Object.create(null),r=t.split(","),i=0;i-1)return t.splice(n,1)}}function f(t,e){return _n.call(t,e)}function p(t){var e=Object.create(null);return function(n){return e[n]||(e[n]=t(n))}}function d(t,e){function n(n){var r=arguments.length;return r?r>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n}function h(t,e){e=e||0;for(var n=t.length-e,r=new Array(n);n--;)r[n]=t[n+e];return r}function v(t,e){for(var n in e)t[n]=e[n];return t}function m(t){for(var e={},n=0;n0&&(G((c=i(c,(a||"")+"_"+s))[0])&&G(l)&&(f[u]=k(l.text+c[0].text),c.shift()),f.push.apply(f,c)):r(c)?G(l)?f[u]=k(l.text+c):""!==c&&f.push(k(c)):G(c)&&G(l)?f[u]=k(l.text+c.text):(n(o._isVList)&&e(c.tag)&&t(c.key)&&e(a)&&(c.key="__vlist"+a+"_"+s+"__"),f.push(c)));return f}(u):void 0:c===Dr&&(s=function(t){for(var e=0;e=0||n.indexOf(t[i])<0)&&r.push(t[i]);return r}return t}(n[o],r[o],i[o]));return e}(t);r&&v(t.extendOptions,r),(e=t.options=F(n,t.extendOptions)).name&&(e.components[e.name]=t)}}return e}function Et(t){this._init(t)}function Lt(t){return t&&(t.Ctor.options.name||t.tag)}function It(t,e){return Array.isArray(t)?t.indexOf(e)>-1:"string"==typeof t?t.split(",").indexOf(e)>-1:(n=t,!("[object RegExp]"!==mn.call(n))&&t.test(e));var n}function Dt(t,e){var n=t.cache,r=t.keys,i=t._vnode;for(var o in n){var a=n[o];if(a){var s=Lt(a.componentOptions);s&&!e(s)&&Ft(n,o,r,i)}}}function Ft(t,e,n,r){var i=t[e];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),t[e]=null,l(n,e)}function Nt(t,n){return{staticClass:Pt(t.staticClass,n.staticClass),class:e(t.class)?[t.class,n.class]:n.class}}function Pt(t,e){return t?e?t+" "+e:t:e||""}function Mt(t){return Array.isArray(t)?function(t){for(var n,r="",i=0,o=t.length;i=0&&" "===(m=t.charAt(v));v--);m&&_i.test(m)||(l=!0)}}else void 0===o?(h=i+1,o=t.slice(0,i).trim()):e();if(void 0===o?o=t.slice(0,i).trim():0!==h&&e(),a)for(i=0;i-1?{exp:t.slice(0,zr),key:'"'+t.slice(zr+1)+'"'}:{exp:t,key:null};for(Hr=t,zr=Wr=qr=0;!ce();)ue(Vr=se())?le(Vr):91===Vr&&function(t){var e=1;for(Wr=zr;!ce();)if(t=se(),ue(t))le(t);else if(91===t&&e++,93===t&&e--,0===e){qr=zr;break}}(Vr);return{exp:t.slice(0,Wr),key:t.slice(Wr+1,qr)}}(t);return null===n.key?t+"="+e:"$set("+n.exp+", "+n.key+", "+e+")"}function se(){return Hr.charCodeAt(++zr)}function ce(){return zr>=Ur}function ue(t){return 34===t||39===t}function le(t){for(var e=t;!ce()&&(t=se())!==e;);}function fe(t,e,n,r,i){e=(o=e)._withTask||(o._withTask=function(){hr=!0;var t=o.apply(null,arguments);return hr=!1,t}),n&&(e=function(t,e,n){var r=Jr;return function i(){null!==t.apply(null,arguments)&&pe(e,i,n,r)}}(e,t,r)),Jr.addEventListener(t,e,Vn?{capture:r,passive:i}:r);var o}function pe(t,e,n,r){(r||Jr).removeEventListener(t,e._withTask||e,n)}function de(n,r){if(!t(n.data.on)||!t(r.data.on)){var i=r.data.on||{},o=n.data.on||{};Jr=r.elm,function(t){if(e(t[bi])){var n=Pn?"change":"input";t[n]=[].concat(t[bi],t[n]||[]),delete t[bi]}e(t[wi])&&(t.change=[].concat(t[wi],t.change||[]),delete t[wi])}(i),J(i,o,fe,pe,r.context),Jr=void 0}}function he(n,r){if(!t(n.data.domProps)||!t(r.data.domProps)){var i,o,a=r.elm,s=n.data.domProps||{},u=r.data.domProps||{};e(u.__ob__)&&(u=r.data.domProps=v({},u));for(i in s)t(u[i])&&(a[i]="");for(i in u){if(o=u[i],"textContent"===i||"innerHTML"===i){if(r.children&&(r.children.length=0),o===s[i])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===i){a._value=o;var l=t(o)?"":String(o);p=l,!(f=a).composing&&("OPTION"===f.tagName||function(t,e){var n=!0;try{n=document.activeElement!==t}catch(t){}return n&&t.value!==e}(f,p)||function(t,n){var r=t.value,i=t._vModifiers;if(e(i)){if(i.lazy)return!1;if(i.number)return c(r)!==c(n);if(i.trim)return r.trim()!==n.trim()}return r!==n}(f,p))&&(a.value=l)}else a[i]=o}}var f,p}function ve(t){var e=me(t.style);return t.staticStyle?v(t.staticStyle,e):e}function me(t){return Array.isArray(t)?m(t):"string"==typeof t?ki(t):t}function ge(n,r){var i=r.data,o=n.data;if(!(t(i.staticStyle)&&t(i.style)&&t(o.staticStyle)&&t(o.style))){var a,s,c=r.elm,u=o.staticStyle,l=o.normalizedStyle||o.style||{},f=u||l,p=me(r.data.style)||{};r.data.normalizedStyle=e(p.__ob__)?v({},p):p;var d=function(t,e){for(var n,r={},i=t;i.componentInstance;)(i=i.componentInstance._vnode)&&i.data&&(n=ve(i.data))&&v(r,n);(n=ve(t.data))&&v(r,n);for(var o=t;o=o.parent;)o.data&&(n=ve(o.data))&&v(r,n);return r}(r);for(s in f)t(d[s])&&Si(c,s,"");for(s in d)(a=d[s])!==f[s]&&Si(c,s,null==a?"":a)}}function ye(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(/\s+/).forEach(function(e){return t.classList.add(e)}):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function _e(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(/\s+/).forEach(function(e){return t.classList.remove(e)}):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{for(var n=" "+(t.getAttribute("class")||"")+" ",r=" "+e+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?t.setAttribute("class",n):t.removeAttribute("class")}}function be(t){if(t){if("object"==typeof t){var e={};return!1!==t.css&&v(e,Ei(t.name||"v")),v(e,t),e}return"string"==typeof t?Ei(t):void 0}}function we(t){Ri(function(){Ri(t)})}function $e(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),ye(t,e))}function xe(t,e){t._transitionClasses&&l(t._transitionClasses,e),_e(t,e)}function ke(t,e,n){var r=Ce(t,e),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===Ii?Ni:Mi,c=0,u=function(){t.removeEventListener(s,l),n()},l=function(e){e.target===t&&++c>=a&&u()};setTimeout(function(){c0&&(n=Ii,l=a,f=o.length):e===Di?u>0&&(n=Di,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?Ii:Di:null)?n===Ii?o.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===Ii&&Bi.test(r[Fi+"Property"])}}function Ae(t,e){for(;t.length1}function Le(t,e){!0!==e.data.show&&Oe(e)}function Ie(t,e,n){De(t,e,n),(Pn||Rn)&&setTimeout(function(){De(t,e,n)},0)}function De(t,e,n){var r=e.value,i=t.multiple;if(!i||Array.isArray(r)){for(var o,a,s=0,c=t.options.length;s-1,a.selected!==o&&(a.selected=o);else if(y(Ne(a),r))return void(t.selectedIndex!==s&&(t.selectedIndex=s));i||(t.selectedIndex=-1)}}function Fe(t,e){return e.every(function(e){return!y(e,t)})}function Ne(t){return"_value"in t?t._value:t.value}function Pe(t){t.target.composing=!0}function Me(t){t.target.composing&&(t.target.composing=!1,Re(t.target,"input"))}function Re(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function Be(t){return!t.componentInstance||t.data&&t.data.transition?t:Be(t.componentInstance._vnode)}function Ue(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?Ue(Q(e.children)):t}function He(t){var e={},n=t.$options;for(var r in n.propsData)e[r]=t[r];var i=n._parentListeners;for(var o in i)e[wn(o)]=i[o];return e}function Ve(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}function ze(t){t.elm._moveCb&&t.elm._moveCb(),t.elm._enterCb&&t.elm._enterCb()}function We(t){t.data.newPos=t.elm.getBoundingClientRect()}function qe(t){var e=t.data.pos,n=t.data.newPos,r=e.left-n.left,i=e.top-n.top;if(r||i){t.data.moved=!0;var o=t.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}function Je(t,e){var n=e?jo:To;return t.replace(n,function(t){return Oo[t]})}function Ke(t,e,n){return{type:1,tag:t,attrsList:e,attrsMap:function(t){for(var e={},n=0,r=t.length;n ':'
',ko.innerHTML.indexOf("
")>0}var vn=Object.freeze({}),mn=Object.prototype.toString,gn=u("slot,component",!0),yn=u("key,ref,slot,slot-scope,is"),_n=Object.prototype.hasOwnProperty,bn=/-(\w)/g,wn=p(function(t){return t.replace(bn,function(t,e){return e?e.toUpperCase():""})}),$n=p(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}),xn=/\B([A-Z])/g,kn=p(function(t){return t.replace(xn,"-$1").toLowerCase()}),Cn=function(t,e,n){return!1},An=function(t){return t},Sn="data-server-rendered",On=["component","directive","filter"],Tn=["beforeCreate","created","beforeMount","mounted","beforeUpdate","updated","beforeDestroy","destroyed","activated","deactivated","errorCaptured"],jn={optionMergeStrategies:Object.create(null),silent:!1,productionTip:!1,devtools:!1,performance:!1,errorHandler:null,warnHandler:null,ignoredElements:[],keyCodes:Object.create(null),isReservedTag:Cn,isReservedAttr:Cn,isUnknownElement:Cn,getTagNamespace:g,parsePlatformTagName:An,mustUseProp:Cn,_lifecycleHooks:Tn},En=/[^\w.$]/,Ln="__proto__"in{},In="undefined"!=typeof window,Dn="undefined"!=typeof WXEnvironment&&!!WXEnvironment.platform,Fn=Dn&&WXEnvironment.platform.toLowerCase(),Nn=In&&window.navigator.userAgent.toLowerCase(),Pn=Nn&&/msie|trident/.test(Nn),Mn=Nn&&Nn.indexOf("msie 9.0")>0,Rn=Nn&&Nn.indexOf("edge/")>0,Bn=Nn&&Nn.indexOf("android")>0||"android"===Fn,Un=Nn&&/iphone|ipad|ipod|ios/.test(Nn)||"ios"===Fn,Hn=(Nn&&/chrome\/\d+/.test(Nn),{}.watch),Vn=!1;if(In)try{var zn={};Object.defineProperty(zn,"passive",{get:function(){Vn=!0}}),window.addEventListener("test-passive",null,zn)}catch(t){}var Wn,qn,Jn=function(){return void 0===Wn&&(Wn=!In&&"undefined"!=typeof global&&"server"===global.process.env.VUE_ENV),Wn},Kn=In&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,Xn="undefined"!=typeof Symbol&&x(Symbol)&&"undefined"!=typeof Reflect&&x(Reflect.ownKeys);qn="undefined"!=typeof Set&&x(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var Gn=g,Zn=0,Yn=function(){this.id=Zn++,this.subs=[]};Yn.prototype.addSub=function(t){this.subs.push(t)},Yn.prototype.removeSub=function(t){l(this.subs,t)},Yn.prototype.depend=function(){Yn.target&&Yn.target.addDep(this)},Yn.prototype.notify=function(){for(var t=this.subs.slice(),e=0,n=t.length;eSr&&$r[n].id>t.id;)n--;$r.splice(n+1,0,t)}else $r.push(t);Cr||(Cr=!0,z(ut))}}(this)},Tr.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||i(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(t){B(t,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},Tr.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},Tr.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},Tr.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||l(this.vm._watchers,this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1}};var jr={enumerable:!0,configurable:!0,get:g,set:g},Er={lazy:!0};Ct(At.prototype);var Lr={init:function(t,n,r,i){if(!t.componentInstance||t.componentInstance._isDestroyed)(t.componentInstance=function(t,n,o,a){var s={_isComponent:!0,parent:wr,_parentVnode:t,_parentElm:r||null,_refElm:i||null},c=t.data.inlineTemplate;return e(c)&&(s.render=c.render,s.staticRenderFns=c.staticRenderFns),new t.componentOptions.Ctor(s)}(t)).$mount(n?t.elm:void 0,n);else if(t.data.keepAlive){var o=t;Lr.prepatch(o,o)}},prepatch:function(t,e){var n=e.componentOptions;!function(t,e,n,r,i){var o=!!(i||t.$options._renderChildren||r.data.scopedSlots||t.$scopedSlots!==vn);if(t.$options._parentVnode=r,t.$vnode=r,t._vnode&&(t._vnode.parent=r),t.$options._renderChildren=i,t.$attrs=r.data&&r.data.attrs||vn,t.$listeners=n||vn,e&&t.$options.props){ar.shouldConvert=!1;for(var a=t._props,s=t.$options._propKeys||[],c=0;c1?h(n):n;for(var r=h(arguments,1),i=0,o=n.length;iparseInt(this.max)&&Ft(a,s[0],s,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}}};!function(t){var e={};e.get=function(){return jn},Object.defineProperty(t,"config",e),t.util={warn:Gn,extend:v,mergeOptions:F,defineReactive:O},t.set=T,t.delete=j,t.nextTick=z,t.options=Object.create(null),On.forEach(function(e){t.options[e+"s"]=Object.create(null)}),t.options._base=t,v(t.options.components,Br),t.use=function(t){var e=this._installedPlugins||(this._installedPlugins=[]);if(e.indexOf(t)>-1)return this;var n=h(arguments,1);return n.unshift(this),"function"==typeof t.install?t.install.apply(t,n):"function"==typeof t&&t.apply(null,n),e.push(t),this},t.mixin=function(t){return this.options=F(this.options,t),this},function(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,r=n.cid,i=t._Ctor||(t._Ctor={});if(i[r])return i[r];var o=t.name||n.options.name,a=function(t){this._init(t)};return(a.prototype=Object.create(n.prototype)).constructor=a,a.cid=e++,a.options=F(n.options,t),a.super=n,a.options.props&&function(t){var e=t.options.props;for(var n in e)lt(t.prototype,"_props",n)}(a),a.options.computed&&function(t){var e=t.options.computed;for(var n in e)ft(t.prototype,n,e[n])}(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,On.forEach(function(t){a[t]=n[t]}),o&&(a.options.components[o]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=v({},a.options),i[r]=a,a}}(t),n=t,On.forEach(function(t){n[t]=function(e,n){return n?("component"===t&&o(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}});var n}(Et),Object.defineProperty(Et.prototype,"$isServer",{get:Jn}),Object.defineProperty(Et.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Et.version="2.5.13";var Ur,Hr,Vr,zr,Wr,qr,Jr,Kr,Xr=u("style,class"),Gr=u("input,textarea,option,select,progress"),Zr=function(t,e,n){return"value"===n&&Gr(t)&&"button"!==e||"selected"===n&&"option"===t||"checked"===n&&"input"===t||"muted"===n&&"video"===t},Yr=u("contenteditable,draggable,spellcheck"),Qr=u("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),ti="http://www.w3.org/1999/xlink",ei=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},ni=function(t){return ei(t)?t.slice(6,t.length):""},ri=function(t){return null==t||!1===t},ii={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"},oi=u("html,body,base,head,link,meta,style,title,address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,menuitem,summary,content,element,shadow,template,blockquote,iframe,tfoot"),ai=u("svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view",!0),si=function(t){return oi(t)||ai(t)},ci=Object.create(null),ui=u("text,number,password,search,email,tel,url"),li=Object.freeze({createElement:function(t,e){var n=document.createElement(t);return"select"!==t?n:(e.data&&e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute("multiple","multiple"),n)},createElementNS:function(t,e){return document.createElementNS(ii[t],e)},createTextNode:function(t){return document.createTextNode(t)},createComment:function(t){return document.createComment(t)},insertBefore:function(t,e,n){t.insertBefore(e,n)},removeChild:function(t,e){t.removeChild(e)},appendChild:function(t,e){t.appendChild(e)},parentNode:function(t){return t.parentNode},nextSibling:function(t){return t.nextSibling},tagName:function(t){return t.tagName},setTextContent:function(t,e){t.textContent=e},setAttribute:function(t,e,n){t.setAttribute(e,n)}}),fi={create:function(t,e){Ut(e)},update:function(t,e){t.data.ref!==e.data.ref&&(Ut(t,!0),Ut(e))},destroy:function(t){Ut(t,!0)}},pi=new tr("",{},[]),di=["create","activate","update","remove","destroy"],hi={create:zt,update:zt,destroy:function(t){zt(t,pi)}},vi=Object.create(null),mi=[fi,hi],gi={create:Jt,update:Jt},yi={create:Xt,update:Xt},_i=/[\w).+\-_$\]]/,bi="__r",wi="__c",$i={create:de,update:de},xi={create:he,update:he},ki=p(function(t){var e={},n=/:(.+)/;return t.split(/;(?![^(]*\))/g).forEach(function(t){if(t){var r=t.split(n);r.length>1&&(e[r[0].trim()]=r[1].trim())}}),e}),Ci=/^--/,Ai=/\s*!important$/,Si=function(t,e,n){if(Ci.test(e))t.style.setProperty(e,n);else if(Ai.test(n))t.style.setProperty(e,n.replace(Ai,""),"important");else{var r=Ti(e);if(Array.isArray(n))for(var i=0,o=n.length;id?h(n,t(i[_+1])?null:i[_+1].elm,i,p,_,o):p>_&&m(0,r,f,d)}(c,p,d,o,s):e(d)?(e(r.text)&&C.setTextContent(c,""),h(c,null,d,0,d.length-1,o)):e(p)?m(0,p,0,p.length-1):e(r.text)&&C.setTextContent(c,""):r.text!==i.text&&C.setTextContent(c,i.text),e(l)&&e(u=l.hook)&&e(u=u.postpatch)&&u(r,i)}}}function _(t,r,i){if(n(i)&&e(t.parent))t.parent.data.pendingInsert=r;else for(var o=0;o-1?ci[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:ci[t]=/HTMLUnknownElement/.test(e.toString())},v(Et.options.directives,Vi),v(Et.options.components,Ji),Et.prototype.__patch__=In?Ui:g,Et.prototype.$mount=function(t,e){return function(t,e,n){t.$el=e,t.$options.render||(t.$options.render=nr),ct(t,"beforeMount");return new Tr(t,function(){t._update(t._render(),n)},g,null,!0),n=!1,null==t.$vnode&&(t._isMounted=!0,ct(t,"mounted")),t}(this,t=t&&In?Bt(t):void 0,e)},Et.nextTick(function(){jn.devtools&&Kn&&Kn.emit("init",Et)},0);var Ki,Xi=/\{\{((?:.|\n)+?)\}\}/g,Gi=/[-.*+?^${}()|[\]\/\\]/g,Zi=p(function(t){var e=t[0].replace(Gi,"\\$&"),n=t[1].replace(Gi,"\\$&");return new RegExp(e+"((?:.|\\n)+?)"+n,"g")}),Yi={staticKeys:["staticClass"],transformNode:function(t,e){e.warn;var n=ie(t,"class");n&&(t.staticClass=JSON.stringify(n));var r=re(t,"class",!1);r&&(t.classBinding=r)},genData:function(t){var e="";return t.staticClass&&(e+="staticClass:"+t.staticClass+","),t.classBinding&&(e+="class:"+t.classBinding+","),e}},Qi={staticKeys:["staticStyle"],transformNode:function(t,e){e.warn;var n=ie(t,"style");n&&(t.staticStyle=JSON.stringify(ki(n)));var r=re(t,"style",!1);r&&(t.styleBinding=r)},genData:function(t){var e="";return t.staticStyle&&(e+="staticStyle:"+t.staticStyle+","),t.styleBinding&&(e+="style:("+t.styleBinding+"),"),e}},to=u("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),eo=u("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),no=u("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),ro=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,io="[a-zA-Z_][\\w\\-\\.]*",oo="((?:"+io+"\\:)?"+io+")",ao=new RegExp("^<"+oo),so=/^\s*(\/?)>/,co=new RegExp("^<\\/"+oo+"[^>]*>"),uo=/^]+>/i,lo=/^/g,"$1").replace(//g,"$1")),Lo(p,n)&&(n=n.slice(1)),e.chars&&e.chars(n),""});l+=t.length-h.length,t=h,r(p,l-f,l)}else{var v=t.indexOf("<");if(0===v){if(lo.test(t)){var m=t.indexOf("--\x3e");if(m>=0){e.shouldKeepComment&&e.comment(t.substring(4,m)),n(m+3);continue}}if(fo.test(t)){var g=t.indexOf("]>");if(g>=0){n(g+2);continue}}var y=t.match(uo);if(y){n(y[0].length);continue}var _=t.match(co);if(_){var b=l;n(_[0].length),r(_[1],b,l);continue}var w=function(){var e=t.match(ao);if(e){var r={tagName:e[1],attrs:[],start:l};n(e[0].length);for(var i,o;!(i=t.match(so))&&(o=t.match(ro));)n(o[0].length),r.attrs.push(o);if(i)return r.unarySlash=i[1],n(i[0].length),r.end=l,r}}();if(w){!function(t){var n=t.tagName,i=t.unarySlash;s&&("p"===o&&no(n)&&r(o),u(n)&&o===n&&r(n));for(var l=c(n)||!!i,f=t.attrs.length,p=new Array(f),d=0;d=0){for(x=t.slice(v);!(co.test(x)||ao.test(x)||lo.test(x)||fo.test(x)||(k=x.indexOf("<",1))<0);)v+=k,x=t.slice(v);$=t.substring(0,v),n(v)}v<0&&($=t,t=""),e.chars&&$&&e.chars($)}if(t===i){e.chars&&e.chars(t);break}}r()}(t,{warn:ho,expectHTML:e.expectHTML,isUnaryTag:e.isUnaryTag,canBeLeftOpenTag:e.canBeLeftOpenTag,shouldDecodeNewlines:e.shouldDecodeNewlines,shouldDecodeNewlinesForHref:e.shouldDecodeNewlinesForHref,shouldKeepComment:e.comments,start:function(t,a,u){var l=i&&i.ns||wo(t);Pn&&"svg"===l&&(a=function(t){for(var e=[],n=0;nc&&(s.push(o=t.slice(c,i)),a.push(JSON.stringify(o)));var u=Gt(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c1?1:0:1:t?Math.min(t,2):0;var n}(e,n.length)]?n[e].trim():t}function a(t){return JSON.parse(JSON.stringify(t))}function s(t){for(var n=arguments,r=Object(t),i=1;i=97&&e<=122||e>=65&&e<=90?"ident":e>=49&&e<=57?"number":"else"}function d(t){var e=t.trim();return("0"!==t.charAt(0)||!isNaN(t))&&(n=e,N.test(n)?function(t){var e=t.charCodeAt(0);return e!==t.charCodeAt(t.length-1)||34!==e&&39!==e?t:t.slice(1,-1)}(e):"*"+e);var n}var h,v=Object.prototype.toString,m="[object Object]",g=Object.prototype.hasOwnProperty,y="undefined"!=typeof Intl&&void 0!==Intl.DateTimeFormat,_="undefined"!=typeof Intl&&void 0!==Intl.NumberFormat,b={beforeCreate:function(){var t=this.$options;if(t.i18n=t.i18n||(t.__i18n?{}:null),t.i18n){if(t.i18n instanceof M){if(t.__i18n)try{var e={};t.__i18n.forEach(function(t){e=s(e,JSON.parse(t))}),Object.keys(e).forEach(function(n){t.i18n.mergeLocaleMessage(n,e[n])})}catch(t){}this._i18n=t.i18n,this._i18nWatcher=this._i18n.watchI18nData(),this._i18n.subscribeDataChanging(this),this._subscribing=!0}else if(n(t.i18n)){if(this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof M&&(t.i18n.root=this.$root.$i18n,t.i18n.fallbackLocale=this.$root.$i18n.fallbackLocale,t.i18n.silentTranslationWarn=this.$root.$i18n.silentTranslationWarn),t.__i18n)try{var r={};t.__i18n.forEach(function(t){r=s(r,JSON.parse(t))}),t.i18n.messages=r}catch(t){}this._i18n=new M(t.i18n),this._i18nWatcher=this._i18n.watchI18nData(),this._i18n.subscribeDataChanging(this),this._subscribing=!0,(void 0===t.i18n.sync||t.i18n.sync)&&(this._localeWatcher=this.$i18n.watchLocale())}}else this.$root&&this.$root.$i18n&&this.$root.$i18n instanceof M?(this._i18n=this.$root.$i18n,this._i18n.subscribeDataChanging(this),this._subscribing=!0):t.parent&&t.parent.$i18n&&t.parent.$i18n instanceof M&&(this._i18n=t.parent.$i18n,this._i18n.subscribeDataChanging(this),this._subscribing=!0)},beforeDestroy:function(){this._i18n&&(this._subscribing&&(this._i18n.unsubscribeDataChanging(this),delete this._subscribing),this._i18nWatcher&&(this._i18nWatcher(),delete this._i18nWatcher),this._localeWatcher&&(this._localeWatcher(),delete this._localeWatcher),this._i18n=null)}},w={name:"i18n",functional:!0,props:{tag:{type:String,default:"span"},path:{type:String,required:!0},locale:{type:String},places:{type:[Array,Object]}},render:function(e,n){var r=n.props,i=n.data,o=n.children,a=n.parent.$i18n;if(o=(o||[]).filter(function(t){return t.tag||(t.text=t.text.trim())}),!a)return o;var s=r.path,c=r.locale,u={},l=r.places||{},f=Array.isArray(l)?l.length>0:Object.keys(l).length>0,p=o.every(function(t){if(t.data&&t.data.attrs){var e=t.data.attrs.place;return void 0!==e&&""!==e}});return f&&o.length>0&&!p&&t("If places prop is set, all child elements must have place prop set."),Array.isArray(l)?l.forEach(function(t,e){u[e]=t}):Object.keys(l).forEach(function(t){u[t]=l[t]}),o.forEach(function(t,e){var n=p?""+t.data.attrs.place:""+e;u[n]=t}),e(r.tag,i,a.i(s,c,u))}},$=function(){this._caches=Object.create(null)};$.prototype.interpolate=function(t,n){var r=this._caches[t];return r||(r=function(t){for(var e=[],n=0,r="";n0)f--,l=j,h[C]();else{if(f=0,!1===(n=d(n)))return!1;h[A]()}};null!==l;)if(u++,"\\"!==(e=t[u])||!function(){var e=t[u+1];if(l===E&&"'"===e||l===L&&'"'===e)return u++,r="\\"+e,h[C](),!0}()){if(i=p(e),(o=(s=F[l])[i]||s.else||D)===D)return;if(l=o[0],(a=h[o[1]])&&(r=o[2],r=void 0===r?e:r,!1===a()))return;if(l===I)return c}}(t))&&(this._cache[t]=e),e||[]},P.prototype.getPathValue=function(t,n){if(!e(t))return null;var r=this.parsePath(n);if(i=r,Array.isArray(i)&&0===i.length)return null;for(var i,o=r.length,a=t,s=0;s-1)t.splice(n,1)}}(this._dataListeners,t)},M.prototype.watchI18nData=function(){var t=this;return this._vm.$watch("$data",function(){for(var e=t._dataListeners.length;e--;)h.nextTick(function(){t._dataListeners[e]&&t._dataListeners[e].$forceUpdate()})},{deep:!0})},M.prototype.watchLocale=function(){if(!this._sync||!this._root)return null;var t=this._vm;return this._root.vm.$watch("locale",function(e){t.$set(t,"locale",e),t.$forceUpdate()},{immediate:!0})},R.vm.get=function(){return this._vm},R.messages.get=function(){return a(this._getMessages())},R.dateTimeFormats.get=function(){return a(this._getDateTimeFormats())},R.numberFormats.get=function(){return a(this._getNumberFormats())},R.locale.get=function(){return this._vm.locale},R.locale.set=function(t){this._vm.$set(this._vm,"locale",t)},R.fallbackLocale.get=function(){return this._vm.fallbackLocale},R.fallbackLocale.set=function(t){this._vm.$set(this._vm,"fallbackLocale",t)},R.missing.get=function(){return this._missing},R.missing.set=function(t){this._missing=t},R.formatter.get=function(){return this._formatter},R.formatter.set=function(t){this._formatter=t},R.silentTranslationWarn.get=function(){return this._silentTranslationWarn},R.silentTranslationWarn.set=function(t){this._silentTranslationWarn=t},M.prototype._getMessages=function(){return this._vm.messages},M.prototype._getDateTimeFormats=function(){return this._vm.dateTimeFormats},M.prototype._getNumberFormats=function(){return this._vm.numberFormats},M.prototype._warnDefault=function(t,e,n,i){return r(n)?(this.missing&&this.missing.apply(null,[t,e,i]),e):n},M.prototype._isFallbackRoot=function(t){return!t&&!r(this._root)&&this._fallbackRoot},M.prototype._interpolate=function(t,e,i,o,a,s){if(!e)return null;var c=this._path.getPathValue(e,i);if(Array.isArray(c))return c;var u;if(r(c)){if(!n(e))return null;if("string"!=typeof(u=e[i]))return null}else{if("string"!=typeof c)return null;u=c}return u.indexOf("@:")>=0&&(u=this._link(t,e,u,o,a,s)),s?this._render(u,a,s):u},M.prototype._link=function(t,e,n,r,i,o){var a=n,s=a.match(/(@:[\w\-_|.]+)/g);for(var c in s)if(s.hasOwnProperty(c)){var u=s[c],l=u.substr(2),f=this._interpolate(t,e,l,r,"raw"===i?"string":i,"raw"===i?void 0:o);if(this._isFallbackRoot(f)){if(!this._root)throw Error("unexpected error");var p=this._root;f=p._translate(p._getMessages(),p.locale,p.fallbackLocale,l,r,i,o)}a=(f=this._warnDefault(t,l,f,r))?a.replace(u,f):a}return a},M.prototype._render=function(t,e,n){var r=this._formatter.interpolate(t,n);return"string"===e?r.join(""):r},M.prototype._translate=function(t,e,n,i,o,a,s){var c=this._interpolate(e,t[e],i,o,a,s);return r(c)?r(c=this._interpolate(n,t[n],i,o,a,s))?null:c:c},M.prototype._t=function(t,e,n,r){for(var o=[],a=arguments.length-4;a-- >0;)o[a]=arguments[a+4];if(!t)return"";var s=i.apply(void 0,o),c=s.locale||e,u=this._translate(n,c,this.fallbackLocale,t,r,"string",s.params);if(this._isFallbackRoot(u)){if(!this._root)throw Error("unexpected error");return(l=this._root).t.apply(l,[t].concat(o))}return this._warnDefault(c,t,u,r);var l},M.prototype.t=function(t){for(var e=[],n=arguments.length-1;n-- >0;)e[n]=arguments[n+1];return(r=this)._t.apply(r,[t,this.locale,this._getMessages(),null].concat(e));var r},M.prototype._i=function(t,e,n,r,i){var o=this._translate(n,e,this.fallbackLocale,t,r,"raw",i);if(this._isFallbackRoot(o)){if(!this._root)throw Error("unexpected error");return this._root.i(t,e,i)}return this._warnDefault(e,t,o,r)},M.prototype.i=function(t,e,n){return t?("string"!=typeof e&&(e=this.locale),this._i(t,e,this._getMessages(),null,n)):""},M.prototype._tc=function(t,e,n,r,i){for(var a=[],s=arguments.length-5;s-- >0;)a[s]=arguments[s+5];return t?(void 0===i&&(i=1),o((c=this)._t.apply(c,[t,e,n,r].concat(a)),i)):"";var c},M.prototype.tc=function(t,e){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];return(i=this)._tc.apply(i,[t,this.locale,this._getMessages(),null,e].concat(n));var i},M.prototype._te=function(t,e,n){for(var r=[],o=arguments.length-3;o-- >0;)r[o]=arguments[o+3];var a=i.apply(void 0,r).locale||e;return this._exist(n[a],t)},M.prototype.te=function(t,e){return this._te(t,this.locale,this._getMessages(),e)},M.prototype.getLocaleMessage=function(t){return a(this._vm.messages[t]||{})},M.prototype.setLocaleMessage=function(t,e){this._vm.messages[t]=e},M.prototype.mergeLocaleMessage=function(t,e){this._vm.messages[t]=h.util.extend(this._vm.messages[t]||{},e)},M.prototype.getDateTimeFormat=function(t){return a(this._vm.dateTimeFormats[t]||{})},M.prototype.setDateTimeFormat=function(t,e){this._vm.dateTimeFormats[t]=e},M.prototype.mergeDateTimeFormat=function(t,e){this._vm.dateTimeFormats[t]=h.util.extend(this._vm.dateTimeFormats[t]||{},e)},M.prototype._localizeDateTime=function(t,e,n,i,o){var a=e,s=i[a];if((r(s)||r(s[o]))&&(a=n,s=i[a]),r(s)||r(s[o]))return null;var c=s[o],u=a+"__"+o,l=this._dateTimeFormatters[u];return l||(l=this._dateTimeFormatters[u]=new Intl.DateTimeFormat(a,c)),l.format(t)},M.prototype._d=function(t,e,n){if(!n)return new Intl.DateTimeFormat(e).format(t);var r=this._localizeDateTime(t,e,this.fallbackLocale,this._getDateTimeFormats(),n);if(this._isFallbackRoot(r)){if(!this._root)throw Error("unexpected error");return this._root.d(t,n,e)}return r||""},M.prototype.d=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=this.locale,o=null;return 1===n.length?"string"==typeof n[0]?o=n[0]:e(n[0])&&(n[0].locale&&(i=n[0].locale),n[0].key&&(o=n[0].key)):2===n.length&&("string"==typeof n[0]&&(o=n[0]),"string"==typeof n[1]&&(i=n[1])),this._d(t,i,o)},M.prototype.getNumberFormat=function(t){return a(this._vm.numberFormats[t]||{})},M.prototype.setNumberFormat=function(t,e){this._vm.numberFormats[t]=e},M.prototype.mergeNumberFormat=function(t,e){this._vm.numberFormats[t]=h.util.extend(this._vm.numberFormats[t]||{},e)},M.prototype._localizeNumber=function(t,e,n,i,o){var a=e,s=i[a];if((r(s)||r(s[o]))&&(a=n,s=i[a]),r(s)||r(s[o]))return null;var c=s[o],u=a+"__"+o,l=this._numberFormatters[u];return l||(l=this._numberFormatters[u]=new Intl.NumberFormat(a,c)),l.format(t)},M.prototype._n=function(t,e,n){if(!n)return new Intl.NumberFormat(e).format(t);var r=this._localizeNumber(t,e,this.fallbackLocale,this._getNumberFormats(),n);if(this._isFallbackRoot(r)){if(!this._root)throw Error("unexpected error");return this._root.n(t,n,e)}return r||""},M.prototype.n=function(t){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=this.locale,o=null;return 1===n.length?"string"==typeof n[0]?o=n[0]:e(n[0])&&(n[0].locale&&(i=n[0].locale),n[0].key&&(o=n[0].key)):2===n.length&&("string"==typeof n[0]&&(o=n[0]),"string"==typeof n[1]&&(i=n[1])),this._n(t,i,o)},Object.defineProperties(M.prototype,R),M.availabilities={dateTimeFormat:y,numberFormat:_},M.install=function t(e){(h=e).version&&Number(h.version.split(".")[0]),t.installed=!0,Object.defineProperty(h.prototype,"$i18n",{get:function(){return this._i18n}}),n=h,Object.defineProperty(n.prototype,"$t",{get:function(){var t=this;return function(e){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];var i=t.$i18n;return i._t.apply(i,[e,i.locale,i._getMessages(),t].concat(n))}}}),Object.defineProperty(n.prototype,"$tc",{get:function(){var t=this;return function(e,n){for(var r=[],i=arguments.length-2;i-- >0;)r[i]=arguments[i+2];var o=t.$i18n;return o._tc.apply(o,[e,o.locale,o._getMessages(),t,n].concat(r))}}}),Object.defineProperty(n.prototype,"$te",{get:function(){var t=this;return function(e,n){var r=t.$i18n;return r._te(e,r.locale,r._getMessages(),n)}}}),Object.defineProperty(n.prototype,"$d",{get:function(){var t=this;return function(e){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(i=t.$i18n).d.apply(i,[e].concat(n));var i}}}),Object.defineProperty(n.prototype,"$n",{get:function(){var t=this;return function(e){for(var n=[],r=arguments.length-1;r-- >0;)n[r]=arguments[r+1];return(i=t.$i18n).n.apply(i,[e].concat(n));var i}}}),h.mixin(b),h.directive("t",{bind:c,update:u}),h.component(w.name,w);var n,r=h.config.optionMergeStrategies;r.i18n=r.methods},M.version="7.3.3","undefined"!=typeof window&&window.Vue&&window.Vue.use(M),M});var messages={en:{title:"Stairs",systemID:"System ID",firmwareVersion:"Firmware version: ",copyright:"Copyright © 2017 Mark van Renswoude",loading:"Please wait, loading configuration...",applyButton:"Apply",applyButtonSaving:"Saving...",wifiStatus:{accesspoint:{title:"AP: ",disabled:"Disabled"},stationmode:{title:"WiFi: ",disabled:"Disabled",idle:"Idle",noSSID:"SSID not found",scanCompleted:"Scan completed",connectFailed:"Failed to connect",connectionLost:"Connection lost",disconnected:"Disconnected"}},status:{tabTitle:"Status",title:"Current status"},triggers:{tabTitle:"Triggers",timeTitle:"Time",motionTitle:"Motion"},connection:{tabTitle:"Connection",title:"Connection parameters",accesspoint:"Enable access point",accesspointHint:"Allows for a direct connection from your device to this Stairs module for configuration purposes. The Stairs configuration is available on http://192.168.1.4/ when you are connected to it. Turn it off as soon as station mode is configured, as it is not secured in any way. You can always turn this option back on by pushing the access point button until the LED lights up.",stationmode:"Enable station mode",stationmodeHint:"Connect this Stairs module to your own WiFi router. Please enter the SSID, password and further configuration below.",ssid:"SSID",password:"Password",dhcp:"Use DHCP",dhcpHint:"Automatically assigns an IP address to this Stairs module. You probably want to keep this on unless you know what you're doing.",ipaddress:"IP address",subnetmask:"Subnet mask",gateway:"Gateway",hostname:"Hostname",hostnamePlaceholder:"Default: mac address"}},nl:{title:"Trap",systemID:"Systeem ID",firmwareVersion:"Firmware versie: ",copyright:"Copyright © 2017 Mark van Renswoude",loading:"Een ogenblik geduld, bezig met laden van configuratie...",applyButton:"Apply",applyButtonSaving:"Saving...",wifiStatus:{accesspoint:{title:"AP: ",disabled:"Uitgeschakeld"},stationmode:{title:"WiFi: ",disabled:"Uitgeschakeld",idle:"Slaapstand",noSSID:"SSID niet gevonden",scanCompleted:"Scan afgerond",connectFailed:"Kan geen verbinding maken",connectionLost:"Verbinding verloren",disconnected:"Niet verbonden"}},status:{tabTitle:"Status",title:"Huidige status"},triggers:{tabTitle:"Triggers",timeTitle:"Tijd",motionTitle:"Beweging"},connection:{tabTitle:"Verbinding",title:"Verbinding configuratie",accesspoint:"Access point inschakelen",accesspointhint:"Maakt het mogelijk om een directe connectie vanaf een apparaat naar deze Trap module te maken om de module te configureren. De Trap module is te benaderen via http://192.168.1.4/ nadat je connectie hebt gemaakt. Schakel deze optie uit na het configureren, aangezien deze niet beveiligd is. Je kunt deze optie ook inschakelen door op de Access point knop te drukken totdat de LED aan gaat.",stationmode:"Verbinding met WiFi maken",stationmodehint:"Verbind deze Trap module aan je eigen WiFi router. Vul hieronder het SSID en wachtwoord in, en configureer eventuel de overige opties.",ssid:"SSID",password:"Wachtwoord",dhcp:"Gebruik DHCP",dhcphint:"Automatisch een IP adres toewijzen aan deze Trap module. Waarschijnlijk wil je deze optie aan laten, tenzij je weet waar je mee bezig bent.",ipaddress:"IP adres",subnetmask:"Subnet masker",gateway:"Gateway",hostname:"Hostnaam",hostnamePlaceholder:"Standaard: mac adres"}}};function startApp(){var t=new VueI18n({locale:navigator.language,fallbackLocale:"en",messages:messages});new Vue({el:"#app",i18n:t,data:{loading:!0,saving:!1,loadingIndicator:"|",activeTab:"status",version:{systemID:"loading...",version:"loading..."},wifiStatus:{ap:{enabled:!1,ip:"0.0.0.0"},station:{enabled:!1,status:0,ip:"0.0.0.0"}},connection:{hostname:null,accesspoint:!0,station:!1,ssid:null,password:null,dhcp:!0,ip:null,subnetmask:null,gateway:null},steps:[{value:50},{value:0},{value:0},{value:0},{value:0},{value:70},{value:0},{value:0},{value:0},{value:0},{value:25},{value:0},{value:0},{value:0}]},created:function(){var e=this;document.title=t.t("title"),e.startLoadingIndicator(),e.updateWiFiStatus(),setInterval(e.updateWiFiStatus,5e3),axios.get("/api/version").then(function(t){"object"==typeof t.data&&(e.version=t.data)}).catch(function(t){console.log(t)}),axios.all([axios.get("/api/connection").then(function(t){"object"==typeof t.data&&(e.connection=t.data)}).catch(function(t){console.log(t)})]).then(axios.spread(function(t,n){e.stopLoadingIndicator(),e.loading=!1}))},methods:{applyConnection:function(){var t=this;t.saving||(t.saving=!0,axios.post("/api/connection",{hostname:t.connection.hostname,accesspoint:t.connection.accesspoint,station:t.connection.station,ssid:t.connection.ssid,password:t.connection.password,dhcp:t.connection.dhcp,ip:t.connection.ip,subnetmask:t.connection.subnetmask,gateway:t.connection.gateway}).then(function(t){}).catch(function(t){console.log(t)}).then(function(){t.saving=!1}))},startLoadingIndicator:function(){var t=this;t.loadingStage=0,t.loadingTimer=setInterval(function(){switch(t.loadingStage++,console.log(t.loadingStage),t.loadingStage){case 1:t.loadingIndicator="/";break;case 2:t.loadingIndicator="-";break;case 3:t.loadingIndicator="\\";break;case 4:t.loadingIndicator="|",t.loadingStage=0}},250)},stopLoadingIndicator:function(){clearInterval(this.loadingTimer)},getWiFiStationStatus:function(){if(!this.wifiStatus.station.enabled)return"disconnected";switch(this.wifiStatus.station.status){case 0:case 2:return"connecting";case 1:case 4:case 5:return"error";case 3:return"connected";case 6:default:return"disconnected"}},getWiFiStationStatusText:function(){if(!this.wifiStatus.station.enabled)return t.t("wifiStatus.stationmode.disabled");switch(this.wifiStatus.station.status){case 0:return t.t("wifiStatus.stationmode.idle");case 1:return t.t("wifiStatus.stationmode.noSSID");case 2:return t.t("wifiStatus.stationmode.scanCompleted");case 3:return this.wifiStatus.station.ip;case 4:return t.t("wifiStatus.stationmode.connectFailed");case 5:return t.t("wifiStatus.stationmode.connectionLost");case 6:default:return t.t("wifiStatus.stationmode.disconnected")}},updateWiFiStatus:function(){var t=this;t.saving||axios.get("/api/connection/status").then(function(e){"object"==typeof e.data&&(t.wifiStatus=e.data)}).catch(function(t){console.log(t)})}}})}
\ No newline at end of file
diff --git a/web/gulpfile.js b/web/gulpfile.js
deleted file mode 100644
index 06a443f..0000000
--- a/web/gulpfile.js
+++ /dev/null
@@ -1,96 +0,0 @@
-'use strict';
-
-var gulp = require('gulp');
-var ts = require('gulp-typescript');
-var uglify = require('gulp-uglify');
-var sass = require('gulp-sass');
-var cleanCSS = require('gulp-clean-css');
-var concat = require('gulp-concat');
-var watch = require('gulp-debounced-watch');
-var plumber = require('gulp-plumber');
-
-
-var config =
-{
- dest: 'static/assets/dist/',
- typescriptBase: 'static/assets/ts/',
- sassBase: 'static/assets/sass/',
-
- assets: ['static/assets/ts/**/*.html', 'static/assets/js/**/*.js']
-};
-
-config.typescriptSrc = config.typescriptBase + '**/*.ts';
-config.sassSrc = config.sassBase + '**/*.scss';
-
-
-gulp.task('default',
- [
- 'compileTypescript',
- 'compileSass',
- 'copyAssets'
- ],
- function(){});
-
-gulp.task('watch',
- [
- 'compileTypescript',
- 'compileSass',
- 'copyAssets'
- ],
- function()
- {
- watch(config.typescriptSrc, function() { gulp.start('compileTypescript'); });
- watch(config.sassSrc, function() { gulp.start('compileSass'); });
- watch(config.assets, function() { gulp.start('copyAssets'); });
- });
-
-
-gulp.task('compileTypescript', function()
-{
- return gulp.src(config.typescriptSrc, { base: config.typescriptBase })
- .pipe(plumber({
- errorHandler: function (error)
- {
- console.log(error.message);
- this.emit('end');
- }}))
- .pipe(ts(
- {
- noImplicitAny: true,
- removeComments: true,
- preserveConstEnums: true,
- sourceMap: true,
- module: 'amd'
- }))
- .pipe(uglify())
- .pipe(gulp.dest(config.dest));
-});
-
-
-gulp.task('compileSass', function()
-{
- return gulp.src(config.sassSrc)
- .pipe(plumber({
- errorHandler: function (error)
- {
- console.log(error.message);
- this.emit('end');
- }}))
- .pipe(sass())
- .pipe(concat('bundle.css'))
- .pipe(cleanCSS())
- .pipe(gulp.dest(config.dest));
-});
-
-
-gulp.task('copyAssets', function()
-{
- return gulp.src(config.assets)
- .pipe(plumber({
- errorHandler: function (error)
- {
- console.log(error.message);
- this.emit('end');
- }}))
- .pipe(gulp.dest(config.dest));
-});
\ No newline at end of file
diff --git a/web/index.html b/web/index.html
new file mode 100644
index 0000000..1e9d39d
--- /dev/null
+++ b/web/index.html
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('loading') }} {{ loadingIndicator }}
+
+
+
+
+ {{ $t('status.tabTitle') }}
+ {{ $t('triggers.tabTitle') }}
+ {{ $t('connection.tabTitle') }}
+
+
+
+
{{ $t('status.title') }}
+
+
+ {{ index + 1 }}
+
+ {{ step.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('copyright') }}
+ {{ version.version !== null ? $t('firmwareVersion') + version.version : '' }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/lang.js b/web/lang.js
new file mode 100644
index 0000000..01a9d49
--- /dev/null
+++ b/web/lang.js
@@ -0,0 +1,127 @@
+var messages = {
+ en: {
+ title: 'Stairs',
+ systemID: 'System ID',
+ firmwareVersion: 'Firmware version: ',
+ copyright: 'Copyright © 2017 Mark van Renswoude',
+ loading: 'Please wait, loading configuration...',
+
+ applyButton: 'Apply',
+ applyButtonSaving: 'Saving...',
+
+ wifiStatus: {
+ accesspoint: {
+ title: 'AP: ',
+ disabled: 'Disabled'
+ },
+
+ stationmode: {
+ title: 'WiFi: ',
+ disabled: 'Disabled',
+ idle: 'Idle',
+ noSSID: 'SSID not found',
+ scanCompleted: 'Scan completed',
+ connectFailed: 'Failed to connect',
+ connectionLost: 'Connection lost',
+ disconnected: 'Disconnected'
+ }
+ },
+
+ status: {
+ tabTitle: 'Status',
+ title: 'Current status'
+ },
+
+ triggers: {
+ tabTitle: 'Triggers',
+ timeTitle: 'Time',
+ motionTitle: 'Motion'
+ },
+
+ connection: {
+ tabTitle: 'Connection',
+ title: 'Connection parameters',
+
+ accesspoint: 'Enable access point',
+ accesspointHint: 'Allows for a direct connection from your device to this Stairs module for configuration purposes. The Stairs configuration is available on http://192.168.1.4/ when you are connected to it. Turn it off as soon as station mode is configured, as it is not secured in any way. You can always turn this option back on by pushing the access point button until the LED lights up.',
+
+ stationmode: 'Enable station mode',
+ stationmodeHint: 'Connect this Stairs module to your own WiFi router. Please enter the SSID, password and further configuration below.',
+
+ ssid: 'SSID',
+ password: 'Password',
+
+ dhcp: 'Use DHCP',
+ dhcpHint: 'Automatically assigns an IP address to this Stairs module. You probably want to keep this on unless you know what you\'re doing.',
+
+ ipaddress: 'IP address',
+ subnetmask: 'Subnet mask',
+ gateway: 'Gateway',
+ hostname: 'Hostname',
+ hostnamePlaceholder: 'Default: mac address'
+ }
+ },
+
+ nl: {
+ title: 'Trap',
+ systemID: 'Systeem ID',
+ firmwareVersion: 'Firmware versie: ',
+ copyright: 'Copyright © 2017 Mark van Renswoude',
+ loading: 'Een ogenblik geduld, bezig met laden van configuratie...',
+
+ applyButton: 'Apply',
+ applyButtonSaving: 'Saving...',
+
+ wifiStatus: {
+ accesspoint: {
+ title: 'AP: ',
+ disabled: 'Uitgeschakeld'
+ },
+
+ stationmode: {
+ title: 'WiFi: ',
+ disabled: 'Uitgeschakeld',
+ idle: 'Slaapstand',
+ noSSID: 'SSID niet gevonden',
+ scanCompleted: 'Scan afgerond',
+ connectFailed: 'Kan geen verbinding maken',
+ connectionLost: 'Verbinding verloren',
+ disconnected: 'Niet verbonden'
+ }
+ },
+
+ status: {
+ tabTitle: 'Status',
+ title: 'Huidige status'
+ },
+
+ triggers: {
+ tabTitle: 'Triggers',
+ timeTitle: 'Tijd',
+ motionTitle: 'Beweging'
+ },
+
+ connection: {
+ tabTitle: 'Verbinding',
+ title: 'Verbinding configuratie',
+
+ accesspoint: 'Access point inschakelen',
+ accesspointhint: 'Maakt het mogelijk om een directe connectie vanaf een apparaat naar deze Trap module te maken om de module te configureren. De Trap module is te benaderen via http://192.168.1.4/ nadat je connectie hebt gemaakt. Schakel deze optie uit na het configureren, aangezien deze niet beveiligd is. Je kunt deze optie ook inschakelen door op de Access point knop te drukken totdat de LED aan gaat.',
+
+ stationmode: 'Verbinding met WiFi maken',
+ stationmodehint: 'Verbind deze Trap module aan je eigen WiFi router. Vul hieronder het SSID en wachtwoord in, en configureer eventuel de overige opties.',
+
+ ssid: 'SSID',
+ password: 'Wachtwoord',
+
+ dhcp: 'Gebruik DHCP',
+ dhcphint: 'Automatisch een IP adres toewijzen aan deze Trap module. Waarschijnlijk wil je deze optie aan laten, tenzij je weet waar je mee bezig bent.',
+
+ ipaddress: 'IP adres',
+ subnetmask: 'Subnet masker',
+ gateway: 'Gateway',
+ hostname: 'Hostnaam',
+ hostnamePlaceholder: 'Standaard: mac adres'
+ }
+ }
+}
\ No newline at end of file
diff --git a/web/logo.ai b/web/logo.ai
new file mode 100644
index 0000000..1b09e41
--- /dev/null
+++ b/web/logo.ai
@@ -0,0 +1,333 @@
+%PDF-1.5
%âãÏÓ
+1 0 obj
<>/OCGs[5 0 R 21 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<>stream
+
+
+
+
+ Adobe Illustrator CS6 (Windows)
+ 2017-12-30T16:13+01:00
+ 2017-12-30T16:17:16+01:00
+ 2017-12-30T16:17:16+01:00
+
+
+
+ 248
+ 256
+ JPEG
+ /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAD4AwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY
q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq
7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7
FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F
XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX
Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FX//2Q==
+
+
+
+
+
+ 1
+ False
+ False
+
+ 512.000000
+ 512.000000
+ Points
+
+
+
+
+ Default Swatch Group
+ 0
+
+
+
+
+
+ application/pdf
+
+
+ Document
+
+
+ xmp.did:89DEF0EC73EDE7119CCADB31B93B2005
+ uuid:b03a2483-4f32-4465-b083-e0550ab05b88
+ xmp.did:89DEF0EC73EDE7119CCADB31B93B2005
+ proof:pdf
+
+
+
+
+ saved
+ xmp.iid:89DEF0EC73EDE7119CCADB31B93B2005
+ 2017-12-30T16:13:01+01:00
+ Adobe Illustrator CS6 (Windows)
+ /
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+endstream
endobj
3 0 obj
<>
endobj
7 0 obj
<>/Resources<>/Properties<>>>/Thumb 26 0 R/TrimBox[0.0 0.0 512.0 512.0]/Type/Page>>
endobj
23 0 obj
<>stream
+H‰”‘Á
+Â0†ïyŠ¼Àº&M¶õj•0dîàˆxqÂôàëÛ
+º¦ ¡¥)ßßÐr°ì‚ÅÕ: L`Q‰_«HÛí¼aª}*†±Ù"”í`ñ|‡)¶6VdÄáºFfÂãévnØ8'ñ|úEÞÿàûÿó]•ûDyšó¿L9{¼7\Qâr
¥g¹…1ÄŠñ)–4ãV5º€¿íM.Wÿ!7]üŠž CÕPt
+endstream
endobj
26 0 obj
<>stream
+8;Z]L!=]#/!5bE.$"(^o%O_;W!8uZ9(]Y:
+endstream
endobj
27 0 obj
[/Indexed/DeviceRGB 255 28 0 R]
endobj
28 0 obj
<>stream
+8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
+b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
+E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn
+6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j $XKrcYp0n+Xl_nU*O(
+l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
+endstream
endobj
21 0 obj
<>
endobj
29 0 obj
[/View/Design]
endobj
30 0 obj
<>>>
endobj
25 0 obj
<>
endobj
24 0 obj
<>
endobj
31 0 obj
<>
endobj
32 0 obj
<>stream
+%!PS-Adobe-3.0
+%%Creator: Adobe Illustrator(R) 16.0
+%%AI8_CreatorVersion: 16.0.0
+%%For: (PsychoMark) ()
+%%Title: (logo.ai)
+%%CreationDate: 12/30/2017 4:17 PM
+%%Canvassize: 16383
+%%BoundingBox: 113 218 501 623
+%%HiResBoundingBox: 113.6367 218.375 500.3867 622.625
+%%DocumentProcessColors:
+%AI5_FileFormat 12.0
+%AI12_BuildNumber: 682
+%AI3_ColorUsage: Color
+%AI7_ImageSettings: 0
+%%RGBProcessColor: 0 0 0 ([Registration])
+%AI3_Cropmarks: 41.5 164.5 553.5 676.5
+%AI3_TemplateBox: 297.5 420.5 297.5 420.5
+%AI3_TileBox: -8.5 24.5 603.5 816.5
+%AI3_DocumentPreview: None
+%AI5_ArtSize: 14400 14400
+%AI5_RulerUnits: 2
+%AI9_ColorModel: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI9_OpenToView: -1232 1218 0.5 1789 914 26 0 0 82 117 0 0 0 1 1 1 1 1 0 1
+%AI5_OpenViewLayers: 7
+%%PageOrigin:0 0
+%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9
+%AI9_Flatten: 1
+%AI12_CMSettings: 00.MS
+%%EndComments
+
+endstream
endobj
33 0 obj
<>stream
+%%BoundingBox: 113 218 501 623
+%%HiResBoundingBox: 113.6367 218.375 500.3867 622.625
+%AI7_Thumbnail: 124 128 8
+%%BeginData: 2021 Hex Bytes
+%0000330000660000990000CC0033000033330033660033990033CC0033FF
+%0066000066330066660066990066CC0066FF009900009933009966009999
+%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66
+%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333
+%3333663333993333CC3333FF3366003366333366663366993366CC3366FF
+%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99
+%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033
+%6600666600996600CC6600FF6633006633336633666633996633CC6633FF
+%6666006666336666666666996666CC6666FF669900669933669966669999
+%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33
+%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF
+%9933009933339933669933999933CC9933FF996600996633996666996699
+%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33
+%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF
+%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399
+%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933
+%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF
+%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC
+%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699
+%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33
+%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100
+%000011111111220000002200000022222222440000004400000044444444
+%550000005500000055555555770000007700000077777777880000008800
+%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB
+%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF
+%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF
+%524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF
+%FDFCFFFDFCFFFDFCFFFDF7FFFF
+%%EndData
+
+endstream
endobj
34 0 obj
<>stream
+%AI12_CompressedDataxœÜ½gwò:Ó0z>ïµò(Iè`z
½)Š)¡Æ†]žïo?’ÜdãFÙïÙç¹÷ºs–g¤Ñhšf¤;c£åÊL¶#Òåw†›?îîr9Üo©˜ýl¨¬VzOÁŸ¬M›Ár°U¦°-;$E/¶›zÆ<-Â÷
úŸñ|û4¤–6ƒÕo/ö+ô»€Þ}¥‡3ÐmôýTÖ৹߃ŽÑ1"Y³”Å1‚_ÑÖ&9[ 4ú²q©ín
ÞxÝA@” øúÁßP8ä²íÚäz·„EÃ÷EÃàqÀG€¿Øg®)jæŠÀç^ˆ€ð"^ž@òÏùWÌð¼Ý,m2Ô¾ÅÌP @Ì_öQó°"©×ÍbúË'Êçi;!Wà
Dq5D4Aÿy…¿l‹öš‘{0±ÛÕa¸.ÂcPþ¸‘Ôwä¦½í ®º¼>¿LàHo85D½ƒ/„°DÀ3Àpbî?‚ï„!q8ÂpÚ`&ëÔb¶ØĸN†%j1¦7ì3D˜?h îöÿ(÷¶¿`ôû=¹á X+÷„1
+á~jA¬…Í$·]É ÑJ ,²Ü–ûTø‚ž‡;ôà Ì[ƒZl à›?ž™g‘Acu KÔö°«l¦Û›?¬Œèc°ÐÁäNõÑø4bbC›ŽðoöΦŒ“"
ÌSð.ú
+þÂõ¼Ÿ'§`
+ ˜_›?ÉÕv‡æn&†·!µÓ¼±n†”=àaׂ'C@2ºð›.°€kv€Hè%ÔF‚B¥öHªá~nÈ®ÈÍ„æ¡3_%g~Ô²õÏz´]-è5ÿ…ÿ¬³w{’ÚÔ7L7©=7´·Û•@¦ûH˜djϼóŸAÂ7–C þw熫ÕbF
wóÅX¾Ìs‘»º¸hŒ¨.‡QüˆGvüÆ ÇD…É?…eÚ¦õ×p?žñ2¢†Ô‚ÔX‹pz§‹Ít´uXìIa¾¶ë4uùp†-‹XKnp ® \.MÕežA¿ÿgEã©n¶mÐ7°Ž¬@$«ý—Íày®Iƒ´i-€ùAòCþÁUlwi‚?îpð
é…£¡ˆ} |>ÔŽ°oØ׺ø‚—ûöüö>ý€ßþ2x Óáã‹0LnÀC ᘀ®0¢;~ó‡Áz
+? aR`ƒÒ¦Nc¸ê˜d†Ñéï·ÔCèþ¤œÔÂkŒÁÿ³Boxœ§MR
MÌñ™&gò„—`2²‚ú¸ß0é¯JØNs†%ð GÜ
<Üoà×Å’gHýÃü@