[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/app/zte_webui/js/3rd/apache.echarts.js b/ap/app/zte_webui/js/3rd/apache.echarts.js
new file mode 100755
index 0000000..e4473aa
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/apache.echarts.js
@@ -0,0 +1,9 @@
+!function(t,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():t.echarts=e()}(this,function(){var t,e;!function(){function i(t,e){if(!e)return t;if(0===t.indexOf(".")){var i=e.split("/"),n=t.split("/"),r=i.length-1,a=n.length,o=0,s=0;t:for(var l=0;a>l;l++)switch(n[l]){case"..":if(!(r>o))break t;o++,s++;break;case".":s++;break;default:break t}return i.length=r-o,n=n.slice(s),i.concat(n).join("/")}return t}function n(t){function e(e,o){if("string"==typeof e){var s=n[e];return s||(s=a(i(e,t)),n[e]=s),s}e instanceof Array&&(o=o||function(){},o.apply(this,r(e,o,t)))}var n={};return e}function r(e,n,r){for(var s=[],l=o[r],c=0,u=Math.min(e.length,n.length);u>c;c++){var h,d=i(e[c],r);switch(d){case"require":h=l&&l.require||t;break;case"exports":h=l.exports;break;case"module":h=l;break;default:h=a(d)}s.push(h)}return s}function a(t){var e=o[t];if(!e)throw new Error("No "+t);if(!e.defined){var i=e.factory,n=i.apply(this,r(e.deps||[],i,t));"undefined"!=typeof n&&(e.exports=n),e.defined=1}return e.exports}var o={};e=function(t,e,i){o[t]={id:t,deps:e,factory:i,defined:0,exports:{},require:n(t)}},t=n("")}();var i="moveTo",n="radius",r="../../echarts",a="../../util/graphic",o="dataToPoint",s="dimensions",l="ordinal",c="category",u="parsePercent",h="getItemModel",d="../core/util",f="createElement",p="undefined",g="updateProps",v="animation",m="inside",y="getShallow",x="stroke",_="lineWidth",b="applyTransform",w="Sector",S="getItemGraphicEl",M="normal",A="emphasis",C="getItemVisual",T="getName",L="ecModel",P="getComponent",z="option",k="getExtent",I="getLabel",D="contain",O="opacity",R="position",B="center",E="middle",N="getBoundingRect",V="getFont",F="textAlign",G="textStyle",H="coordinateSystem",q="removeAll",W="inherits",Z="function",X="indexOf",j="isArray",U="replace",Y="zlevel",Q="getDataParams",$="seriesIndex",K="dataIndex",J="target",te="mouseout",ee="mouseover",ie="getData",ne="splice",re="series",ae="trigger",oe="length",se="defaults",le="extend",ce="remove",ue="isObject",he="update",de="create",fe="height",pe="bottom",ge="ignore",ve="getHeight",me="getWidth",ye="getModel",xe="resize",_e="string",be="prototype",we="toLowerCase",Se="filter",Me="transform",Ae="zrender/core/util",Ce="require";e("echarts/echarts",[Ce,"./model/Global","./ExtensionAPI","./CoordinateSystem","./model/OptionManager","./model/Component","./model/Series","./view/Component","./view/Chart","./util/graphic","zrender",Ae,"zrender/tool/color","zrender/core/env","zrender/mixin/Eventful","./loading/default","./visual/seriesColor","./preprocessor/backwardCompat","./util/number","./util/format","zrender/core/matrix","zrender/core/vector"],function(t){function e(t){return function(e,i,n){e=e&&e[we](),T[be][t].call(this,e,i,n)}}function i(){T.call(this)}function n(t,e,n){n=n||{},typeof e===_e&&(e=G[e]),e&&L(V,function(t){t(e)}),this.id,this.group,this._dom=t,this._zr=S.init(t,{renderer:n.renderer||"canvas",devicePixelRatio:n.devicePixelRatio}),this._theme=M.clone(e),this._chartsViews=[],this._chartsMap={},this._componentsViews=[],this._componentsMap={},this._api=new g(this),this._coordSysMgr=new v,T.call(this),this._messageCenter=new i,this._initEvents(),this[xe]=M.bind(this[xe],this)}function r(t,e){var i=this._model;i&&i.eachComponent({mainType:"series",query:e},function(n){var r=this._chartsMap[n.__viewId];r&&r.__alive&&r[t](n,i,this._api,e)},this)}function a(t,e,i){var n=this._api;L(this._componentsViews,function(r){var a=r.__model;r[t](a,e,n,i),d(a,r)},this),e.eachSeries(function(r){var a=this._chartsMap[r.__viewId];a[t](r,e,n,i),d(r,a)},this)}function o(t,e){for(var i="component"===t,n=i?this._componentsViews:this._chartsViews,r=i?this._componentsMap:this._chartsMap,a=this._zr,o=0;o<n[oe];o++)n[o].__alive=!1;e[i?"eachComponent":"eachSeries"](function(t,o){if(i){if(t===re)return}else o=t;var s=o.id+"_"+o.type,l=r[s];if(!l){var c=y.parseClassType(o.type),u=i?_.getClass(c.main,c.sub):b.getClass(c.sub);if(!u)return;l=new u,l.init(e,this._api),r[s]=l,n.push(l),a.add(l.group)}o.__viewId=s,l.__alive=!0,l.__id=s,l.__model=o},this);for(var o=0;o<n[oe];){var s=n[o];s.__alive?o++:(a[ce](s.group),s.dispose(e,this._api),n[ne](o,1),delete r[s.__id])}}function s(t,e){L(z,function(i){L(N[i]||[],function(i){i(t,e)})})}function l(t){var e={};t.eachSeries(function(t){var i=t.get("stack"),n=t[ie]();if(i&&"list"===n.type){var r=e[i];r&&(n.stackedOn=r),e[i]=n}})}function c(t,e){var i=this._api;L(E,function(n){n(t,i,e)})}function u(t,e){L(P,function(i){L(F[i]||[],function(i){i(t,e)})})}function h(t,e){var i=this._api;L(this._componentsViews,function(n){var r=n.__model;n.render(r,t,i,e),d(r,n)},this),L(this._chartsViews,function(t){t.__alive=!1},this),t.eachSeries(function(n){var r=this._chartsMap[n.__viewId];r.__alive=!0,r.render(n,t,i,e),r.group.silent=!!n.get("silent"),d(n,r)},this),L(this._chartsViews,function(e){e.__alive||e[ce](t,i)},this)}function d(t,e){var i=t.get("z"),n=t.get(Y);e.group.traverse(function(t){null!=i&&(t.z=i),null!=n&&(t[Y]=n)})}function f(t){function e(t,e){for(var i=0;i<t[oe];i++){var n=t[i];n[a]=e}}var i=0,n=1,r=2,a="__connectUpdateStatus";M.each(B,function(o,s){t._messageCenter.on(s,function(o){if(q[t.group]&&t[a]!==i){var s=t.makeActionFromEvent(o),l=[];for(var c in H){var u=H[c];u!==t&&u.group===t.group&&l.push(u)}e(l,i),L(l,function(t){t[a]!==n&&t.dispatchAction(s)}),e(l,r)}})})}var p=t("./model/Global"),g=t("./ExtensionAPI"),v=t("./CoordinateSystem"),m=t("./model/OptionManager"),y=t("./model/Component"),x=t("./model/Series"),_=t("./view/Component"),b=t("./view/Chart"),w=t("./util/graphic"),S=t("zrender"),M=t(Ae),A=t("zrender/tool/color"),C=t("zrender/core/env"),T=t("zrender/mixin/Eventful"),L=M.each,P=["echarts","chart","component"],z=[Me,Se,"statistic"];i[be].on=e("on"),i[be].off=e("off"),i[be].one=e("one"),M.mixin(i,T);var k=n[be];k.getDom=function(){return this._dom},k.getZr=function(){return this._zr},k.setOption=function(t,e,i){(!this._model||e)&&(this._model=new p(null,null,this._theme,new m(this._api))),this._model.setOption(t,V),I.prepareAndUpdate.call(this),!i&&this._zr.refreshImmediately()},k.setTheme=function(){console.log("ECharts#setTheme() is DEPRECATED in ECharts 3.0")},k[ye]=function(){return this._model},k.getOption=function(){return this._model.getOption()},k[me]=function(){return this._zr[me]()},k[ve]=function(){return this._zr[ve]()},k.getRenderedCanvas=function(t){if(C.canvasSupported){t=t||{},t.pixelRatio=t.pixelRatio||1,t.backgroundColor=t.backgroundColor||this._model.get("backgroundColor");var e=this._zr,i=e.storage.getDisplayList();return M.each(i,function(t){t.stopAnimation(!0)}),e.painter.getRenderedCanvas(t)}},k.getDataURL=function(t){t=t||{};var e=t.excludeComponents,i=this._model,n=[],r=this;L(e,function(t){i.eachComponent({mainType:t},function(t){var e=r._componentsMap[t.__viewId];e.group[ge]||(n.push(e),e.group[ge]=!0)})});var a=this.getRenderedCanvas(t).toDataURL("image/"+(t&&t.type||"png"));return L(n,function(t){t.group[ge]=!1}),a},k.getConnectedDataURL=function(t){if(C.canvasSupported){var e=this.group,i=Math.min,n=Math.max,r=1/0;if(q[e]){var a=r,o=r,s=-r,l=-r,c=[],u=t&&t.pixelRatio||1;for(var h in H){var d=H[h];if(d.group===e){var f=d.getRenderedCanvas(M.clone(t)),p=d.getDom().getBoundingClientRect();a=i(p.left,a),o=i(p.top,o),s=n(p.right,s),l=n(p[pe],l),c.push({dom:f,left:p.left,top:p.top})}}a*=u,o*=u,s*=u,l*=u;var g=s-a,v=l-o,m=M.createCanvas();m.width=g,m[fe]=v;var y=S.init(m);return L(c,function(t){var e=new w.Image({style:{x:t.left*u-a,y:t.top*u-o,image:t.dom}});y.add(e)}),y.refreshImmediately(),m.toDataURL("image/"+(t&&t.type||"png"))}return this.getDataURL(t)}};var I={update:function(t){var e=this._model,i=this._api,n=this._coordSysMgr;if(e){e.restoreData(),n[de](this._model,this._api),s.call(this,e,i),l.call(this,e),n[he](e,i),c.call(this,e,t),u.call(this,e,t),h.call(this,e,t);var r=e.get("backgroundColor")||"transparent",a=this._zr.painter;if(a.isSingleCanvas&&a.isSingleCanvas())this._zr.configLayer(0,{clearColor:r});else{if(!C.canvasSupported){var o=A.parse(r);r=A.stringify(o,"rgb"),0===o[3]&&(r="transparent")}r=r,this._dom.style.backgroundColor=r}}},updateView:function(t){var e=this._model;e&&(c.call(this,e,t),u.call(this,e,t),a.call(this,"updateView",e,t))},updateVisual:function(t){var e=this._model;e&&(u.call(this,e,t),a.call(this,"updateVisual",e,t))},updateLayout:function(t){var e=this._model;e&&(c.call(this,e,t),a.call(this,"updateLayout",e,t))},highlight:function(t){r.call(this,"highlight",t)},downplay:function(t){r.call(this,"downplay",t)},prepareAndUpdate:function(t){var e=this._model;o.call(this,"component",e),o.call(this,"chart",e),I[he].call(this,t)}};k[xe]=function(){this._zr[xe]();var t=this._model&&this._model.resetOption("media");I[t?"prepareAndUpdate":he].call(this),this._loadingFX&&this._loadingFX[xe]()};var D=t("./loading/default");k.showLoading=function(t,e){M[ue](t)&&(e=t,t="default"),this.hideLoading();var i=D(this._api,e),n=this._zr;this._loadingFX=i,n.add(i)},k.hideLoading=function(){this._loadingFX&&this._zr[ce](this._loadingFX),this._loadingFX=null},k.makeActionFromEvent=function(t){var e=M[le]({},t);return e.type=B[t.type],e},k.dispatchAction=function(t,e){var i=R[t.type];if(i){var n=i.actionInfo,r=n[he]||he,a=[t],o=!1;t.batch&&(o=!0,a=M.map(t.batch,function(e){return e=M[se](M[le]({},e),t),e.batch=null,e}));for(var s,l=[],c="highlight"===t.type||"downplay"===t.type,u=0;u<a[oe];u++){var h=a[u];s=i.action(h,this._model),s=s||M[le]({},h),s.type=n.event||s.type,l.push(s),c&&I[r].call(this,h)}"none"!==r&&!c&&I[r].call(this,t),e||(s=o?{type:n.event||t.type,batch:l}:l[0],this._messageCenter[ae](s.type,s))}},k.on=e("on"),k.off=e("off"),k.one=e("one");var O=["click","dblclick",ee,te,"mousedown","mouseup","globalout"];k._initEvents=function(){L(O,function(t){this._zr.on(t,function(e){var i=this[ye](),n=e[J];if(n&&null!=n[K]){var r=n.dataModel||i.getSeriesByIndex(n[$]),a=r&&r[Q](n[K],n.dataType)||{};a.event=e,a.type=t,this[ae](t,a)}else n&&n.eventData&&this[ae](t,n.eventData)},this)},this),L(B,function(t,e){this._messageCenter.on(e,function(t){this[ae](e,t)},this)},this)},k.isDisposed=function(){return this._disposed},k.clear=function(){this.setOption({},!0)},k.dispose=function(){this._disposed=!0;var t=this._api,e=this._model;L(this._componentsViews,function(i){i.dispose(e,t)}),L(this._chartsViews,function(i){i.dispose(e,t)}),this._zr.dispose(),delete H[this.id]},M.mixin(n,T);var R=[],B={},E=[],N={},V=[],F={},G={},H={},q={},Ce=new Date-0,Te=new Date-0,Le="_echarts_instance_",Pe={version:"0.0.0",dependencies:{zrender:"0.0.0"}};return Pe.init=function(t,e,i){if(S.version[U](".","")-0<Pe.dependencies.zrender[U](".","")-0)throw new Error("ZRender "+S.version+" is too old for ECharts "+Pe.version+". Current version need ZRender "+Pe.dependencies.zrender+"+");if(!t)throw new Error("Initialize failed: invalid dom.");var r=new n(t,e,i);return r.id="ec_"+Ce++,H[r.id]=r,t.setAttribute&&t.setAttribute(Le,r.id),f(r),r},Pe.connect=function(t){if(M[j](t)){var e=t;t=null,M.each(e,function(e){null!=e.group&&(t=e.group)}),t=t||"g_"+Te++,M.each(e,function(e){e.group=t})}return q[t]=!0,t},Pe.disConnect=function(t){q[t]=!1},Pe.dispose=function(t){M.isDom(t)?t=Pe.getInstanceByDom(t):typeof t===_e&&(t=H[t]),t instanceof n&&!t.isDisposed()&&t.dispose()},Pe.getInstanceByDom=function(t){var e=t.getAttribute(Le);return H[e]},Pe.getInstanceById=function(t){return H[t]},Pe.registerTheme=function(t,e){G[t]=e},Pe.registerPreprocessor=function(t){V.push(t)},Pe.registerProcessor=function(t,e){if(M[X](z,t)<0)throw new Error("stage should be one of "+z);var i=N[t]||(N[t]=[]);i.push(e)},Pe.registerAction=function(t,e,i){typeof e===Z&&(i=e,e="");var n=M[ue](t)?t.type:[t,t={event:e}][0];t.event=(t.event||n)[we](),e=t.event,R[n]||(R[n]={action:i,actionInfo:t}),B[e]=n},Pe.registerCoordinateSystem=function(t,e){v.register(t,e)},Pe.registerLayout=function(t){M[X](E,t)<0&&E.push(t)},Pe.registerVisualCoding=function(t,e){if(M[X](P,t)<0)throw new Error("stage should be one of "+P);var i=F[t]||(F[t]=[]);i.push(e)},Pe.extendChartView=function(t){return b[le](t)},Pe.extendComponentModel=function(t){return y[le](t)},Pe.extendSeriesModel=function(t){return x[le](t)},Pe.extendComponentView=function(t){return _[le](t)},Pe.setCanvasCreator=function(t){M.createCanvas=t},Pe.registerVisualCoding("echarts",M.curry(t("./visual/seriesColor"),"","itemStyle")),Pe.registerPreprocessor(t("./preprocessor/backwardCompat")),Pe.registerAction({type:"highlight",event:"highlight",update:"highlight"},M.noop),Pe.registerAction({type:"downplay",event:"downplay",update:"downplay"},M.noop),Pe.graphic=t("./util/graphic"),Pe.number=t("./util/number"),Pe.format=t("./util/format"),Pe.matrix=t("zrender/core/matrix"),Pe.vector=t("zrender/core/vector"),Pe.util={},L(["map","each",Se,X,W,"reduce",Se,"bind","curry",j,"isString",ue,"isFunction",le],function(t){Pe.util[t]=M[t]}),Pe}),e("echarts/chart/bar",[Ce,Ae,"../coord/cartesian/Grid","./bar/BarSeries","./bar/BarView","../layout/barGrid","../echarts","../component/grid"],function(t){var e=t(Ae);t("../coord/cartesian/Grid"),t("./bar/BarSeries"),t("./bar/BarView");var i=t("../layout/barGrid"),n=t("../echarts");n.registerLayout(e.curry(i,"bar")),n.registerVisualCoding("chart",function(t){t.eachSeriesByType("bar",function(t){var e=t[ie]();e.setVisual("legendSymbol","roundRect")})}),t("../component/grid")}),e("echarts/chart/line",[Ce,Ae,"../echarts","./line/LineSeries","./line/LineView","../visual/symbol","../layout/points","../processor/dataSample","../component/grid"],function(t){var e=t(Ae),i=t("../echarts");t("./line/LineSeries"),t("./line/LineView"),i.registerVisualCoding("chart",e.curry(t("../visual/symbol"),"line","circle","line")),i.registerLayout(e.curry(t("../layout/points"),"line")),i.registerProcessor("statistic",e.curry(t("../processor/dataSample"),"line")),t("../component/grid")}),e("echarts/chart/pie",[Ce,Ae,"../echarts","./pie/PieSeries","./pie/PieView","../action/createDataSelectAction","../visual/dataColor","./pie/pieLayout","../processor/dataFilter"],function(t){var e=t(Ae),i=t("../echarts");t("./pie/PieSeries"),t("./pie/PieView"),t("../action/createDataSelectAction")("pie",[{type:"pieToggleSelect",event:"pieselectchanged",method:"toggleSelected"},{type:"pieSelect",event:"pieselected",method:"select"},{type:"pieUnSelect",event:"pieunselected",method:"unSelect"}]),i.registerVisualCoding("chart",e.curry(t("../visual/dataColor"),"pie")),i.registerLayout(e.curry(t("./pie/pieLayout"),"pie")),i.registerProcessor(Se,e.curry(t("../processor/dataFilter"),"pie"))}),e("echarts/component/grid",[Ce,"../util/graphic",Ae,"../coord/cartesian/Grid","./axis","../echarts"],function(t){var e=t("../util/graphic"),i=t(Ae);t("../coord/cartesian/Grid"),t("./axis"),t("../echarts").extendComponentView({type:"grid",render:function(t){this.group[q](),t.get("show")&&this.group.add(new e.Rect({shape:t[H].getRect(),style:i[se]({fill:t.get("backgroundColor")},t.getItemStyle()),silent:!0}))}})}),e("echarts/component/polar",[Ce,"../coord/polar/polarCreator","./angleAxis","./radiusAxis","../echarts"],function(t){t("../coord/polar/polarCreator"),t("./angleAxis"),t("./radiusAxis"),t("../echarts").extendComponentView({type:"polar"})}),e("echarts/component/title",[Ce,"../echarts","../util/graphic","../util/layout"],function(t){var e=t("../echarts"),i=t("../util/graphic"),n=t("../util/layout");e.extendComponentModel({type:"title",layoutMode:{type:"box",ignoreSize:!0},defaultOption:{zlevel:0,z:6,show:!0,text:"",target:"blank",subtext:"",subtarget:"blank",left:0,top:0,backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderWidth:0,padding:5,itemGap:10,textStyle:{fontSize:18,fontWeight:"bolder",color:"#333"},subtextStyle:{color:"#aaa"}}}),e.extendComponentView({type:"title",render:function(t,e,r){if(this.group[q](),t.get("show")){var a=this.group,o=t[ye](G),s=t[ye]("subtextStyle"),l=t.get(F),c=new i.Text({style:{text:t.get("text"),textFont:o[V](),fill:o.getTextColor(),textBaseline:"top"},z2:10}),u=c[N](),h=t.get("subtext"),d=new i.Text({style:{text:h,textFont:s[V](),fill:s.getTextColor(),y:u[fe]+t.get("itemGap"),textBaseline:"top"},z2:10}),f=t.get("link"),p=t.get("sublink");c.silent=!f,d.silent=!p,f&&c.on("click",function(){window.open(f,"_"+t.get(J))}),p&&d.on("click",function(){window.open(p,"_"+t.get("subtarget"))}),a.add(c),h&&a.add(d);var g=a[N](),v=t.getBoxLayoutParams();v.width=g.width,v[fe]=g[fe];var m=n.getLayoutRect(v,{width:r[me](),height:r[ve]()},t.get("padding"));l||(l=t.get("left")||t.get("right"),l===E&&(l=B),"right"===l?m.x+=m.width:l===B&&(m.x+=m.width/2)),a[R]=[m.x,m.y],c.setStyle(F,l),d.setStyle(F,l),g=a[N]();var y=m.margin,x=t.getItemStyle(["color",O]);x.fill=t.get("backgroundColor");var _=new i.Rect({shape:{x:g.x-y[3],y:g.y-y[0],width:g.width+y[1]+y[3],height:g[fe]+y[0]+y[2]},style:x,silent:!0});i.subPixelOptimizeRect(_),a.add(_)}}})}),e("echarts/component/legend",[Ce,"./legend/LegendModel","./legend/legendAction","./legend/LegendView","../echarts","./legend/legendFilter"],function(t){t("./legend/LegendModel"),t("./legend/legendAction"),t("./legend/LegendView");var e=t("../echarts");e.registerProcessor(Se,t("./legend/legendFilter"))}),e("echarts/component/tooltip",[Ce,"./tooltip/TooltipModel","./tooltip/TooltipView","../echarts"],function(t){t("./tooltip/TooltipModel"),t("./tooltip/TooltipView"),t("../echarts").registerAction({type:"showTip",event:"showTip",update:"none"},function(){}),t("../echarts").registerAction({type:"hideTip",event:"hideTip",update:"none"},function(){})}),e("zrender/vml/vml",[Ce,"./graphic","../zrender","./Painter"],function(t){t("./graphic"),t("../zrender").registerPainter("vml",t("./Painter"))}),e("echarts/scale/Time",[Ce,Ae,"../util/number","../util/format","./Interval"],function(t){var e=t(Ae),i=t("../util/number"),n=t("../util/format"),r=t("./Interval"),a=r[be],o=Math.ceil,s=Math.floor,l=1e3,c=60*l,u=60*c,h=24*u,d=function(t,e,i,n){for(;n>i;){var r=i+n>>>1;t[r][2]<e?i=r+1:n=r}return i},f=r[le]({type:"time",getLabel:function(t){var e=this._stepLvl,i=new Date(t);return n.formatTime(e[0],i)},niceExtent:function(t,e,n){var r=this._extent;if(r[0]===r[1]&&(r[0]-=h,r[1]+=h),r[1]===-1/0&&1/0===r[0]){var a=new Date;r[1]=new Date(a.getFullYear(),a.getMonth(),a.getDate()),r[0]=r[1]-h}this.niceTicks(t);var l=this._interval;e||(r[0]=i.round(s(r[0]/l)*l)),n||(r[1]=i.round(o(r[1]/l)*l))},niceTicks:function(t){t=t||10;var e=this._extent,n=e[1]-e[0],r=n/t,a=p[oe],l=d(p,r,0,a),c=p[Math.min(l,a-1)],u=c[2];if("year"===c[0]){var h=n/u,f=i.nice(h/t,!0);u*=f}var g=[o(e[0]/u)*u,s(e[1]/u)*u];this._stepLvl=c,this._interval=u,this._niceExtent=g},parse:function(t){return+i.parseDate(t)}});e.each([D,"normalize"],function(t){f[be][t]=function(e){return a[t].call(this,this.parse(e))}});var p=[["hh:mm:ss",1,l],["hh:mm:ss",5,5*l],["hh:mm:ss",10,10*l],["hh:mm:ss",15,15*l],["hh:mm:ss",30,30*l],["hh:mm\nMM-dd",1,c],["hh:mm\nMM-dd",5,5*c],["hh:mm\nMM-dd",10,10*c],["hh:mm\nMM-dd",15,15*c],["hh:mm\nMM-dd",30,30*c],["hh:mm\nMM-dd",1,u],["hh:mm\nMM-dd",2,2*u],["hh:mm\nMM-dd",6,6*u],["hh:mm\nMM-dd",12,12*u],["MM-dd\nyyyy",1,h],["week",7,7*h],["month",1,31*h],["quarter",3,380*h/4],["half-year",6,380*h/2],["year",1,380*h]];return f[de]=function(){return new f},f}),e("echarts/scale/Log",[Ce,Ae,"./Scale","../util/number","./Interval"],function(t){var e=t(Ae),i=t("./Scale"),n=t("../util/number"),r=t("./Interval"),a=i[be],o=r[be],s=Math.floor,l=Math.ceil,c=Math.pow,u=10,h=Math.log,d=i[le]({type:"log",getTicks:function(){return e.map(o.getTicks.call(this),function(t){return n.round(c(u,t))})},getLabel:o[I],scale:function(t){return t=a.scale.call(this,t),c(u,t)},setExtent:function(t,e){t=h(t)/h(u),e=h(e)/h(u),o.setExtent.call(this,t,e)},getExtent:function(){var t=a[k].call(this);return t[0]=c(u,t[0]),t[1]=c(u,t[1]),t},unionExtent:function(t){t[0]=h(t[0])/h(u),t[1]=h(t[1])/h(u),a.unionExtent.call(this,t)},niceTicks:function(t){t=t||10;var e=this._extent,i=e[1]-e[0];if(!(1/0===i||0>=i)){var r=c(10,s(h(i/t)/Math.LN10)),a=t/i*r;.5>=a&&(r*=10);var o=[n.round(l(e[0]/r)*r),n.round(s(e[1]/r)*r)];this._interval=r,this._niceExtent=o}},niceExtent:o.niceExtent});return e.each([D,"normalize"],function(t){d[be][t]=function(e){return e=h(e)/h(u),a[t].call(this,e)}}),d[de]=function(){return new d},d}),e("echarts/model/Global",[Ce,Ae,"../util/model","./Model","./Component","./globalDefault"],function(t){function e(t,e){for(var i in e)y.hasClass(i)||("object"==typeof e[i]?t[i]=t[i]?c.merge(t[i],e[i],!1):c.clone(e[i]):null==t[i]&&(t[i]=e[i]))}function i(t){t=t,this[z]={},this[z][_]=1,this._componentsMap={},this._seriesIndices=null,e(t,this._theme[z]),c.merge(t,x,!1),this.mergeOption(t)}function n(t,e){c[j](e)||(e=e?[e]:[]);var i={};return d(e,function(e){i[e]=(t[e]||[]).slice()}),i}function r(t,e){var i={};d(e,function(t){var e=t.exist;e&&(i[e.id]=t)}),d(e,function(e){var n=e[z];if(c.assert(!n||null==n.id||!i[n.id]||i[n.id]===e,"id duplicates: "+(n&&n.id)),n&&null!=n.id&&(i[n.id]=e),m(n)){var r=a(t,n,e.exist);e.keyInfo={mainType:t,subType:r}}}),d(e,function(t){var e=t.exist,n=t[z],r=t.keyInfo;if(m(n)){if(r.name=null!=n.name?n.name+"":e?e.name:"\x00-",e)r.id=e.id;else if(null!=n.id)r.id=n.id+"";else{var a=0;do r.id="\x00"+r.name+"\x00"+a++;while(i[r.id])}i[r.id]=t}})}function a(t,e,i){var n=e.type?e.type:i?i.subType:y.determineSubType(t,e);return n}function o(t){return p(t,function(t){return t.componentIndex})||[]}function s(t,e){return e.hasOwnProperty("subType")?f(t,function(t){return t.subType===e.subType}):t}function l(t){if(!t._seriesIndices)throw new Error("Series has not been initialized yet.")}var c=t(Ae),u=t("../util/model"),h=t("./Model"),d=c.each,f=c[Se],p=c.map,g=c[j],v=c[X],m=c[ue],y=t("./Component"),x=t("./globalDefault"),_="\x00_ec_inner",b=h[le]({constructor:b,init:function(t,e,i,n){i=i||{},this[z]=null,this._theme=new h(i),this._optionManager=n},setOption:function(t,e){c.assert(!(_ in t),"please use chart.getOption()"),this._optionManager.setOption(t,e),this.resetOption()},resetOption:function(t){var e=!1,n=this._optionManager;if(!t||"recreate"===t){var r=n.mountOption("recreate"===t);this[z]&&"recreate"!==t?(this.restoreData(),this.mergeOption(r)):i.call(this,r),e=!0}if(("timeline"===t||"media"===t)&&this.restoreData(),!t||"recreate"===t||"timeline"===t){var a=n.getTimelineOption(this);a&&(this.mergeOption(a),e=!0)}if(!t||"recreate"===t||"media"===t){var o=n.getMediaOption(this,this._api);o[oe]&&d(o,function(t){this.mergeOption(t,e=!0)},this)}return e},mergeOption:function(t){function e(e,s){var l=u.normalizeToArray(t[e]),h=u.mappingToExists(a[e],l);r(e,h);var f=n(a,s);i[e]=[],a[e]=[],d(h,function(t,n){var r=t.exist,o=t[z];if(c.assert(m(o)||r,"Empty component definition"),o){var s=y.getClass(e,t.keyInfo.subType,!0);r&&r instanceof s?(r.mergeOption(o,this),r.optionUpdated(this)):(r=new s(o,this,this,c[le]({dependentModels:f,componentIndex:n},t.keyInfo)),r.optionUpdated(this))}else r.mergeOption({},this),r.optionUpdated(this);a[e][n]=r,i[e][n]=r[z]},this),e===re&&(this._seriesIndices=o(a[re]))}var i=this[z],a=this._componentsMap,s=[];d(t,function(t,e){null!=t&&(y.hasClass(e)?s.push(e):i[e]=null==i[e]?c.clone(t):c.merge(i[e],t,!0))}),y.topologicalTravel(s,y.getAllClassMainTypes(),e,this)},getOption:function(){var t=c.clone(this[z]);return d(t,function(e,i){if(y.hasClass(i)){for(var e=u.normalizeToArray(e),n=e[oe]-1;n>=0;n--)u.isIdInner(e[n])&&e[ne](n,1);t[i]=e}}),delete t[_],t},getTheme:function(){return this._theme},getComponent:function(t,e){var i=this._componentsMap[t];return i?i[e||0]:void 0},queryComponents:function(t){var e=t.mainType;if(!e)return[];var i=t.index,n=t.id,r=t.name,a=this._componentsMap[e];if(!a||!a[oe])return[];var o;if(null!=i)g(i)||(i=[i]),o=f(p(i,function(t){return a[t]}),function(t){return!!t});else if(null!=n){var l=g(n);o=f(a,function(t){return l&&v(n,t.id)>=0||!l&&t.id===n})}else if(null!=r){var c=g(r);o=f(a,function(t){return c&&v(r,t.name)>=0||!c&&t.name===r})}return s(o,t)},findComponents:function(t){function e(t){var e=r+"Index",i=r+"Id",n=r+"Name";return t&&(t.hasOwnProperty(e)||t.hasOwnProperty(i)||t.hasOwnProperty(n))?{mainType:r,index:t[e],id:t[i],name:t[n]}:null}function i(e){return t[Se]?f(e,t[Se]):e}var n=t.query,r=t.mainType,a=e(n),o=a?this.queryComponents(a):this._componentsMap[r];return i(s(o,t))},eachComponent:function(t,e,i){var n=this._componentsMap;if(typeof t===Z)i=e,e=t,d(n,function(t,n){d(t,function(t,r){e.call(i,n,t,r)})});else if(c.isString(t))d(n[t],e,i);else if(m(t)){var r=this.findComponents(t);d(r,e,i)}},getSeriesByName:function(t){var e=this._componentsMap[re];return f(e,function(e){return e.name===t})},getSeriesByIndex:function(t){return this._componentsMap[re][t]},getSeriesByType:function(t){var e=this._componentsMap[re];return f(e,function(e){return e.subType===t})},getSeries:function(){return this._componentsMap[re].slice()},eachSeries:function(t,e){l(this),d(this._seriesIndices,function(i){var n=this._componentsMap[re][i];t.call(e,n,i)},this)},eachRawSeries:function(t,e){d(this._componentsMap[re],t,e)},eachSeriesByType:function(t,e,i){l(this),d(this._seriesIndices,function(n){var r=this._componentsMap[re][n];r.subType===t&&e.call(i,r,n)},this)},eachRawSeriesByType:function(t,e,i){return d(this.getSeriesByType(t),e,i)},isSeriesFiltered:function(t){return l(this),c[X](this._seriesIndices,t.componentIndex)<0},filterSeries:function(t,e){l(this);var i=f(this._componentsMap[re],t,e);this._seriesIndices=o(i)},restoreData:function(){var t=this._componentsMap;this._seriesIndices=o(t[re]);var e=[];d(t,function(t,i){e.push(i)}),y.topologicalTravel(e,y.getAllClassMainTypes(),function(e){d(t[e],function(t){t.restoreData()})})}});return b}),e("echarts/ExtensionAPI",[Ce,Ae],function(t){function e(t){i.each(n,function(e){this[e]=i.bind(t[e],t)},this)}var i=t(Ae),n=["getDom","getZr",me,ve,"dispatchAction","on","off","getDataURL","getConnectedDataURL",ye,"getOption"];return e}),e("echarts/CoordinateSystem",[Ce],function(){function t(){this._coordinateSystems=[]}var e={};return t[be]={constructor:t,create:function(t,i){var n=[];for(var r in e){var a=e[r][de](t,i);a&&(n=n.concat(a))}this._coordinateSystems=n},update:function(t,e){for(var i=this._coordinateSystems,n=0;n<i[oe];n++)i[n][he]&&i[n][he](t,e)}},t.register=function(t,i){e[t]=i},t.get=function(t){return e[t]},t}),e("echarts/model/OptionManager",[Ce,Ae,"../util/model","./Component"],function(t){function e(t){this._api=t,this._timelineOptions=[],this._mediaList=[],this._mediaDefault,this._currentMediaIndices=[],this._optionBackup,this._newBaseOption}function i(t,e){var i,n,r=[],a=[],o=t.timeline;if(t.baseOption&&(n=t.baseOption),(o||t.options)&&(n=n||{},r=(t.options||[]).slice()),t.media){n=n||{};var l=t.media;u(l,function(t){t&&t[z]&&(t.query?a.push(t):i||(i=t))})}return n||(n=t),n.timeline||(n.timeline=o),u([n].concat(r).concat(s.map(a,function(t){return t[z]})),function(t){u(e,function(e){e(t)})}),{baseOption:n,timelineOptions:r,mediaDefault:i,mediaList:a}}function n(t,e,i){var n={width:e,height:i,aspectratio:e/i},a=!0;return s.each(t,function(t,e){var i=e.match(p);if(i&&i[1]&&i[2]){var o=i[1],s=i[2][we]();r(n[s],t,o)||(a=!1)}}),a}function r(t,e,i){return"min"===i?t>=e:"max"===i?e>=t:t===e}function a(t,e){return t.join(",")===e.join(",")}function o(t,e){e=e||{},u(e,function(e,i){if(null!=e){var n=t[i];if(c.hasClass(i)){e=l.normalizeToArray(e),n=l.normalizeToArray(n);var r=l.mappingToExists(n,e);t[i]=d(r,function(t){return t[z]&&t.exist?f(t.exist,t[z],!0):t.exist||t[z]})}else t[i]=f(n,e,!0)}})}var s=t(Ae),l=t("../util/model"),c=t("./Component"),u=s.each,h=s.clone,d=s.map,f=s.merge,p=/^(min|max)?(.+)$/;return e[be]={constructor:e,setOption:function(t,e){t=h(t,!0);var n=this._optionBackup,r=i.call(this,t,e);this._newBaseOption=r.baseOption,n?(o(n.baseOption,r.baseOption),r.timelineOptions[oe]&&(n.timelineOptions=r.timelineOptions),r.mediaList[oe]&&(n.mediaList=r.mediaList),r.mediaDefault&&(n.mediaDefault=r.mediaDefault)):this._optionBackup=r},mountOption:function(t){var e=this._optionBackup;return this._timelineOptions=d(e.timelineOptions,h),this._mediaList=d(e.mediaList,h),this._mediaDefault=h(e.mediaDefault),this._currentMediaIndices=[],h(t?e.baseOption:this._newBaseOption)},getTimelineOption:function(t){var e,i=this._timelineOptions;if(i[oe]){var n=t[P]("timeline");n&&(e=h(i[n.getCurrentIndex()],!0))}return e},getMediaOption:function(){var t=this._api[me](),e=this._api[ve](),i=this._mediaList,r=this._mediaDefault,o=[],s=[];if(!i[oe]&&!r)return s;for(var l=0,c=i[oe];c>l;l++)n(i[l].query,t,e)&&o.push(l);return!o[oe]&&r&&(o=[-1]),o[oe]&&!a(o,this._currentMediaIndices)&&(s=d(o,function(t){return h(-1===t?r[z]:i[t][z])})),this._currentMediaIndices=o,s}},e}),e("echarts/model/Component",[Ce,"./Model",Ae,"../util/component","../util/clazz","../util/layout","./mixin/boxLayout"],function(t){function e(t){var e=[];return n.each(l.getClassesByMainType(t),function(t){r.apply(e,t[be].dependencies||[])}),n.map(e,function(t){return o.parseClassType(t).main})}var i=t("./Model"),n=t(Ae),r=Array[be].push,a=t("../util/component"),o=t("../util/clazz"),s=t("../util/layout"),l=i[le]({type:"component",id:"",name:"",mainType:"",subType:"",componentIndex:0,defaultOption:null,ecModel:null,dependentModels:[],uid:null,layoutMode:null,init:function(){this.mergeDefaultAndTheme(this[z],this[L])},mergeDefaultAndTheme:function(t,e){var i=this.layoutMode,r=i?s.getLayoutParams(t):{},a=e.getTheme();n.merge(t,a.get(this.mainType)),n.merge(t,this.getDefaultOption()),i&&s.mergeLayoutParam(t,r,i)},mergeOption:function(t){n.merge(this[z],t,!0);var e=this.layoutMode;e&&s.mergeLayoutParam(this[z],t,e)},optionUpdated:function(){},getDefaultOption:function(){if(!this.hasOwnProperty("__defaultOption")){for(var t=[],e=this.constructor;e;){var i=e[be].defaultOption;i&&t.push(i),e=e.superClass}for(var r={},a=t[oe]-1;a>=0;a--)r=n.merge(r,t[a],!0);this.__defaultOption=r}return this.__defaultOption}});return o.enableClassExtend(l,function(t,e,i,r){n[le](this,r),this.uid=a.getUID("componentModel")}),o.enableClassManagement(l,{registerWhenExtend:!0}),a.enableSubTypeDefaulter(l),a.enableTopologicalTravel(l,e),n.mixin(l,t("./mixin/boxLayout")),l}),e("echarts/model/Series",[Ce,Ae,"../util/format","../util/model","./Component"],function(t){var e=t(Ae),i=t("../util/format"),n=t("../util/model"),r=t("./Component"),a=i.encodeHTML,o=i.addCommas,s=r[le]({type:"series.__base__",seriesIndex:0,coordinateSystem:null,defaultOption:null,legendDataProvider:null,init:function(t,e,i){this[$]=this.componentIndex,this.mergeDefaultAndTheme(t,i),this._dataBeforeProcessed=this.getInitialData(t,i),this._data=this._dataBeforeProcessed.cloneShallow()},mergeDefaultAndTheme:function(t,i){e.merge(t,i.getTheme().get(this.subType)),e.merge(t,this.getDefaultOption()),n.defaultEmphasis(t.label,n.LABEL_OPTIONS),this.fillDataTextStyle(t.data)},mergeOption:function(t,i){t=e.merge(this[z],t,!0),this.fillDataTextStyle(t.data);var n=this.getInitialData(t,i);n&&(this._data=n,this._dataBeforeProcessed=n.cloneShallow())},fillDataTextStyle:function(t){if(t)for(var e=0;e<t[oe];e++)t[e]&&t[e].label&&n.defaultEmphasis(t[e].label,n.LABEL_OPTIONS)},getInitialData:function(){},getData:function(t){return null==t?this._data:this._data.getLinkedData(t)},setData:function(t){this._data=t},getRawData:function(){return this._dataBeforeProcessed},coordDimToDataDim:function(t){return[t]},dataDimToCoordDim:function(t){return t},getBaseAxis:function(){var t=this[H];return t&&t.getBaseAxis&&t.getBaseAxis()},formatTooltip:function(t,i){var n=this._data,r=this.getRawValue(t),s=e[j](r)?e.map(r,o).join(", "):o(r),l=n[T](t),c=n[C](t,"color"),u='<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:'+c+'"></span>',h=this.name;return"\x00-"===h&&(h=""),i?u+a(this.name)+" : "+s:(h&&a(h)+"<br />")+u+(l?a(l)+" : "+s:s)},restoreData:function(){this._data=this._dataBeforeProcessed.cloneShallow()},getAxisTooltipDataIndex:null});
+return e.mixin(s,n.dataFormatMixin),s}),e("echarts/view/Component",[Ce,"zrender/container/Group","../util/component","../util/clazz"],function(t){var e=t("zrender/container/Group"),i=t("../util/component"),n=t("../util/clazz"),r=function(){this.group=new e,this.uid=i.getUID("viewComponent")};r[be]={constructor:r,init:function(){},render:function(){},dispose:function(){}};var a=r[be];return a.updateView=a.updateLayout=a.updateVisual=function(){},n.enableClassExtend(r),n.enableClassManagement(r,{registerWhenExtend:!0}),r}),e("echarts/view/Chart",[Ce,"zrender/container/Group","../util/component","../util/clazz"],function(t){function e(){this.group=new r,this.uid=a.getUID("viewChart")}function i(t,e){if(t&&(t[ae](e),"group"===t.type))for(var n=0;n<t.childCount();n++)i(t.childAt(n),e)}function n(t,e,n){if(null!=e[K]){var r=t[S](e[K]);i(r,n)}else if(e.name){var a=t.indexOfName(e.name),r=t[S](a);i(r,n)}else t.eachItemGraphicEl(function(t){i(t,n)})}var r=t("zrender/container/Group"),a=t("../util/component"),o=t("../util/clazz");e[be]={type:"chart",init:function(){},render:function(){},highlight:function(t,e,i,r){n(t[ie](),r,A)},downplay:function(t,e,i,r){n(t[ie](),r,M)},remove:function(){this.group[q]()},dispose:function(){}};var s=e[be];return s.updateView=s.updateLayout=s.updateVisual=function(t,e,i,n){this.render(t,e,i,n)},o.enableClassExtend(e),o.enableClassManagement(e,{registerWhenExtend:!0}),e}),e("echarts/util/graphic",[Ce,Ae,"zrender/tool/path","zrender/graphic/Path","zrender/tool/color","zrender/core/matrix","zrender/core/vector","zrender/graphic/Gradient","zrender/container/Group","zrender/graphic/Image","zrender/graphic/Text","zrender/graphic/shape/Circle","zrender/graphic/shape/Sector","zrender/graphic/shape/Ring","zrender/graphic/shape/Polygon","zrender/graphic/shape/Polyline","zrender/graphic/shape/Rect","zrender/graphic/shape/Line","zrender/graphic/shape/BezierCurve","zrender/graphic/shape/Arc","zrender/graphic/CompoundPath","zrender/graphic/LinearGradient","zrender/graphic/RadialGradient","zrender/core/BoundingRect"],function(t){function e(t){return null!=t&&"none"!=t}function i(t){return t instanceof k?t:L.lift(t,-.1)}function n(t){if(t.__hoverStlDirty){var n=t.style[x],r=t.style.fill,a=t.__hoverStl;a.fill=a.fill||(e(r)?i(r):null),a[x]=a[x]||(e(n)?i(n):null);var o={};for(var s in a)a.hasOwnProperty(s)&&(o[s]=t.style[s]);t.__normalStl=o,t.__hoverStlDirty=!1}}function r(t){t.__isHover||(n(t),t.setStyle(t.__hoverStl),t.z2+=1,t.__isHover=!0)}function a(t){if(t.__isHover){var e=t.__normalStl;e&&t.setStyle(e),t.z2-=1,t.__isHover=!1}}function o(t){"group"===t.type?t.traverse(function(t){"group"!==t.type&&r(t)}):r(t)}function s(t){"group"===t.type?t.traverse(function(t){"group"!==t.type&&a(t)}):a(t)}function l(t,e){t.__hoverStl=t.hoverStyle||e||{},t.__hoverStlDirty=!0,t.__isHover&&n(t)}function c(){!this.__isEmphasis&&o(this)}function u(){!this.__isEmphasis&&s(this)}function h(){this.__isEmphasis=!0,o(this)}function d(){this.__isEmphasis=!1,s(this)}function f(t,e,i,n,r,a){typeof r===Z&&(a=r,r=null);var o=t?"Update":"",s=n&&n[y]("animationDuration"+o),l=n&&n[y]("animationEasing"+o),c=n&&n[y]("animationDelay"+o);typeof c===Z&&(c=c(r)),n&&n[y](v)?e.animateTo(i,s,c||0,l,a):(e.attr(i),a&&a())}var p=t(Ae),S=t("zrender/tool/path"),C=Math.round,T=t("zrender/graphic/Path"),L=t("zrender/tool/color"),P=t("zrender/core/matrix"),z=t("zrender/core/vector"),k=t("zrender/graphic/Gradient"),I={};return I.Group=t("zrender/container/Group"),I.Image=t("zrender/graphic/Image"),I.Text=t("zrender/graphic/Text"),I.Circle=t("zrender/graphic/shape/Circle"),I[w]=t("zrender/graphic/shape/Sector"),I.Ring=t("zrender/graphic/shape/Ring"),I.Polygon=t("zrender/graphic/shape/Polygon"),I.Polyline=t("zrender/graphic/shape/Polyline"),I.Rect=t("zrender/graphic/shape/Rect"),I.Line=t("zrender/graphic/shape/Line"),I.BezierCurve=t("zrender/graphic/shape/BezierCurve"),I.Arc=t("zrender/graphic/shape/Arc"),I.CompoundPath=t("zrender/graphic/CompoundPath"),I.LinearGradient=t("zrender/graphic/LinearGradient"),I.RadialGradient=t("zrender/graphic/RadialGradient"),I.BoundingRect=t("zrender/core/BoundingRect"),I.extendShape=function(t){return T[le](t)},I.extendPath=function(t,e){return S.extendFromString(t,e)},I.makePath=function(t,e,i,n){var r=S.createFromString(t,e),a=r[N]();if(i){var o=a.width/a[fe];if(n===B){var s,l=i[fe]*o;l<=i.width?s=i[fe]:(l=i.width,s=l/o);var c=i.x+i.width/2,u=i.y+i[fe]/2;i.x=c-l/2,i.y=u-s/2,i.width=l,i[fe]=s}this.resizePath(r,i)}return r},I.mergePath=S.mergePath,I.resizePath=function(t,e){if(t[b]){var i=t[N](),n=i.calculateTransform(e);t[b](n)}},I.subPixelOptimizeLine=function(t){var e=I.subPixelOptimize,i=t.shape,n=t.style[_];return C(2*i.x1)===C(2*i.x2)&&(i.x1=i.x2=e(i.x1,n,!0)),C(2*i.y1)===C(2*i.y2)&&(i.y1=i.y2=e(i.y1,n,!0)),t},I.subPixelOptimizeRect=function(t){var e=I.subPixelOptimize,i=t.shape,n=t.style[_],r=i.x,a=i.y,o=i.width,s=i[fe];return i.x=e(i.x,n,!0),i.y=e(i.y,n,!0),i.width=Math.max(e(r+o,n,!1)-i.x,0===o?0:1),i[fe]=Math.max(e(a+s,n,!1)-i.y,0===s?0:1),t},I.subPixelOptimize=function(t,e,i){var n=C(2*t);return(n+C(e))%2===0?n/2:(n+(i?1:-1))/2},I.setHoverStyle=function(t,e){"group"===t.type?t.traverse(function(t){"group"!==t.type&&l(t,e)}):l(t,e),t.on(ee,c).on(te,u),t.on(A,h).on(M,d)},I.setText=function(t,e,i){var n=e[y](R)||m,r=n[X](m)>=0?"white":i,a=e[ye](G);p[le](t,{textDistance:e[y]("distance")||5,textFont:a[V](),textPosition:n,textFill:a.getTextColor()||r})},I[g]=p.curry(f,!0),I.initProps=p.curry(f,!1),I.getTransform=function(t,e){for(var i=P.identity([]);t&&t!==e;)P.mul(i,t.getLocalTransform(),i),t=t.parent;return i},I[b]=function(t,e,i){return i&&(e=P.invert([],e)),z[b]([],t,e)},I.transformDirection=function(t,e,i){var n=0===e[4]||0===e[5]||0===e[0]?1:Math.abs(2*e[4]/e[0]),r=0===e[4]||0===e[5]||0===e[2]?1:Math.abs(2*e[4]/e[2]),a=["left"===t?-n:"right"===t?n:0,"top"===t?-r:t===pe?r:0];return a=I[b](a,e,i),Math.abs(a[0])>Math.abs(a[1])?a[0]>0?"right":"left":a[1]>0?pe:"top"},I}),e("zrender/tool/color",[Ce],function(){function t(t){return t=Math.round(t),0>t?0:t>255?255:t}function e(t){return t=Math.round(t),0>t?0:t>360?360:t}function i(t){return 0>t?0:t>1?1:t}function n(e){return t(e[oe]&&"%"===e.charAt(e[oe]-1)?parseFloat(e)/100*255:parseInt(e,10))}function r(t){return i(t[oe]&&"%"===t.charAt(t[oe]-1)?parseFloat(t)/100:parseFloat(t))}function a(t,e,i){return 0>i?i+=1:i>1&&(i-=1),1>6*i?t+(e-t)*i*6:1>2*i?e:2>3*i?t+(e-t)*(2/3-i)*6:t}function o(t,e,i){return t+(e-t)*i}function s(t){if(t){t+="";var e=t[U](/ /g,"")[we]();if(e in m)return m[e].slice();if("#"!==e.charAt(0)){var i=e[X]("("),a=e[X](")");if(-1!==i&&a+1===e[oe]){var o=e.substr(0,i),s=e.substr(i+1,a-(i+1)).split(","),c=1;switch(o){case"rgba":if(4!==s[oe])return;c=r(s.pop());case"rgb":if(3!==s[oe])return;return[n(s[0]),n(s[1]),n(s[2]),c];case"hsla":if(4!==s[oe])return;return s[3]=r(s[3]),l(s);case"hsl":if(3!==s[oe])return;return l(s);default:return}}}else{if(4===e[oe]){var u=parseInt(e.substr(1),16);if(!(u>=0&&4095>=u))return;return[(3840&u)>>4|(3840&u)>>8,240&u|(240&u)>>4,15&u|(15&u)<<4,1]}if(7===e[oe]){var u=parseInt(e.substr(1),16);if(!(u>=0&&16777215>=u))return;return[(16711680&u)>>16,(65280&u)>>8,255&u,1]}}}}function l(e){var i=(parseFloat(e[0])%360+360)%360/360,n=r(e[1]),o=r(e[2]),s=.5>=o?o*(n+1):o+n-o*n,l=2*o-s,c=[t(255*a(l,s,i+1/3)),t(255*a(l,s,i)),t(255*a(l,s,i-1/3))];return 4===e[oe]&&(c[3]=e[3]),c}function c(t){if(t){var e,i,n=t[0]/255,r=t[1]/255,a=t[2]/255,o=Math.min(n,r,a),s=Math.max(n,r,a),l=s-o,c=(s+o)/2;if(0===l)e=0,i=0;else{i=.5>c?l/(s+o):l/(2-s-o);var u=((s-n)/6+l/2)/l,h=((s-r)/6+l/2)/l,d=((s-a)/6+l/2)/l;n===s?e=d-h:r===s?e=1/3+u-d:a===s&&(e=2/3+h-u),0>e&&(e+=1),e>1&&(e-=1)}var f=[360*e,i,c];return null!=t[3]&&f.push(t[3]),f}}function u(t,e){var i=s(t);if(i){for(var n=0;3>n;n++)i[n]=0>e?i[n]*(1-e)|0:(255-i[n])*e+i[n]|0;return v(i,4===i[oe]?"rgba":"rgb")}}function h(t){var e=s(t);return e?((1<<24)+(e[0]<<16)+(e[1]<<8)+ +e[2]).toString(16).slice(1):void 0}function d(e,i,n){if(i&&i[oe]&&e>=0&&1>=e){n=n||[0,0,0,0];var r=e*(i[oe]-1),a=Math.floor(r),s=Math.ceil(r),l=i[a],c=i[s],u=r-a;return n[0]=t(o(l[0],c[0],u)),n[1]=t(o(l[1],c[1],u)),n[2]=t(o(l[2],c[2],u)),n[3]=t(o(l[3],c[3],u)),n}}function f(e,n,r){if(n&&n[oe]&&e>=0&&1>=e){var a=e*(n[oe]-1),l=Math.floor(a),c=Math.ceil(a),u=s(n[l]),h=s(n[c]),d=a-l,f=v([t(o(u[0],h[0],d)),t(o(u[1],h[1],d)),t(o(u[2],h[2],d)),i(o(u[3],h[3],d))],"rgba");return r?{color:f,leftIndex:l,rightIndex:c,value:a}:f}}function p(t,i,n,a){return t=s(t),t?(t=c(t),null!=i&&(t[0]=e(i)),null!=n&&(t[1]=r(n)),null!=a&&(t[2]=r(a)),v(l(t),"rgba")):void 0}function g(t,e){return t=s(t),t&&null!=e?(t[3]=i(e),v(t,"rgba")):void 0}function v(t,e){return("rgb"===e||"hsv"===e||"hsl"===e)&&(t=t.slice(0,3)),e+"("+t.join(",")+")"}var m={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]};return{parse:s,lift:u,toHex:h,fastMapToColor:d,mapToColor:f,modifyHSL:p,modifyAlpha:g,stringify:v}}),e("zrender/core/env",[],function(){function t(t){var e={},i={},n=t.match(/Web[kK]it[\/]{0,1}([\d.]+)/),r=t.match(/(Android);?[\s\/]+([\d.]+)?/),a=t.match(/(iPad).*OS\s([\d_]+)/),o=t.match(/(iPod)(.*OS\s([\d_]+))?/),s=!a&&t.match(/(iPhone\sOS)\s([\d_]+)/),l=t.match(/(webOS|hpwOS)[\s\/]([\d.]+)/),c=l&&t.match(/TouchPad/),u=t.match(/Kindle\/([\d.]+)/),h=t.match(/Silk\/([\d._]+)/),d=t.match(/(BlackBerry).*Version\/([\d.]+)/),p=t.match(/(BB10).*Version\/([\d.]+)/),g=t.match(/(RIM\sTablet\sOS)\s([\d.]+)/),v=t.match(/PlayBook/),m=t.match(/Chrome\/([\d.]+)/)||t.match(/CriOS\/([\d.]+)/),y=t.match(/Firefox\/([\d.]+)/),x=n&&t.match(/Mobile\//)&&!m,_=t.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/)&&!m,b=t.match(/MSIE\s([\d.]+)/)||t.match(/Trident\/.+?rv:(([\d.]+))/),w=t.match(/Edge\/([\d.]+)/);return(i.webkit=!!n)&&(i.version=n[1]),r&&(e.android=!0,e.version=r[2]),s&&!o&&(e.ios=e.iphone=!0,e.version=s[2][U](/_/g,".")),a&&(e.ios=e.ipad=!0,e.version=a[2][U](/_/g,".")),o&&(e.ios=e.ipod=!0,e.version=o[3]?o[3][U](/_/g,"."):null),l&&(e.webos=!0,e.version=l[2]),c&&(e.touchpad=!0),d&&(e.blackberry=!0,e.version=d[2]),p&&(e.bb10=!0,e.version=p[2]),g&&(e.rimtabletos=!0,e.version=g[2]),v&&(i.playbook=!0),u&&(e.kindle=!0,e.version=u[1]),h&&(i.silk=!0,i.version=h[1]),!h&&e.android&&t.match(/Kindle Fire/)&&(i.silk=!0),m&&(i.chrome=!0,i.version=m[1]),y&&(i.firefox=!0,i.version=y[1]),b&&(i.ie=!0,i.version=b[1]),x&&(t.match(/Safari/)||e.ios)&&(i.safari=!0),_&&(i.webview=!0),b&&(i.ie=!0,i.version=b[1]),w&&(i.edge=!0,i.version=w[1]),e.tablet=!!(a||v||r&&!t.match(/Mobile/)||y&&t.match(/Tablet/)||b&&!t.match(/Phone/)&&t.match(/Touch/)),e.phone=!(e.tablet||e.ipod||!(r||s||l||d||p||m&&t.match(/Android/)||m&&t.match(/CriOS\/([\d.]+)/)||y&&t.match(/Mobile/)||b&&t.match(/Touch/))),{browser:i,os:e,node:!1,canvasSupported:document[f]("canvas").getContext?!0:!1,touchEventsSupported:"ontouchstart"in window&&!i.ie&&!i.edge,pointerEventsSupported:"onpointerdown"in window&&(i.edge||i.ie&&i.version>=10)}}var e={};return e=typeof navigator===p?{browser:{},os:{},node:!0,canvasSupported:!0}:t(navigator.userAgent)}),e(Ae,[Ce,"../graphic/Gradient"],function(t){function e(t){if("object"==typeof t&&null!==t){var i=t;if(t instanceof Array){i=[];for(var n=0,r=t[oe];r>n;n++)i[n]=e(t[n])}else if(!M(t)&&!A(t)){i={};for(var a in t)t.hasOwnProperty(a)&&(i[a]=e(t[a]))}return i}return t}function i(t,n,r){if(!S(n)||!S(t))return r?e(n):t;for(var a in n)if(n.hasOwnProperty(a)){var o=t[a],s=n[a];!S(s)||!S(o)||_(s)||_(o)||A(s)||A(o)||M(s)||M(o)?!r&&a in t||(t[a]=e(n[a],!0)):i(o,s,r)}return t}function n(t,e){for(var n=t[0],r=1,a=t[oe];a>r;r++)n=i(n,t[r],e);return n}function r(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function a(t,e,i){for(var n in e)e.hasOwnProperty(n)&&(i?null!=e[n]:null==t[n])&&(t[n]=e[n]);return t}function o(){return document[f]("canvas")}function s(){return P||(P=V.createCanvas().getContext("2d")),P}function l(t,e){if(t){if(t[X])return t[X](e);for(var i=0,n=t[oe];n>i;i++)if(t[i]===e)return i}return-1}function c(t,e){function i(){}var n=t[be];i[be]=e[be],t[be]=new i;for(var r in n)t[be][r]=n[r];t[be].constructor=t,t.superClass=e}function u(t,e,i){t=be in t?t[be]:t,e=be in e?e[be]:e,a(t,e,i)}function h(t){return t?typeof t==_e?!1:"number"==typeof t[oe]:void 0}function d(t,e,i){if(t&&e)if(t.forEach&&t.forEach===O)t.forEach(e,i);else if(t[oe]===+t[oe])for(var n=0,r=t[oe];r>n;n++)e.call(i,t[n],n,t);else for(var a in t)t.hasOwnProperty(a)&&e.call(i,t[a],a,t)}function p(t,e,i){if(t&&e){if(t.map&&t.map===E)return t.map(e,i);for(var n=[],r=0,a=t[oe];a>r;r++)n.push(e.call(i,t[r],r,t));return n}}function g(t,e,i,n){if(t&&e){if(t.reduce&&t.reduce===N)return t.reduce(e,i,n);for(var r=0,a=t[oe];a>r;r++)i=e.call(n,i,t[r],r,t);return i}}function v(t,e,i){if(t&&e){if(t[Se]&&t[Se]===R)return t[Se](e,i);for(var n=[],r=0,a=t[oe];a>r;r++)e.call(i,t[r],r,t)&&n.push(t[r]);return n}}function m(t,e,i){if(t&&e)for(var n=0,r=t[oe];r>n;n++)if(e.call(i,t[n],n,t))return t[n]}function y(t,e){var i=B.call(arguments,2);return function(){return t.apply(e,i.concat(B.call(arguments)))}}function x(t){var e=B.call(arguments,1);return function(){return t.apply(this,e.concat(B.call(arguments)))}}function _(t){return"[object Array]"===I.call(t)}function b(t){return typeof t===Z}function w(t){return"[object String]"===I.call(t)}function S(t){var e=typeof t;return e===Z||!!t&&"object"==e}function M(t){return!!k[I.call(t)]||t instanceof z}function A(t){return t&&1===t.nodeType&&typeof t.nodeName==_e}function C(){for(var t=0,e=arguments[oe];e>t;t++)if(null!=arguments[t])return arguments[t]}function T(){return Function.call.apply(B,arguments)}function L(t,e){if(!t)throw new Error(e)}var P,z=t("../graphic/Gradient"),k={"[object Function]":1,"[object RegExp]":1,"[object Date]":1,"[object Error]":1,"[object CanvasGradient]":1},I=Object[be].toString,D=Array[be],O=D.forEach,R=D[Se],B=D.slice,E=D.map,N=D.reduce,V={inherits:c,mixin:u,clone:e,merge:i,mergeAll:n,extend:r,defaults:a,getContext:s,createCanvas:o,indexOf:l,slice:T,find:m,isArrayLike:h,each:d,map:p,reduce:g,filter:v,bind:y,curry:x,isArray:_,isString:w,isObject:S,isFunction:b,isBuildInObject:M,isDom:A,retrieve:C,assert:L,noop:function(){}};return V}),e("zrender/zrender",[Ce,"./core/guid","./core/env","./Handler","./Storage","./animation/Animation","./Painter"],function(t){function e(t){delete c[t]}var i=t("./core/guid"),n=t("./core/env"),r=t("./Handler"),a=t("./Storage"),o=t("./animation/Animation"),s=!n.canvasSupported,l={canvas:t("./Painter")},c={},u={};u.version="0.0.0",u.init=function(t,e){var n=new h(i(),t,e);return c[n.id]=n,n},u.dispose=function(t){if(t)t.dispose();else{for(var e in c)c[e].dispose();c={}}return u},u.getInstance=function(t){return c[t]},u.registerPainter=function(t,e){l[t]=e};var h=function(t,e,i){i=i||{},this.dom=e,this.id=t;var c=this,u=new a,h=i.renderer;if(s){if(!l.vml)throw new Error("You need to require 'zrender/vml/vml' to support IE8");h="vml"}else h&&l[h]||(h="canvas");var d=new l[h](e,u,i);this.storage=u,this.painter=d,n.node||(this.handler=new r(d.getViewportRoot(),u,d)),this[v]=new o({stage:{update:function(){c._needsRefresh&&c.refreshImmediately()}}}),this[v].start(),this._needsRefresh;var f=u.delFromMap,p=u.addToMap;u.delFromMap=function(t){var e=u.get(t);f.call(u,t),e&&e.removeSelfFromZr(c)},u.addToMap=function(t){p.call(u,t),t.addSelfToZr(c)}};return h[be]={constructor:h,getId:function(){return this.id},add:function(t){this.storage.addRoot(t),this._needsRefresh=!0},remove:function(t){this.storage.delRoot(t),this._needsRefresh=!0},configLayer:function(t,e){this.painter.configLayer(t,e),this._needsRefresh=!0},refreshImmediately:function(){this._needsRefresh=!1,this.painter.refresh(),this._needsRefresh=!1},refresh:function(){this._needsRefresh=!0},resize:function(){this.painter[xe](),this.handler&&this.handler[xe]()},clearAnimation:function(){this[v].clear()},getWidth:function(){return this.painter[me]()},getHeight:function(){return this.painter[ve]()},pathToImage:function(t,e,n){var r=i();return this.painter.pathToImage(r,t,e,n)},setDefaultCursorStyle:function(t){this.handler.setDefaultCursorStyle(t)},on:function(t,e,i){this.handler&&this.handler.on(t,e,i)},off:function(t,e){this.handler&&this.handler.off(t,e)},trigger:function(t,e){this.handler&&this.handler[ae](t,e)},clear:function(){this.storage.delRoot(),this.painter.clear()},dispose:function(){this[v].stop(),this.clear(),this.storage.dispose(),this.painter.dispose(),this.handler&&this.handler.dispose(),this[v]=this.storage=this.painter=this.handler=null,e(this.id)}},u}),e("zrender/mixin/Eventful",[Ce,d],function(t){var e=Array[be].slice,i=t(d),n=i[X],r=function(){this._$handlers={}};return r[be]={constructor:r,one:function(t,e,i){var r=this._$handlers;return e&&t?(r[t]||(r[t]=[]),n(r[t],t)>=0?this:(r[t].push({h:e,one:!0,ctx:i||this}),this)):this},on:function(t,e,i){var n=this._$handlers;return e&&t?(n[t]||(n[t]=[]),n[t].push({h:e,one:!1,ctx:i||this}),this):this},isSilent:function(t){var e=this._$handlers;return e[t]&&e[t][oe]},off:function(t,e){var i=this._$handlers;if(!t)return this._$handlers={},this;if(e){if(i[t]){for(var n=[],r=0,a=i[t][oe];a>r;r++)i[t][r].h!=e&&n.push(i[t][r]);i[t]=n}i[t]&&0===i[t][oe]&&delete i[t]}else delete i[t];return this},trigger:function(t){if(this._$handlers[t]){var i=arguments,n=i[oe];n>3&&(i=e.call(i,1));for(var r=this._$handlers[t],a=r[oe],o=0;a>o;){switch(n){case 1:r[o].h.call(r[o].ctx);break;case 2:r[o].h.call(r[o].ctx,i[1]);break;case 3:r[o].h.call(r[o].ctx,i[1],i[2]);break;default:r[o].h.apply(r[o].ctx,i)}r[o].one?(r[ne](o,1),a--):o++}}return this},triggerWithContext:function(t){if(this._$handlers[t]){var i=arguments,n=i[oe];n>4&&(i=e.call(i,1,i[oe]-1));for(var r=i[i[oe]-1],a=this._$handlers[t],o=a[oe],s=0;o>s;){switch(n){case 1:a[s].h.call(r);break;case 2:a[s].h.call(r,i[1]);break;case 3:a[s].h.call(r,i[1],i[2]);break;default:a[s].h.apply(r,i)}a[s].one?(a[ne](s,1),o--):s++}}return this}},r}),e("echarts/loading/default",[Ce,"../util/graphic",Ae],function(t){var e=t("../util/graphic"),i=t(Ae),n=Math.PI;return function(t,r){r=r||{},i[se](r,{text:"loading",color:"#c23531",textColor:"#000",maskColor:"rgba(255, 255, 255, 0.8)",zlevel:0});var a=new e.Rect({style:{fill:r.maskColor},zlevel:r[Y],z:1e4}),o=new e.Arc({shape:{startAngle:-n/2,endAngle:-n/2+.1,r:10},style:{stroke:r.color,lineCap:"round",lineWidth:5},zlevel:r[Y],z:10001}),s=new e.Rect({style:{fill:"none",text:r.text,textPosition:"right",textDistance:10,textFill:r.textColor},zlevel:r[Y],z:10001});o.animateShape(!0).when(1e3,{endAngle:3*n/2}).start("circularInOut"),o.animateShape(!0).when(1e3,{startAngle:3*n/2}).delay(300).start("circularInOut");var l=new e.Group;return l.add(o),l.add(s),l.add(a),l[xe]=function(){var e=t[me]()/2,i=t[ve]()/2;o.setShape({cx:e,cy:i});var n=o.shape.r;s.setShape({x:e-n,y:i-n,width:2*n,height:2*n}),a.setShape({x:0,y:0,width:t[me](),height:t[ve]()})},l[xe](),l}}),e("echarts/visual/seriesColor",[Ce,"zrender/graphic/Gradient"],function(t){var e=t("zrender/graphic/Gradient");return function(t,i,n){function r(t){var r=[i,M,"color"],a=n.get("color"),o=t[ie](),s=t.get(r)||a[t[$]%a[oe]];o.setVisual("color",s),n.isSeriesFiltered(t)||(typeof s!==Z||s instanceof e||o.each(function(e){o.setItemVisual(e,"color",s(t[Q](e)))}),o.each(function(t){var e=o[h](t),i=e.get(r,!0);null!=i&&o.setItemVisual(t,"color",i)}))}t?n.eachSeriesByType(t,r):n.eachSeries(r)}}),e("echarts/preprocessor/backwardCompat",[Ce,Ae,"./helper/compatStyle"],function(t){function e(t,e){e=e.split(",");for(var i=t,n=0;n<e[oe]&&(i=i&&i[e[n]],null!=i);n++);return i}function i(t,e,i,n){e=e.split(",");for(var r,a=t,o=0;o<e[oe]-1;o++)r=e[o],null==a[r]&&(a[r]={}),a=a[r];(n||null==a[e[o]])&&(a[e[o]]=i)}function n(t){c(o,function(e){e[0]in t&&!(e[1]in t)&&(t[e[1]]=t[e[0]])})}var r=t(Ae),a=t("./helper/compatStyle"),o=[["x","left"],["y","top"],["x2","right"],["y2",pe]],s=["grid","geo","parallel","legend","toolbox","title","visualMap","dataZoom","timeline"],l=["bar","boxplot","candlestick","chord","effectScatter","funnel","gauge","lines","graph","heatmap","line","map","parallel","pie","radar","sankey","scatter","treemap"],c=r.each;return function(t){c(t[re],function(t){if(r[ue](t)){var o=t.type;if(a(t),("pie"===o||"gauge"===o)&&null!=t.clockWise&&(t.clockwise=t.clockWise),"gauge"===o){var s=e(t,"pointer.color");null!=s&&i(t,"itemStyle.normal.color",s)}for(var c=0;c<l[oe];c++)if(l[c]===t.type){n(t);break}}}),t.dataRange&&(t.visualMap=t.dataRange),c(s,function(e){var i=t[e];i&&(r[j](i)||(i=[i]),c(i,function(t){n(t)}))})}}),e("echarts/util/format",[Ce,Ae,"./number"],function(t){function e(t){return isNaN(t)?"-":(t=(t+"").split("."),t[0][U](/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,"$1,")+(t[oe]>1?"."+t[1]:""))}function i(t){return t[we]()[U](/-(.)/g,function(t,e){return e.toUpperCase()})}function n(t){var e=t[oe];return"number"==typeof t?[t,t,t,t]:2===e?[t[0],t[1],t[0],t[1]]:3===e?[t[0],t[1],t[2],t[1]]:t}function r(t){return String(t)[U](/&/g,"&amp;")[U](/</g,"&lt;")[U](/>/g,"&gt;")[U](/"/g,"&quot;")[U](/'/g,"&#39;")}function a(t,e){return"{"+t+(null==e?"":e)+"}"}function o(t,e){c[j](e)||(e=[e]);var i=e[oe];if(!i)return"";for(var n=e[0].$vars,r=0;r<n[oe];r++){var o=h[r];t=t[U](a(o),a(o,0))}for(var s=0;i>s;s++)for(var l=0;l<n[oe];l++)t=t[U](a(h[l],s),e[s][n[l]]);return t}function s(t,e){("week"===t||"month"===t||"quarter"===t||"half-year"===t||"year"===t)&&(t="MM-dd\nyyyy");var i=u.parseDate(e),n=i.getFullYear(),r=i.getMonth()+1,a=i.getDate(),o=i.getHours(),s=i.getMinutes(),c=i.getSeconds();return t=t[U]("MM",l(r))[we]()[U]("yyyy",n)[U]("yy",n%100)[U]("dd",l(a))[U]("d",a)[U]("hh",l(o))[U]("h",o)[U]("mm",l(s))[U]("m",s)[U]("ss",l(c))[U]("s",c)}function l(t){return 10>t?"0"+t:t}var c=t(Ae),u=t("./number"),h=["a","b","c","d","e","f","g"];return{normalizeCssArray:n,addCommas:e,toCamelCase:i,encodeHTML:r,formatTpl:o,formatTime:s}}),e("echarts/util/number",[Ce],function(){function t(t){return t[U](/^\s+/,"")[U](/\s+$/,"")}var e={},i=1e-4;return e.linearMap=function(t,e,i,n){var r=e[1]-e[0],a=i[1]-i[0];if(0===r)return 0===a?i[0]:(i[0]+i[1])/2;if(n)if(r>0){if(t<=e[0])return i[0];if(t>=e[1])return i[1]}else{if(t>=e[0])return i[0];if(t<=e[1])return i[1]}else{if(t===e[0])return i[0];if(t===e[1])return i[1]}return(t-e[0])/r*a+i[0]},e[u]=function(e,i){switch(e){case B:case E:e="50%";break;case"left":case"top":e="0%";break;case"right":case pe:e="100%"}return typeof e===_e?t(e).match(/%$/)?parseFloat(e)/100*i:parseFloat(e):null==e?0/0:+e},e.round=function(t){return+(+t).toFixed(10)},e.asc=function(t){return t.sort(function(t,e){return t-e}),t},e.getPrecision=function(t){if(isNaN(t))return 0;for(var e=1,i=0;Math.round(t*e)/e!==t;)e*=10,i++;return i},e.getPixelPrecision=function(t,e){var i=Math.log,n=Math.LN10,r=Math.floor(i(t[1]-t[0])/n),a=Math.round(i(Math.abs(e[1]-e[0]))/n);return Math.max(-r+a,0)},e.MAX_SAFE_INTEGER=9007199254740991,e.remRadian=function(t){var e=2*Math.PI;return(t%e+e)%e},e.isRadianAroundZero=function(t){return t>-i&&i>t},e.parseDate=function(t){return t instanceof Date?t:new Date(typeof t===_e?t[U](/-/g,"/"):Math.round(t))},e.quantity=function(t){return Math.pow(10,Math.floor(Math.log(t)/Math.LN10))},e.nice=function(t,i){var n,r=e.quantity(t),a=t/r;return n=i?1.5>a?1:2.5>a?2:4>a?3:7>a?5:10:1>a?1:2>a?2:3>a?3:5>a?5:10,n*r},e}),e("zrender/core/matrix",[],function(){var t=typeof Float32Array===p?Array:Float32Array,e={create:function(){var i=new t(6);return e.identity(i),i},identity:function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t},copy:function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t},mul:function(t,e,i){var n=e[0]*i[0]+e[2]*i[1],r=e[1]*i[0]+e[3]*i[1],a=e[0]*i[2]+e[2]*i[3],o=e[1]*i[2]+e[3]*i[3],s=e[0]*i[4]+e[2]*i[5]+e[4],l=e[1]*i[4]+e[3]*i[5]+e[5];return t[0]=n,t[1]=r,t[2]=a,t[3]=o,t[4]=s,t[5]=l,t},translate:function(t,e,i){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4]+i[0],t[5]=e[5]+i[1],t},rotate:function(t,e,i){var n=e[0],r=e[2],a=e[4],o=e[1],s=e[3],l=e[5],c=Math.sin(i),u=Math.cos(i);return t[0]=n*u+o*c,t[1]=-n*c+o*u,t[2]=r*u+s*c,t[3]=-r*c+u*s,t[4]=u*a+c*l,t[5]=u*l-c*a,t},scale:function(t,e,i){var n=i[0],r=i[1];return t[0]=e[0]*n,t[1]=e[1]*r,t[2]=e[2]*n,t[3]=e[3]*r,t[4]=e[4]*n,t[5]=e[5]*r,t},invert:function(t,e){var i=e[0],n=e[2],r=e[4],a=e[1],o=e[3],s=e[5],l=i*o-a*n;return l?(l=1/l,t[0]=o*l,t[1]=-a*l,t[2]=-n*l,t[3]=i*l,t[4]=(n*s-o*r)*l,t[5]=(a*r-i*s)*l,t):null}};return e}),e("zrender/core/vector",[],function(){var t=typeof Float32Array===p?Array:Float32Array,e={create:function(e,i){var n=new t(2);return n[0]=e||0,n[1]=i||0,n},copy:function(t,e){return t[0]=e[0],t[1]=e[1],t},clone:function(e){var i=new t(2);return i[0]=e[0],i[1]=e[1],i},set:function(t,e,i){return t[0]=e,t[1]=i,t},add:function(t,e,i){return t[0]=e[0]+i[0],t[1]=e[1]+i[1],t},scaleAndAdd:function(t,e,i,n){return t[0]=e[0]+i[0]*n,t[1]=e[1]+i[1]*n,t},sub:function(t,e,i){return t[0]=e[0]-i[0],t[1]=e[1]-i[1],t},len:function(t){return Math.sqrt(this.lenSquare(t))},lenSquare:function(t){return t[0]*t[0]+t[1]*t[1]},mul:function(t,e,i){return t[0]=e[0]*i[0],t[1]=e[1]*i[1],t},div:function(t,e,i){return t[0]=e[0]/i[0],t[1]=e[1]/i[1],t},dot:function(t,e){return t[0]*e[0]+t[1]*e[1]},scale:function(t,e,i){return t[0]=e[0]*i,t[1]=e[1]*i,t},normalize:function(t,i){var n=e.len(i);return 0===n?(t[0]=0,t[1]=0):(t[0]=i[0]/n,t[1]=i[1]/n),t},distance:function(t,e){return Math.sqrt((t[0]-e[0])*(t[0]-e[0])+(t[1]-e[1])*(t[1]-e[1]))},distanceSquare:function(t,e){return(t[0]-e[0])*(t[0]-e[0])+(t[1]-e[1])*(t[1]-e[1])},negate:function(t,e){return t[0]=-e[0],t[1]=-e[1],t},lerp:function(t,e,i,n){return t[0]=e[0]+n*(i[0]-e[0]),t[1]=e[1]+n*(i[1]-e[1]),t},applyTransform:function(t,e,i){var n=e[0],r=e[1];return t[0]=i[0]*n+i[2]*r+i[4],t[1]=i[1]*n+i[3]*r+i[5],t},min:function(t,e,i){return t[0]=Math.min(e[0],i[0]),t[1]=Math.min(e[1],i[1]),t},max:function(t,e,i){return t[0]=Math.max(e[0],i[0]),t[1]=Math.max(e[1],i[1]),t}};return e[oe]=e.len,e.lengthSquare=e.lenSquare,e.dist=e.distance,e.distSquare=e.distanceSquare,e}),e("echarts/coord/cartesian/Grid",[Ce,"exports","../../util/layout","../../coord/axisHelper",Ae,"./Cartesian2D","./Axis2D","./GridModel","../../CoordinateSystem"],function(t){function e(t,e,i){return i[P]("grid",t.get("gridIndex"))===e}function i(t){var e,i=t.model,n=i.getFormattedLabels(),r=1,a=n[oe];a>40&&(r=Math.ceil(a/40));for(var o=0;a>o;o+=r)if(!t.isLabelIgnored(o)){var s=i.getTextRect(n[o]);e?e.union(s):e=s}return e}function n(t,e,i){this._coordsMap={},this._coordsList=[],this._axesMap={},this._axesList=[],this._initCartesian(t,e,i),this._model=t}function r(t,e){var i=t[k](),n=i[0]+i[1];t.toGlobalCoord="x"===t.dim?function(t){return t+e}:function(t){return n-t+e},t.toLocalCoord="x"===t.dim?function(t){return t-e}:function(t){return n-t+e}}var a=t("../../util/layout"),o=t("../../coord/axisHelper"),u=t(Ae),h=t("./Cartesian2D"),d=t("./Axis2D"),f=u.each,p=o.ifAxisCrossZero,g=o.niceScaleExtent;t("./GridModel");var v=n[be];return v.type="grid",v.getRect=function(){return this._rect},v[he]=function(t,e){function i(t){var e=n[t];for(var i in e){var r=e[i];if(r&&(r.type===c||!p(r)))return!0}return!1}var n=this._axesMap;this._updateScale(t,this._model),f(n.x,function(t){g(t,t.model)}),f(n.y,function(t){g(t,t.model)}),f(n.x,function(t){i("y")&&(t.onZero=!1)}),f(n.y,function(t){i("x")&&(t.onZero=!1)}),this[xe](this._model,e)},v[xe]=function(t,e){function n(){f(s,function(t){var e=t.isHorizontal(),i=e?[0,o.width]:[0,o[fe]],n=t.inverse?1:0;t.setExtent(i[n],i[1-n]),r(t,e?o.x:o.y)})}var o=a.getLayoutRect(t.getBoxLayoutParams(),{width:e[me](),height:e[ve]()});this._rect=o;var s=this._axesList;n(),t.get("containLabel")&&(f(s,function(t){if(!t.model.get("axisLabel.inside")){var e=i(t);if(e){var n=t.isHorizontal()?fe:"width",r=t.model.get("axisLabel.margin");o[n]-=e[n]+r,"top"===t[R]?o.y+=e[fe]+r:"left"===t[R]&&(o.x+=e.width+r)}}}),n())},v.getAxis=function(t,e){var i=this._axesMap[t];if(null!=i){if(null==e)for(var n in i)return i[n];return i[e]}},v.getCartesian=function(t,e){var i="x"+t+"y"+e;return this._coordsMap[i]},v._initCartesian=function(t,i){function n(n){return function(l,u){if(e(l,t,i)){var h=l.get(R);"x"===n?("top"!==h&&h!==pe&&(h=pe),r[h]&&(h="top"===h?pe:"top")):("left"!==h&&"right"!==h&&(h="left"),r[h]&&(h="left"===h?"right":"left")),r[h]=!0;var f=new d(n,o.createScaleByModel(l),[0,0],l.get("type"),h),p=f.type===c;f.onBand=p&&l.get("boundaryGap"),f.inverse=l.get("inverse"),f.onZero=l.get("axisLine.onZero"),l.axis=f,f.model=l,f.index=u,this._axesList.push(f),a[n][u]=f,s[n]++
+}}}var r={left:!1,right:!1,top:!1,bottom:!1},a={x:{},y:{}},s={x:0,y:0};return i.eachComponent("xAxis",n("x"),this),i.eachComponent("yAxis",n("y"),this),s.x&&s.y?(this._axesMap=a,void f(a.x,function(t,e){f(a.y,function(i,n){var r="x"+e+"y"+n,a=new h(r);a.grid=this,this._coordsMap[r]=a,this._coordsList.push(a),a.addAxis(t),a.addAxis(i)},this)},this)):(this._axesMap={},void(this._axesList=[]))},v._updateScale=function(t,i){function n(t,e,i){f(i.coordDimToDataDim(e.dim),function(i){e.scale.unionExtent(t.getDataExtent(i,e.scale.type!==l))})}u.each(this._axesList,function(t){t.scale.setExtent(1/0,-1/0)}),t.eachSeries(function(r){if("cartesian2d"===r.get(H)){var a=r.get("xAxisIndex"),o=r.get("yAxisIndex"),s=t[P]("xAxis",a),l=t[P]("yAxis",o);if(!e(s,i,t)||!e(l,i,t))return;var c=this.getCartesian(a,o),u=r[ie](),h=c.getAxis("x"),d=c.getAxis("y");"list"===u.type&&(n(u,h,r),n(u,d,r))}},this)},n[de]=function(t,e){var i=[];return t.eachComponent("grid",function(r,a){var o=new n(r,t,e);o.name="grid_"+a,o[xe](r,e),r[H]=o,i.push(o)}),t.eachSeries(function(e){if("cartesian2d"===e.get(H)){var n=e.get("xAxisIndex"),r=t[P]("xAxis",n),a=i[r.get("gridIndex")];e[H]=a.getCartesian(n,e.get("yAxisIndex"))}}),i},n[s]=h[be][s],t("../../CoordinateSystem").register("cartesian2d",n),n}),e("echarts/chart/bar/BarSeries",[Ce,"../../model/Series","../helper/createListFromArray"],function(t){var e=t("../../model/Series"),i=t("../helper/createListFromArray");return e[le]({type:"series.bar",dependencies:["grid","polar"],getInitialData:function(t,e){return i(t.data,this,e)},getMarkerPosition:function(t){var e=this[H];if(e){var i=e[o](t),n=this[ie](),r=n.getLayout("offset"),a=n.getLayout("size"),s=e.getBaseAxis().isHorizontal()?0:1;return i[s]+=r+a/2,i}return[0/0,0/0]},defaultOption:{zlevel:0,z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,xAxisIndex:0,yAxisIndex:0,barMinHeight:0,itemStyle:{normal:{barBorderColor:"#fff",barBorderWidth:0},emphasis:{barBorderColor:"#fff",barBorderWidth:0}}}})}),e("echarts/chart/bar/BarView",[Ce,Ae,a,"../../model/Model","./barItemStyle",r],function(t){function e(t,e){var i=t.width>0?1:-1,n=t[fe]>0?1:-1;e=Math.min(e,Math.abs(t.width),Math.abs(t[fe])),t.x+=i*e/2,t.y+=n*e/2,t.width-=i*e,t[fe]-=n*e}var i=t(Ae),n=t(a);return i[le](t("../../model/Model")[be],t("./barItemStyle")),t(r).extendChartView({type:"bar",render:function(t,e,i){var n=t.get(H);return"cartesian2d"===n&&this._renderOnCartesian(t,e,i),this.group},_renderOnCartesian:function(t){function r(r,a){var s=o.getItemLayout(r),l=o[h](r).get(f)||0;e(s,l);var c=new n.Rect({shape:i[le]({},s)});if(d){var p=c.shape,v=u?fe:"width",m={};p[v]=0,m[v]=s[v],n[a?g:"initProps"](c,{shape:m},t,r)}return c}var a=this.group,o=t[ie](),s=this._data,l=t[H],c=l.getBaseAxis(),u=c.isHorizontal(),d=t.get(v),f=["itemStyle",M,"barBorderWidth"];o.diff(s).add(function(t){if(o.hasValue(t)){var e=r(t);o.setItemGraphicEl(t,e),a.add(e)}})[he](function(i,l){var c=s[S](l);if(!o.hasValue(i))return void a[ce](c);c||(c=r(i,!0));var u=o.getItemLayout(i),d=o[h](i).get(f)||0;e(u,d),n[g](c,{shape:u},t,i),o.setItemGraphicEl(i,c),a.add(c)})[ce](function(e){var i=s[S](e);i&&(i.style.text="",n[g](i,{shape:{width:0}},t,e,function(){a[ce](i)}))}).execute(),this._updateStyle(t,o,u),this._data=o},_updateStyle:function(t,e,r){function a(t,e,i,r,a){n.setText(t,e,i),t.text=r,"outside"===t.textPosition&&(t.textPosition=a)}e.eachItemGraphicEl(function(o,s){var l=e[h](s),c=e[C](s,"color"),u=e[C](s,O),d=e.getItemLayout(s),f=l[ye]("itemStyle.normal"),p=l[ye]("itemStyle.emphasis").getBarItemStyle();o.setShape("r",f.get("barBorderRadius")||0),o.useStyle(i[se]({fill:c,opacity:u},f.getBarItemStyle()));var g=r?d[fe]>0?pe:"top":d.width>0?"left":"right",v=l[ye]("label.normal"),m=l[ye]("label.emphasis"),y=o.style;v.get("show")?a(y,v,c,i.retrieve(t.getFormattedLabel(s,M),t.getRawValue(s)),g):y.text="",m.get("show")?a(p,m,c,i.retrieve(t.getFormattedLabel(s,A),t.getRawValue(s)),g):p.text="",n.setHoverStyle(o,p)})},remove:function(t){var e=this.group;t.get(v)?this._data&&this._data.eachItemGraphicEl(function(i){i.style.text="",n[g](i,{shape:{width:0}},t,i[K],function(){e[ce](i)})}):e[q]()}})}),e("echarts/layout/barGrid",[Ce,Ae,"../util/number"],function(t){function e(t){return t.get("stack")||"__ec_stack_"+t[$]}function i(t){var i={};r.each(t,function(t){var n=t[H],r=n.getBaseAxis(),a=i[r.index]||{remainedWidth:r.getBandWidth(),autoWidthCount:0,categoryGap:"20%",gap:"30%",axis:r,stacks:{}},o=a.stacks;i[r.index]=a;var s=e(t);o[s]||a.autoWidthCount++,o[s]=o[s]||{width:0,maxWidth:0};var l=t.get("barWidth"),c=t.get("barMaxWidth"),u=t.get("barGap"),h=t.get("barCategoryGap");l&&!o[s].width&&(l=Math.min(a.remainedWidth,l),o[s].width=l,a.remainedWidth-=l),c&&(o[s].maxWidth=c),null!=u&&(a.gap=u),null!=h&&(a.categoryGap=h)});var n={};return r.each(i,function(t,e){n[e]={};var i=t.stacks,a=t.axis,s=a.getBandWidth(),l=o(t.categoryGap,s),c=o(t.gap,1),u=t.remainedWidth,h=t.autoWidthCount,d=(u-l)/(h+(h-1)*c);d=Math.max(d,0),r.each(i,function(t){var e=t.maxWidth;!t.width&&e&&d>e&&(e=Math.min(e,u),u-=e,t.width=e,h--)}),d=(u-l)/(h+(h-1)*c),d=Math.max(d,0);var f,p=0;r.each(i,function(t){t.width||(t.width=d),f=t,p+=t.width*(1+c)}),f&&(p-=f.width*c);var g=-p/2;r.each(i,function(t,i){n[e][i]=n[e][i]||{offset:g,width:t.width},g+=t.width*(1+c)})}),n}function n(t,n){var a=i(r[Se](n.getSeriesByType(t),function(t){return!n.isSeriesFiltered(t)&&t[H]&&"cartesian2d"===t[H].type})),o={};n.eachSeriesByType(t,function(t){var i=t[ie](),n=t[H],r=n.getBaseAxis(),s=e(t),l=a[r.index][s],c=l.offset,u=l.width,h=n.getOtherAxis(r),d=t.get("barMinHeight")||0,f=r.onZero?h.toGlobalCoord(h.dataToCoord(0)):h.getGlobalExtent()[0],p=n.dataToPoints(i,!0);o[s]=o[s]||[],i.setLayout({offset:c,size:u}),i.each(h.dim,function(t,e){if(!isNaN(t)){o[s][e]||(o[s][e]={p:f,n:f});var n,r,a,l,g=t>=0?"p":"n",v=p[e],m=o[s][e][g];h.isHorizontal()?(n=m,r=v[1]+c,a=v[0]-m,l=u,Math.abs(a)<d&&(a=(0>a?-1:1)*d),o[s][e][g]+=a):(n=v[0]+c,r=m,a=u,l=v[1]-m,Math.abs(l)<d&&(l=(0>=l?-1:1)*d),o[s][e][g]+=l),i.setItemLayout(e,{x:n,y:r,width:a,height:l})}},!0)},this)}var r=t(Ae),a=t("../util/number"),o=a[u];return n}),e("echarts/chart/line/LineSeries",[Ce,"../helper/createListFromArray","../../model/Series"],function(t){var e=t("../helper/createListFromArray"),i=t("../../model/Series");return i[le]({type:"series.line",dependencies:["grid","polar"],getInitialData:function(t,i){return e(t.data,this,i)},defaultOption:{zlevel:0,z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,hoverAnimation:!0,xAxisIndex:0,yAxisIndex:0,polarIndex:0,clipOverflow:!0,label:{normal:{position:"top"}},lineStyle:{normal:{width:2,type:"solid"}},smooth:!1,smoothMonotone:null,symbol:"emptyCircle",symbolSize:4,symbolRotate:null,showSymbol:!0,showAllSymbol:!1,connectNulls:!1,sampling:"none",animationEasing:"linear"}})}),e("echarts/chart/line/LineView",[Ce,Ae,"../helper/SymbolDraw","../helper/Symbol","./lineAnimationDiff",a,"./poly","../../view/Chart"],function(t){function e(t,e){if(t[oe]===e[oe]){for(var i=0;i<t[oe];i++){var n=t[i],r=e[i];if(n[0]!==r[0]||n[1]!==r[1])return}return!0}}function i(t){return"number"==typeof t?t:t?.3:0}function r(t){var e=t.getGlobalExtent();if(t.onBand){var i=t.getBandWidth()/2-1,n=e[1]>e[0]?1:-1;e[0]+=n*i,e[1]-=n*i}return e}function s(t){return t>=0?1:-1}function c(t,e){var i=t.getBaseAxis(),r=t.getOtherAxis(i),a=i.onZero?0:r.scale[k]()[0],l=r.dim,c="x"===l||l===n?1:0;return e.mapArray([l],function(n,r){for(var u,h=e.stackedOn;h&&s(h.get(l,r))===s(n);){u=h;break}var d=[];return d[c]=e.get(i.dim,r),d[1-c]=u?u.get(l,r,!0):a,t[o](d)},!0)}function u(t,e){return null!=e[K]?e[K]:null!=e.name?t.indexOfName(e.name):void 0}function h(t,e,i){var n=r(t.getAxis("x")),a=r(t.getAxis("y")),o=t.getBaseAxis().isHorizontal(),s=Math.min(n[0],n[1]),l=Math.min(a[0],a[1]),c=Math.max(n[0],n[1])-s,u=Math.max(a[0],a[1])-l,h=i.get("lineStyle.normal.width")||2,d=i.get("clipOverflow")?h/2:Math.max(c,u);o?(l-=d,u+=2*d):(s-=d,c+=2*d);var f=new _.Rect({shape:{x:s,y:l,width:c,height:u}});return e&&(f.shape[o?"width":fe]=0,_.initProps(f,{shape:{width:c,height:u}},i)),f}function d(t,e,i){var n=t.getAngleAxis(),r=t.getRadiusAxis(),a=r[k](),o=n[k](),s=Math.PI/180,l=new _[w]({shape:{cx:t.cx,cy:t.cy,r0:a[0],r:a[1],startAngle:-o[0]*s,endAngle:-o[1]*s,clockwise:n.inverse}});return e&&(l.shape.endAngle=-o[0]*s,_.initProps(l,{shape:{endAngle:-o[1]*s}},i)),l}function f(t,e,i){return"polar"===t.type?d(t,e,i):h(t,e,i)}var p=t(Ae),m=t("../helper/SymbolDraw"),y=t("../helper/Symbol"),x=t("./lineAnimationDiff"),_=t(a),b=t("./poly"),M=t("../../view/Chart");return M[le]({type:"line",init:function(){var t=new _.Group,e=new m;this.group.add(e.group),this._symbolDraw=e,this._lineGroup=t},render:function(t,n,r){var a=t[H],o=this.group,s=t[ie](),l=t[ye]("lineStyle.normal"),u=t[ye]("areaStyle.normal"),h=s.mapArray(s.getItemLayout,!0),d="polar"===a.type,g=this._coordSys,m=this._symbolDraw,y=this._polyline,x=this._polygon,_=this._lineGroup,b=t.get(v),w=!u.isEmpty(),S=c(a,s),M=t.get("showSymbol"),A=M&&!d&&!t.get("showAllSymbol")&&this._getSymbolIgnoreFunc(s,a),C=this._data;C&&C.eachItemGraphicEl(function(t,e){t.__temp&&(o[ce](t),C.setItemGraphicEl(e,null))}),M||m[ce](),o.add(_),y&&g.type===a.type?(w&&!x?x=this._newPolygon(h,S,a,b):x&&!w&&(_[ce](x),x=this._polygon=null),_.setClipPath(f(a,!1,t)),M&&m.updateData(s,A),s.eachItemGraphicEl(function(t){t.stopAnimation(!0)}),e(this._stackedOnPoints,S)&&e(this._points,h)||(b?this._updateAnimation(s,S,a,r):(y.setShape({points:h}),x&&x.setShape({points:h,stackedOnPoints:S})))):(M&&m.updateData(s,A),y=this._newPolyline(h,a,b),w&&(x=this._newPolygon(h,S,a,b)),_.setClipPath(f(a,!0,t))),y.useStyle(p[se](l.getLineStyle(),{fill:"none",stroke:s.getVisual("color"),lineJoin:"bevel"}));var T=t.get("smooth");if(T=i(t.get("smooth")),y.setShape({smooth:T,smoothMonotone:t.get("smoothMonotone"),connectNulls:t.get("connectNulls")}),x){var L=s.stackedOn,P=0;if(x.useStyle(p[se](u.getAreaStyle(),{fill:s.getVisual("color"),opacity:.7,lineJoin:"bevel"})),L){var z=L.hostModel;P=i(z.get("smooth"))}x.setShape({smooth:T,stackedOnSmooth:P,smoothMonotone:t.get("smoothMonotone"),connectNulls:t.get("connectNulls")})}this._data=s,this._coordSys=a,this._stackedOnPoints=S,this._points=h},highlight:function(t,e,i,n){var r=t[ie](),a=u(r,n);if(null!=a&&a>=0){var o=r[S](a);if(!o){var s=r.getItemLayout(a);o=new y(r,a,i),o[R]=s,o.setZ(t.get(Y),t.get("z")),o[ge]=isNaN(s[0])||isNaN(s[1]),o.__temp=!0,r.setItemGraphicEl(a,o),o.stopSymbolAnimation(!0),this.group.add(o)}o.highlight()}else M[be].highlight.call(this,t,e,i,n)},downplay:function(t,e,i,n){var r=t[ie](),a=u(r,n);if(null!=a&&a>=0){var o=r[S](a);o&&(o.__temp?(r.setItemGraphicEl(a,null),this.group[ce](o)):o.downplay())}else M[be].downplay.call(this,t,e,i,n)},_newPolyline:function(t){var e=this._polyline;return e&&this._lineGroup[ce](e),e=new b.Polyline({shape:{points:t},silent:!0,z2:10}),this._lineGroup.add(e),this._polyline=e,e},_newPolygon:function(t,e){var i=this._polygon;return i&&this._lineGroup[ce](i),i=new b.Polygon({shape:{points:t,stackedOnPoints:e},silent:!0}),this._lineGroup.add(i),this._polygon=i,i},_getSymbolIgnoreFunc:function(t,e){var i=e.getAxesByScale(l)[0];return i&&i.isLabelIgnored?p.bind(i.isLabelIgnored,i):void 0},_updateAnimation:function(t,e,i){var n=this._polyline,r=this._polygon,a=t.hostModel,o=x(this._data,t,this._stackedOnPoints,e,this._coordSys,i);n.shape.points=o.current,_[g](n,{shape:{points:o.next}},a),r&&(r.setShape({points:o.current,stackedOnPoints:o.stackedOnCurrent}),_[g](r,{shape:{points:o.next,stackedOnPoints:o.stackedOnNext}},a));for(var s=[],l=o.status,c=0;c<l[oe];c++){var u=l[c].cmd;if("="===u){var h=t[S](l[c].idx1);h&&s.push({el:h,ptIdx:c})}}n.animators&&n.animators[oe]&&n.animators[0].during(function(){for(var t=0;t<s[oe];t++){var e=s[t].el;e.attr(R,n.shape.points[s[t].ptIdx])}})},remove:function(){var t=this.group,e=this._data;this._lineGroup[q](),this._symbolDraw[ce](!0),e&&e.eachItemGraphicEl(function(i,n){i.__temp&&(t[ce](i),e.setItemGraphicEl(n,null))}),this._polyline=this._polygon=this._coordSys=this._points=this._stackedOnPoints=this._data=null}})}),e("echarts/visual/symbol",[Ce],function(){return function(t,e,i,n){n.eachRawSeriesByType(t,function(t){var r=t[ie](),a=t.get("symbol")||e,o=t.get("symbolSize");r.setVisual({legendSymbol:i||a,symbol:a,symbolSize:o}),n.isSeriesFiltered(t)||(typeof o===Z&&r.each(function(e){var i=t.getRawValue(e),n=t[Q](e);r.setItemVisual(e,"symbolSize",o(i,n))}),r.each(function(t){var e=r[h](t),i=e.get("symbol",!0),n=e.get("symbolSize",!0);null!=i&&r.setItemVisual(t,"symbol",i),null!=n&&r.setItemVisual(t,"symbolSize",n)}))})}}),e("echarts/layout/points",[Ce],function(){return function(t,e){e.eachSeriesByType(t,function(t){var e=t[ie](),i=t[H];if(i){var n=i[s];e.each(n,function(t,n,r){var a;a=isNaN(t)||isNaN(n)?[0/0,0/0]:i[o]([t,n]),e.setItemLayout(r,a)},!0)}})}}),e("echarts/processor/dataSample",[],function(){var t={average:function(t){for(var e=0,i=0,n=0;n<t[oe];n++)isNaN(t[n])||(e+=t[n],i++);return 0===i?0/0:e/i},sum:function(t){for(var e=0,i=0;i<t[oe];i++)e+=t[i]||0;return e},max:function(t){for(var e=-1/0,i=0;i<t[oe];i++)t[i]>e&&(e=t[i]);return e},min:function(t){for(var e=1/0,i=0;i<t[oe];i++)t[i]<e&&(e=t[i]);return e},nearest:function(t){return t[0]}},e=function(t){return Math.round(t[oe]/2)};return function(i,n){n.eachSeriesByType(i,function(i){var n=i[ie](),r=i.get("sampling"),a=i[H];if("cartesian2d"===a.type&&r){var o=a.getBaseAxis(),s=a.getOtherAxis(o),l=o[k](),c=l[1]-l[0],u=Math.round(n.count()/c);if(u>1){var h;typeof r===_e?h=t[r]:typeof r===Z&&(h=r),h&&(n=n.downSample(s.dim,1/u,h,e),i.setData(n))}}},this)}}),e("echarts/chart/pie/PieSeries",[Ce,"../../data/List",Ae,"../../util/model","../../data/helper/completeDimensions","../../component/helper/selectableMixin",r],function(t){var e=t("../../data/List"),i=t(Ae),n=t("../../util/model"),a=t("../../data/helper/completeDimensions"),o=t("../../component/helper/selectableMixin"),s=t(r).extendSeriesModel({type:"series.pie",init:function(t){s.superApply(this,"init",arguments),this.legendDataProvider=function(){return this._dataBeforeProcessed},this.updateSelectedMap(t.data),this._defaultLabelLine(t)},mergeOption:function(t){s.superCall(this,"mergeOption",t),this.updateSelectedMap(this[z].data)},getInitialData:function(t){var i=a(["value"],t.data),n=new e(i,this);return n.initData(t.data),n},getDataParams:function(t){var e=this._data,i=s.superCall(this,Q,t),n=e.getSum("value");return i.percent=n?+(e.get("value",t)/n*100).toFixed(2):0,i.$vars.push("percent"),i},_defaultLabelLine:function(t){n.defaultEmphasis(t.labelLine,["show"]);var e=t.labelLine[M],i=t.labelLine[A];e.show=e.show&&t.label[M].show,i.show=i.show&&t.label[A].show},defaultOption:{zlevel:0,z:2,legendHoverLink:!0,hoverAnimation:!0,center:["50%","50%"],radius:[0,"75%"],clockwise:!0,startAngle:90,minAngle:0,selectedOffset:10,avoidLabelOverlap:!0,label:{normal:{rotate:!1,show:!0,position:"outer"},emphasis:{}},labelLine:{normal:{show:!0,length:15,length2:15,smooth:!1,lineStyle:{width:1,type:"solid"}}},itemStyle:{normal:{borderColor:"rgba(0,0,0,0)",borderWidth:1},emphasis:{borderColor:"rgba(0,0,0,0)",borderWidth:1}},animationEasing:"cubicOut",data:[]}});return i.mixin(s,o),s}),e("echarts/chart/pie/PieView",[Ce,a,Ae,"../../view/Chart"],function(t){function e(t,e,n,r){var a=e[ie](),o=this[K],s=a[T](o),l=e.get("selectedOffset");r.dispatchAction({type:"pieToggleSelect",from:t,name:s,seriesId:e.id}),a.each(function(t){i(a[S](t),a.getItemLayout(t),e.isSelected(a[T](t)),l,n)})}function i(t,e,i,n,r){var a=(e.startAngle+e.endAngle)/2,o=Math.cos(a),s=Math.sin(a),l=i?n:0,c=[o*l,s*l];r?t.animate().when(200,{position:c}).start("bounceOut"):t.attr(R,c)}function n(t,e){function i(){a[ge]=a.hoverIgnore,s[ge]=s.hoverIgnore}function n(){a[ge]=a.normalIgnore,s[ge]=s.normalIgnore}o.Group.call(this);var r=new o[w]({z2:2}),a=new o.Polyline,s=new o.Text;this.add(r),this.add(a),this.add(s),this.updateData(t,e,!0),this.on(A,i).on(M,n).on(ee,i).on(te,n)}function r(t,e,i,n,r){var a=n[ye](G),o=r===m||"inner"===r;return{fill:a.getTextColor()||(o?"#fff":t[C](e,"color")),opacity:t[C](e,O),textFont:a[V](),text:s.retrieve(t.hostModel.getFormattedLabel(e,i),t[T](e))}}var o=t(a),s=t(Ae),l=n[be];l.updateData=function(t,e,n){function r(){l.stopAnimation(!0),l.animateTo({shape:{r:d.r+10}},300,"elasticOut")}function a(){l.stopAnimation(!0),l.animateTo({shape:{r:d.r}},300,"elasticOut")}var l=this.childAt(0),c=t.hostModel,u=t[h](e),d=t.getItemLayout(e),f=s[le]({},d);f.label=null,n?(l.setShape(f),l.shape.endAngle=d.startAngle,o[g](l,{shape:{endAngle:d.endAngle}},c,e)):o[g](l,{shape:f},c,e);var p=u[ye]("itemStyle"),m=t[C](e,"color");l.useStyle(s[se]({fill:m},p[ye](M).getItemStyle())),l.hoverStyle=p[ye](A).getItemStyle(),i(this,t.getItemLayout(e),u.get("selected"),c.get("selectedOffset"),c.get(v)),l.off(ee).off(te).off(A).off(M),u.get("hoverAnimation")&&l.on(ee,r).on(te,a).on(A,r).on(M,a),this._updateLabel(t,e),o.setHoverStyle(this)},l._updateLabel=function(t,e){var i=this.childAt(1),n=this.childAt(2),a=t.hostModel,s=t[h](e),l=t.getItemLayout(e),c=l.label,u=t[C](e,"color");o[g](i,{shape:{points:c.linePoints||[[c.x,c.y],[c.x,c.y],[c.x,c.y]]}},a,e),o[g](n,{style:{x:c.x,y:c.y}},a,e),n.attr({style:{textVerticalAlign:c.verticalAlign,textAlign:c[F],textFont:c.font},rotation:c.rotation,origin:[c.x,c.y],z2:10});var d=s[ye]("label.normal"),f=s[ye]("label.emphasis"),p=s[ye]("labelLine.normal"),v=s[ye]("labelLine.emphasis"),m=d.get(R)||f.get(R);n.setStyle(r(t,e,M,d,m)),n[ge]=n.normalIgnore=!d.get("show"),n.hoverIgnore=!f.get("show"),i[ge]=i.normalIgnore=!p.get("show"),i.hoverIgnore=!v.get("show"),i.setStyle({stroke:u,opacity:t[C](e,O)}),i.setStyle(p[ye]("lineStyle").getLineStyle()),n.hoverStyle=r(t,e,A,f,m),i.hoverStyle=v[ye]("lineStyle").getLineStyle();var y=p.get("smooth");y&&y===!0&&(y=.4),i.setShape({smooth:y})},s[W](n,o.Group);var c=t("../../view/Chart")[le]({type:"pie",init:function(){var t=new o.Group;this._sectorGroup=t},render:function(t,i,r,a){if(!a||a.from!==this.uid){var o=t[ie](),l=this._data,c=this.group,u=i.get(v),h=!l,d=s.curry(e,this.uid,t,u,r),f=t.get("selectedMode");if(o.diff(l).add(function(t){var e=new n(o,t);h&&e.eachChild(function(t){t.stopAnimation(!0)}),f&&e.on("click",d),o.setItemGraphicEl(t,e),c.add(e)})[he](function(t,e){var i=l[S](e);i.updateData(o,t),i.off("click"),f&&i.on("click",d),c.add(i),o.setItemGraphicEl(t,i)})[ce](function(t){var e=l[S](t);c[ce](e)}).execute(),u&&h&&o.count()>0){var p=o.getItemLayout(0),g=Math.max(r[me](),r[ve]())/2,m=s.bind(c.removeClipPath,c);c.setClipPath(this._createClipPath(p.cx,p.cy,g,p.startAngle,p.clockwise,m,t))}this._data=o}},_createClipPath:function(t,e,i,n,r,a,s){var l=new o[w]({shape:{cx:t,cy:e,r0:0,r:i,startAngle:n,endAngle:n,clockwise:r}});return o.initProps(l,{shape:{endAngle:n+(r?1:-1)*Math.PI*2}},s,a),l}});return c}),e("echarts/action/createDataSelectAction",[Ce,"../echarts",Ae],function(t){var e=t("../echarts"),i=t(Ae);return function(t,n){i.each(n,function(i){i[he]="updateView",e.registerAction(i,function(e,n){var r={};return n.eachComponent({mainType:"series",subType:t,query:e},function(t){t[i.method]&&t[i.method](e.name);var n=t[ie]();n.each(function(e){var i=n[T](e);r[i]=t.isSelected(i)||!1})}),{name:e.name,selected:r}})})}}),e("echarts/visual/dataColor",[Ce],function(){return function(t,e){var i=e.get("color"),n=0;e.eachRawSeriesByType(t,function(t){var r=t.get("color",!0),a=t.getRawData();if(!e.isSeriesFiltered(t)){var o=t[ie]();o.each(function(t){var e=o[h](t),s=o.getRawIndex(t),l=o[C](t,"color",!0);if(l)a.setItemVisual(s,"color",l);else{var c=r?r[s%r[oe]]:i[(s+n)%i[oe]],u=e.get("itemStyle.normal.color")||c;a.setItemVisual(s,"color",u),o.setItemVisual(t,"color",u)}})}n+=a.count()})}}),e("echarts/chart/pie/pieLayout",[Ce,"../../util/number","./labelLayout",Ae],function(t){var e=t("../../util/number"),i=e[u],r=t("./labelLayout"),a=t(Ae),o=2*Math.PI,s=Math.PI/180;return function(t,l,c){l.eachSeriesByType(t,function(t){var l=t.get(B),u=t.get(n);a[j](u)||(u=[0,u]),a[j](l)||(l=[l,l]);var h=c[me](),d=c[ve](),f=Math.min(h,d),p=i(l[0],h),g=i(l[1],d),v=i(u[0],f/2),m=i(u[1],f/2),y=t[ie](),x=-t.get("startAngle")*s,_=t.get("minAngle")*s,b=y.getSum("value"),w=Math.PI/(b||y.count())*2,S=t.get("clockwise"),M=t.get("roseType"),A=y.getDataExtent("value");A[0]=0;var C=o,T=0,L=x,P=S?1:-1;if(y.each("value",function(t,i){var n;n="area"!==M?0===b?w:t*w:o/(y.count()||1),_>n?(n=_,C-=_):T+=t;var r=L+P*n;y.setItemLayout(i,{angle:n,startAngle:L,endAngle:r,clockwise:S,cx:p,cy:g,r0:v,r:M?e.linearMap(t,A,[v,m]):m}),L=r},!0),o>C)if(.001>=C){var z=o/y.count();y.each(function(t){var e=y.getItemLayout(t);e.startAngle=x+P*t*z,e.endAngle=x+P*(t+1)*z})}else w=C/T,L=x,y.each("value",function(t,e){var i=y.getItemLayout(e),n=i.angle===_?_:t*w;i.startAngle=L,i.endAngle=L+P*n,L+=n});r(t,m,h,d)})}}),e("echarts/processor/dataFilter",[],function(){return function(t,e){var i=e.findComponents({mainType:"legend"});i&&i[oe]&&e.eachSeriesByType(t,function(t){var e=t[ie]();e.filterSelf(function(t){for(var n=e[T](t),r=0;r<i[oe];r++)if(!i[r].isSelected(n))return!1;return!0},this)},this)}}),e("echarts/component/axis",[Ce,"../coord/cartesian/AxisModel","./axis/AxisView"],function(t){t("../coord/cartesian/AxisModel"),t("./axis/AxisView")}),e("echarts/coord/polar/polarCreator",[Ce,"./Polar","../../util/number","../../coord/axisHelper","./PolarModel","../../CoordinateSystem"],function(t){function e(t,e){var i=t.get(B),r=t.get(n),a=e[me](),s=e[ve](),l=o[u];this.cx=l(i[0],a),this.cy=l(i[1],s);var c=this.getRadiusAxis(),h=Math.min(a,s)/2;c.setExtent(0,l(r,h))}function i(t){var e=this,i=e.getAngleAxis(),r=e.getRadiusAxis();if(i.scale.setExtent(1/0,-1/0),r.scale.setExtent(1/0,-1/0),t.eachSeries(function(t){if(t[H]===e){var a=t[ie]();r.scale.unionExtent(a.getDataExtent(n,r.type!==c)),i.scale.unionExtent(a.getDataExtent("angle",i.type!==c))}}),h(i,i.model),h(r,r.model),i.type===c&&!i.onBand){var a=i[k](),o=360/i.scale.count();i.inverse?a[1]+=o:a[1]-=o,i.setExtent(a[0],a[1])}}function r(t,e){if(t.type=e.get("type"),t.scale=l.createScaleByModel(e),t.onBand=e.get("boundaryGap")&&t.type===c,"angleAxis"===e.mainType){var i=e.get("startAngle");t.inverse=e.get("inverse")^e.get("clockwise"),t.setExtent(i,i+(t.inverse?-360:360))}e.axis=t,t.model=e}var a=t("./Polar"),o=t("../../util/number"),l=t("../../coord/axisHelper"),h=l.niceScaleExtent;t("./PolarModel");var d={dimensions:a[be][s],create:function(t,n){var o=[];return t.eachComponent("polar",function(t,s){var l=new a(s);l[xe]=e,l[he]=i;var c=l.getRadiusAxis(),u=l.getAngleAxis(),h=t.findAxisModel("radiusAxis"),d=t.findAxisModel("angleAxis");r(c,h),r(u,d),l[xe](t,n),o.push(l),t[H]=l}),t.eachSeries(function(t){"polar"===t.get(H)&&(t[H]=o[t.get("polarIndex")])}),o}};t("../../CoordinateSystem").register("polar",d)}),e("echarts/component/angleAxis",[Ce,"../coord/polar/polarCreator","./axis/AngleAxisView"],function(t){t("../coord/polar/polarCreator"),t("./axis/AngleAxisView")}),e("echarts/component/radiusAxis",[Ce,"../coord/polar/polarCreator","./axis/RadiusAxisView"],function(t){t("../coord/polar/polarCreator"),t("./axis/RadiusAxisView")}),e("echarts/util/layout",[Ce,Ae,"zrender/core/BoundingRect","./number","./format"],function(t){function e(t,e,i,n,r){var a=0,o=0;null==n&&(n=1/0),null==r&&(r=1/0);var s=0;e.eachChild(function(l,c){var u,h,d=l[R],f=l[N](),p=e.childAt(c+1),g=p&&p[N]();if("horizontal"===t){var v=f.width+(g?-g.x+f.x:0);u=a+v,u>n||l.newline?(a=0,u=v,o+=s+i,s=f[fe]):s=Math.max(s,f[fe])}else{var m=f[fe]+(g?-g.y+f.y:0);h=o+m,h>r||l.newline?(a+=s+i,o=0,h=m,s=f.width):s=Math.max(s,f.width)}l.newline||(d[0]=a,d[1]=o,"horizontal"===t?a=u+i:o=h+i)})}var i=t(Ae),n=t("zrender/core/BoundingRect"),r=t("./number"),a=t("./format"),o=r[u],s=i.each,l={},c=["left","right","top",pe,"width",fe];return l.box=e,l.vbox=i.curry(e,"vertical"),l.hbox=i.curry(e,"horizontal"),l.getAvailableSize=function(t,e,i){var n=e.width,r=e[fe],s=o(t.x,n),l=o(t.y,r),c=o(t.x2,n),u=o(t.y2,r);return(isNaN(s)||isNaN(parseFloat(t.x)))&&(s=0),(isNaN(c)||isNaN(parseFloat(t.x2)))&&(c=n),(isNaN(l)||isNaN(parseFloat(t.y)))&&(l=0),(isNaN(u)||isNaN(parseFloat(t.y2)))&&(u=r),i=a.normalizeCssArray(i||0),{width:Math.max(c-s-i[1]-i[3],0),height:Math.max(u-l-i[0]-i[2],0)}},l.getLayoutRect=function(t,e,i){i=a.normalizeCssArray(i||0);var r=e.width,s=e[fe],l=o(t.left,r),c=o(t.top,s),u=o(t.right,r),h=o(t[pe],s),d=o(t.width,r),f=o(t[fe],s),p=i[2]+i[0],g=i[1]+i[3],v=t.aspect;switch(isNaN(d)&&(d=r-u-g-l),isNaN(f)&&(f=s-h-p-c),isNaN(d)&&isNaN(f)&&(v>r/s?d=.8*r:f=.8*s),null!=v&&(isNaN(d)&&(d=v*f),isNaN(f)&&(f=d/v)),isNaN(l)&&(l=r-u-d-g),isNaN(c)&&(c=s-h-f-p),t.left||t.right){case B:l=r/2-d/2-i[3];break;case"right":l=r-d-g}switch(t.top||t[pe]){case E:case B:c=s/2-f/2-i[0];break;case pe:c=s-f-p}l=l||0,c=c||0,isNaN(d)&&(d=r-l-(u||0)),isNaN(f)&&(f=s-c-(h||0));var m=new n(l+i[3],c+i[0],d,f);return m.margin=i,m},l.positionGroup=function(t,e,n,r){var a=t[N]();e=i[le](i.clone(e),{width:a.width,height:a[fe]}),e=l.getLayoutRect(e,n,r),t[R]=[e.x-a.x,e.y-a.y]},l.mergeLayoutParam=function(t,e,n){function r(i){var r={},l=0,c={},u=0,h=n.ignoreSize?1:2;if(s(i,function(e){c[e]=t[e]}),s(i,function(t){a(e,t)&&(r[t]=c[t]=e[t]),o(r,t)&&l++,o(c,t)&&u++}),u!==h&&l){if(l>=h)return r;for(var d=0;d<i[oe];d++){var f=i[d];if(!a(r,f)&&a(t,f)){r[f]=t[f];break}}return r}return c}function a(t,e){return t.hasOwnProperty(e)}function o(t,e){return null!=t[e]&&"auto"!==t[e]}function l(t,e,i){s(t,function(t){e[t]=i[t]})}!i[ue](n)&&(n={});var c=["width","left","right"],u=[fe,"top",pe],h=r(c),d=r(u);l(c,t,h),l(u,t,d)},l.getLayoutParams=function(t){return l.copyLayoutParams({},t)},l.copyLayoutParams=function(t,e){return e&&t&&s(c,function(i){e.hasOwnProperty(i)&&(t[i]=e[i])}),t},l}),e("echarts/component/legend/LegendModel",[Ce,Ae,"../../model/Model",r],function(t){var e=t(Ae),i=t("../../model/Model"),n=t(r).extendComponentModel({type:"legend",dependencies:[re],layoutMode:{type:"box",ignoreSize:!0},init:function(t,e,i){this.mergeDefaultAndTheme(t,i),t.selected=t.selected||{},this._updateData(i);var n=this._data,r=this[z].selected;if(n[0]&&"single"===this.get("selectedMode")){var a=!1;for(var o in r)r[o]&&(this.select(o),a=!0);!a&&this.select(n[0].get("name"))}},mergeOption:function(t){n.superCall(this,"mergeOption",t),this._updateData(this[L])},_updateData:function(t){var n=e.map(this.get("data")||[],function(t){return typeof t===_e&&(t={name:t}),new i(t,this,this[L])},this);this._data=n;var r=e.map(t.getSeries(),function(t){return t.name});t.eachSeries(function(t){if(t.legendDataProvider){var e=t.legendDataProvider();r=r.concat(e.mapArray(e[T]))}}),this._availableNames=r},getData:function(){return this._data},select:function(t){var i=this[z].selected,n=this.get("selectedMode");if("single"===n){var r=this._data;e.each(r,function(t){i[t.get("name")]=!1})}i[t]=!0},unSelect:function(t){"single"!==this.get("selectedMode")&&(this[z].selected[t]=!1)},toggleSelected:function(t){var e=this[z].selected;t in e||(e[t]=!0),this[e[t]?"unSelect":"select"](t)},isSelected:function(t){var i=this[z].selected;return!(t in i&&!i[t])&&e[X](this._availableNames,t)>=0},defaultOption:{zlevel:0,z:4,show:!0,orient:"horizontal",left:"center",top:"top",align:"auto",backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderWidth:0,padding:5,itemGap:10,itemWidth:25,itemHeight:14,textStyle:{color:"#333"},selectedMode:!0}});return n}),e("echarts/component/legend/legendAction",[Ce,r,Ae],function(t){function e(t,e,i){var r,a={},o="toggleSelected"===t;return i.eachComponent("legend",function(i){o&&null!=r?i[r?"select":"unSelect"](e.name):(i[t](e.name),r=i.isSelected(e.name));var s=i[ie]();n.each(s,function(t){var e=t.get("name");if("\n"!==e&&""!==e){var n=i.isSelected(e);a[e]=e in a?a[e]&&n:n}})}),{name:e.name,selected:a}}var i=t(r),n=t(Ae);i.registerAction("legendToggleSelect","legendselectchanged",n.curry(e,"toggleSelected")),i.registerAction("legendSelect","legendselected",n.curry(e,"select")),i.registerAction("legendUnSelect","legendunselected",n.curry(e,"unSelect"))}),e("echarts/component/legend/LegendView",[Ce,Ae,"../../util/symbol",a,"../helper/listComponent",r],function(t){function e(t,e){e.dispatchAction({type:"legendToggleSelect",name:t})}function i(t,e,i){t.get("legendHoverLink")&&i.dispatchAction({type:"highlight",seriesName:t.name,name:e})}function n(t,e,i){t.get("legendHoverLink")&&i.dispatchAction({type:"downplay",seriesName:t.name,name:e})}var o=t(Ae),s=t("../../util/symbol"),l=t(a),c=t("../helper/listComponent"),u=o.curry,h="#ccc";return t(r).extendComponentView({type:"legend",init:function(){this._symbolTypeStore={}},render:function(t,r,a){var s=this.group;if(s[q](),t.get("show")){var h=t.get("selectedMode"),d=t.get("align");"auto"===d&&(d="right"===t.get("left")&&"vertical"===t.get("orient")?"right":"left");var f={};o.each(t[ie](),function(o){var c=o.get("name");if(""===c||"\n"===c)return void s.add(new l.Group({newline:!0}));var p=r.getSeriesByName(c)[0];if(!f[c])if(p){var g=p[ie](),v=g.getVisual("color");typeof v===Z&&(v=v(p[Q](0)));var m=g.getVisual("legendSymbol")||"roundRect",y=g.getVisual("symbol"),x=this._createItem(c,o,t,m,y,d,v,h);x.on("click",u(e,c,a)).on(ee,u(i,p,"",a)).on(te,u(n,p,"",a)),f[c]=!0}else r.eachRawSeries(function(r){if(!f[c]&&r.legendDataProvider){var s=r.legendDataProvider(),l=s.indexOfName(c);if(0>l)return;var p=s[C](l,"color"),g="roundRect",v=this._createItem(c,o,t,g,null,d,p,h);v.on("click",u(e,c,a)).on(ee,u(i,r,c,a)).on(te,u(n,r,c,a)),f[c]=!0}},this)},this),c.layout(s,t,a),c.addBackground(s,t)}},_createItem:function(t,e,i,n,r,a,o,c){var u=i.get("itemWidth"),d=i.get("itemHeight"),f=i.isSelected(t),p=new l.Group,g=e[ye](G),v=e.get("icon");if(n=v||n,p.add(s.createSymbol(n,0,0,u,d,f?o:h)),!v&&r&&(r!==n||"none"==r)){var m=.8*d;"none"===r&&(r="circle"),p.add(s.createSymbol(r,(u-m)/2,(d-m)/2,m,m,f?o:h))}var y="left"===a?u+5:-5,x=a,_=i.get("formatter");typeof _===_e&&_?t=_[U]("{name}",t):typeof _===Z&&(t=_(t));var b=new l.Text({style:{text:t,x:y,y:d/2,fill:f?g.getTextColor():h,textFont:g[V](),textAlign:x,textVerticalAlign:"middle"}});return p.add(b),p.add(new l.Rect({shape:p[N](),invisible:!0})),p.eachChild(function(t){t.silent=!c}),this.group.add(p),l.setHoverStyle(p),p}})}),e("echarts/component/legend/legendFilter",[],function(){return function(t){var e=t.findComponents({mainType:"legend"});e&&e[oe]&&t.filterSeries(function(t){for(var i=0;i<e[oe];i++)if(!e[i].isSelected(t.name))return!1;return!0})}}),e("echarts/component/tooltip/TooltipModel",[Ce,r],function(t){t(r).extendComponentModel({type:"tooltip",defaultOption:{zlevel:0,z:8,show:!0,showContent:!0,trigger:"item",triggerOn:"mousemove",alwaysShowContent:!1,showDelay:0,hideDelay:100,transitionDuration:.4,enterable:!1,backgroundColor:"rgba(50,50,50,0.7)",borderColor:"#333",borderRadius:4,borderWidth:0,padding:5,extraCssText:"",axisPointer:{type:"line",axis:"auto",animation:!0,animationDurationUpdate:200,animationEasingUpdate:"exponentialOut",lineStyle:{color:"#555",width:1,type:"solid"},crossStyle:{color:"#555",width:1,type:"dashed",textStyle:{}},shadowStyle:{color:"rgba(150,150,150,0.3)"}},textStyle:{color:"#fff",fontSize:14}}})}),e("echarts/component/tooltip/TooltipView",[Ce,"./TooltipContent",a,Ae,"../../util/format","../../util/number","zrender/core/env",r],function(t){function e(t,e){if(!t||!e)return!1;var i=P.round;return i(t[0])===i(e[0])&&i(t[1])===i(e[1])}function l(t,e,i,n){return{x1:t,y1:e,x2:i,y2:n}}function d(t,e,i,n){return{x:t,y:e,width:i,height:n}}function f(t,e,i,n,r,a){return{cx:t,cy:e,r0:i,r:n,startAngle:r,endAngle:a,clockwise:!0}}function p(t,e,i,n,r){var a=i.clientWidth,o=i.clientHeight,s=20;return t+a+s>n?t-=a+s:t+=s,e+o+s>r?e-=o+s:e+=s,[t,e]}function v(t,e,i){var n=i.clientWidth,r=i.clientHeight,a=5,o=0,s=0,l=e.width,c=e[fe];switch(t){case m:o=e.x+l/2-n/2,s=e.y+c/2-r/2;break;case"top":o=e.x+l/2-n/2,s=e.y-r-a;break;case pe:o=e.x+l/2-n/2,s=e.y+c+a;break;case"left":o=e.x-n-a,s=e.y+c/2-r/2;break;case"right":o=e.x+l+a,s=e.y+c/2-r/2
+}return[o,s]}function y(t,e,n,r,a,o,s){var l=s[me](),c=s[ve](),u=o&&o[N]().clone();if(o&&u[b](o[Me]),typeof t===Z&&(t=t([e,n],a,r.el,u)),C[j](t))e=z(t[0],l),n=z(t[1],c);else if(typeof t===_e&&o){var h=v(t,u,r.el);e=h[0],n=h[1]}else{var h=p(e,n,r.el,l,c);e=h[0],n=h[1]}r[i](e,n)}function _(t){var e=t[H],i=t.get("tooltip.trigger",!0);return!(!e||"cartesian2d"!==e.type&&"polar"!==e.type&&"single"!==e.type||"item"===i)}var M=t("./TooltipContent"),A=t(a),C=t(Ae),L=t("../../util/format"),P=t("../../util/number"),z=P[u],D=t("zrender/core/env");t(r).extendComponentView({type:"tooltip",_axisPointers:{},init:function(t,e){if(!D.node){var i=new M(e.getDom(),e);this._tooltipContent=i,e.on("showTip",this._manuallyShowTip,this),e.on("hideTip",this._manuallyHideTip,this)}},render:function(t,e,i){if(!D.node){this.group[q](),this._axisPointers={},this._tooltipModel=t,this._ecModel=e,this._api=i,this._lastHover={};var n=this._tooltipContent;n[he](),n.enterable=t.get("enterable"),this._alwaysShowContent=t.get("alwaysShowContent"),this._seriesGroupByAxis=this._prepareAxisTriggerData(t,e);var r=this._crossText;if(r&&this.group.add(r),null!=this._lastX&&null!=this._lastY){var a=this;clearTimeout(this._refreshUpdateTimeout),this._refreshUpdateTimeout=setTimeout(function(){a._manuallyShowTip({x:a._lastX,y:a._lastY})})}var o=this._api.getZr();o.off("click",this._tryShow),o.off("mousemove",this._mousemove),o.off(te,this._hide),o.off("globalout",this._hide),"click"===t.get("triggerOn")?o.on("click",this._tryShow,this):(o.on("mousemove",this._mousemove,this),o.on(te,this._hide,this),o.on("globalout",this._hide,this))}},_mousemove:function(t){var e=this._tooltipModel.get("showDelay"),i=this;clearTimeout(this._showTimeout),e>0?this._showTimeout=setTimeout(function(){i._tryShow(t)},e):this._tryShow(t)},_manuallyShowTip:function(t){if(t.from!==this.uid){var e=this._ecModel,i=t[$],n=t[K],r=e.getSeriesByIndex(i),a=this._api;if(null==t.x||null==t.y){if(r||e.eachSeries(function(t){_(t)&&!r&&(r=t)}),r){var l=r[ie]();null==n&&(n=l.indexOfName(t.name));var c,u,h=l[S](n),d=r[H];if(d&&d[o]){var f=d[o](l.getValues(C.map(d[s],function(t){return r.coordDimToDataDim(t)[0]}),n,!0));c=f&&f[0],u=f&&f[1]}else if(h){var p=h[N]().clone();p[b](h[Me]),c=p.x+p.width/2,u=p.y+p[fe]/2}null!=c&&null!=u&&this._tryShow({offsetX:c,offsetY:u,target:h,event:{}})}}else{var h=a.getZr().handler.findHover(t.x,t.y);this._tryShow({offsetX:t.x,offsetY:t.y,target:h,event:{}})}}},_manuallyHideTip:function(t){t.from!==this.uid&&this._hide()},_prepareAxisTriggerData:function(t,e){var i={};return e.eachSeries(function(t){if(_(t)){var e,n,r=t[H];"cartesian2d"===r.type?(e=r.getBaseAxis(),n=e.dim+e.index):"single"===r.type?(e=r.getAxis(),n=e.dim+e.type):(e=r.getBaseAxis(),n=e.dim+r.name),i[n]=i[n]||{coordSys:[],series:[]},i[n].coordSys.push(r),i[n][re].push(t)}},this),i},_tryShow:function(t){var e=t[J],i=this._tooltipModel,n=i.get(ae),r=this._ecModel,a=this._api;if(i)if(this._lastX=t.offsetX,this._lastY=t.offsetY,e&&null!=e[K]){var o=e.dataModel||r.getSeriesByIndex(e[$]),s=e[K],l=o[ie]()[h](s);"axis"===(l.get("tooltip.trigger")||n)?this._showAxisTooltip(i,r,t):(this._ticket="",this._hideAxisPointer(),this._resetLastHover(),this._showItemTooltipContent(o,s,e.dataType,t)),a.dispatchAction({type:"showTip",from:this.uid,dataIndex:e[K],seriesIndex:e[$]})}else"item"===n?this._hide():this._showAxisTooltip(i,r,t),"cross"===i.get("axisPointer.type")&&a.dispatchAction({type:"showTip",from:this.uid,x:t.offsetX,y:t.offsetY})},_showAxisTooltip:function(t,i,n){var r=t[ye]("axisPointer"),a=r.get("type");if("cross"===a){var l=n[J];if(l&&null!=l[K]){var c=i.getSeriesByIndex(l[$]),u=l[K];this._showItemTooltipContent(c,u,l.dataType,n)}}this._showAxisPointer();var h=!0;C.each(this._seriesGroupByAxis,function(t){var i=t.coordSys,l=i[0],c=[n.offsetX,n.offsetY];if(!l.containPoint(c))return void this._hideAxisPointer(l.name);h=!1;var u=l[s],d=l.pointToData(c,!0);c=l[o](d);var f=l.getBaseAxis(),p=r.get("axis");"auto"===p&&(p=f.dim);var g=!1,v=this._lastHover;if("cross"===a)e(v.data,d)&&(g=!0),v.data=d;else{var m=C[X](u,p);v.data===d[m]&&(g=!0),v.data=d[m]}"cartesian2d"!==l.type||g?"polar"!==l.type||g?"single"!==l.type||g||this._showSinglePointer(r,l,p,c):this._showPolarPointer(r,l,p,c):this._showCartesianPointer(r,l,p,c),"cross"!==a&&this._dispatchAndShowSeriesTooltipContent(l,t[re],c,d,g)},this),this._tooltipModel.get("show")||this._hideAxisPointer(),h&&this._hide()},_showCartesianPointer:function(t,e,i,n){function r(i,n,r){var a="x"===i?l(n[0],r[0],n[0],r[1]):l(r[0],n[1],r[1],n[1]),s=o._getPointerElement(e,t,i,a);c?A[g](s,{shape:a},t):s.attr({shape:a})}function a(i,n,r){var a=e.getAxis(i),s=a.getBandWidth(),l=r[1]-r[0],u="x"===i?d(n[0]-s/2,r[0],s,l):d(r[0],n[1]-s/2,l,s),h=o._getPointerElement(e,t,i,u);c?A[g](h,{shape:u},t):h.attr({shape:u})}var o=this,s=t.get("type"),c="cross"!==s;if("cross"===s)r("x",n,e.getAxis("y").getGlobalExtent()),r("y",n,e.getAxis("x").getGlobalExtent()),this._updateCrossText(e,n,t);else{var u=e.getAxis("x"===i?"y":"x"),h=u.getGlobalExtent();"cartesian2d"===e.type&&("line"===s?r:a)(i,n,h)}},_showSinglePointer:function(t,e,i,n){function r(i,n,r){var o=e.getAxis(),c=o.orient,u="horizontal"===c?l(n[0],r[0],n[0],r[1]):l(r[0],n[1],r[1],n[1]),h=a._getPointerElement(e,t,i,u);s?A[g](h,{shape:u},t):h.attr({shape:u})}var a=this,o=t.get("type"),s="cross"!==o,c=e.getRect(),u=[c.y,c.y+c[fe]];r(i,n,u)},_showPolarPointer:function(t,e,i,r){function a(i,n,r){var a,o=e.pointToCoord(n);if("angle"===i){var c=e.coordToPoint([r[0],o[1]]),u=e.coordToPoint([r[1],o[1]]);a=l(c[0],c[1],u[0],u[1])}else a={cx:e.cx,cy:e.cy,r:o[0]};var h=s._getPointerElement(e,t,i,a);d?A[g](h,{shape:a},t):h.attr({shape:a})}function o(i,n,r){var a,o=e.getAxis(i),l=o.getBandWidth(),c=e.pointToCoord(n),u=Math.PI/180;a="angle"===i?f(e.cx,e.cy,r[0],r[1],(-c[1]-l/2)*u,(-c[1]+l/2)*u):f(e.cx,e.cy,c[0]-l/2,c[0]+l/2,0,2*Math.PI);var h=s._getPointerElement(e,t,i,a);d?A[g](h,{shape:a},t):h.attr({shape:a})}var s=this,c=t.get("type"),u=e.getAngleAxis(),h=e.getRadiusAxis(),d="cross"!==c;if("cross"===c)a("angle",r,h[k]()),a(n,r,u[k]()),this._updateCrossText(e,r,t);else{var p=e.getAxis(i===n?"angle":n),v=p[k]();("line"===c?a:o)(i,r,v)}},_updateCrossText:function(t,e,i){var n=i[ye]("crossStyle"),r=n[ye](G),a=this._tooltipModel,o=this._crossText;o||(o=this._crossText=new A.Text({style:{textAlign:"left",textVerticalAlign:"bottom"}}),this.group.add(o));var l=t.pointToData(e),u=t[s];l=C.map(l,function(e,i){var n=t.getAxis(u[i]);return e=n.type===c||"time"===n.type?n.scale[I](e):L.addCommas(e.toFixed(n.getPixelPrecision()))}),o.setStyle({fill:r.getTextColor()||n.get("color"),textFont:r[V](),text:l.join(", "),x:e[0]+5,y:e[1]-5}),o.z=a.get("z"),o[Y]=a.get(Y)},_getPointerElement:function(t,e,i,r){var a=this._tooltipModel,o=a.get("z"),s=a.get(Y),l=this._axisPointers,c=t.name;if(l[c]=l[c]||{},l[c][i])return l[c][i];var u=e.get("type"),h=e[ye](u+"Style"),d="shadow"===u,f=h[d?"getAreaStyle":"getLineStyle"](),p="polar"===t.type?d?w:i===n?"Circle":"Line":d?"Rect":"Line";d?f[x]=null:f.fill=null;var g=l[c][i]=new A[p]({style:f,z:o,zlevel:s,silent:!0,shape:r});return this.group.add(g),g},_dispatchAndShowSeriesTooltipContent:function(t,e,i,r,a){var o=this._tooltipModel,s=this._tooltipContent,l=t.getBaseAxis(),c=C.map(e,function(t){return{seriesIndex:t[$],dataIndex:t.getAxisTooltipDataIndex?t.getAxisTooltipDataIndex(t.coordDimToDataDim(l.dim),r,l):t[ie]().indexOfNearest(t.coordDimToDataDim(l.dim)[0],r["x"===l.dim||l.dim===n?0:1])}}),u=this._lastHover,h=this._api;if(u.payloadBatch&&!a&&h.dispatchAction({type:"downplay",batch:u.payloadBatch}),a||(h.dispatchAction({type:"highlight",batch:c}),u.payloadBatch=c),h.dispatchAction({type:"showTip",dataIndex:c[0][K],seriesIndex:c[0][$],from:this.uid}),l&&o.get("showContent")&&o.get("show")){var d,f=o.get("formatter"),p=o.get(R),g=C.map(e,function(t,e){return t[Q](c[e][K])});s.show(o);var v=c[0][K];if(!a){if(this._ticket="",f){if(typeof f===_e)d=L.formatTpl(f,g);else if(typeof f===Z){var m=this,x="axis_"+t.name+"_"+v,_=function(t,e){t===m._ticket&&(s.setContent(e),y(p,i[0],i[1],s,g,null,h))};m._ticket=x,d=f(g,x,_)}}else{var b=e[0][ie]()[T](v);d=(b?b+"<br />":"")+C.map(e,function(t,e){return t.formatTooltip(c[e][K],!0)}).join("<br />")}s.setContent(d)}y(p,i[0],i[1],s,g,null,h)}},_showItemTooltipContent:function(t,e,i,n){var r=this._api,a=t[ie](i),o=a[h](e),s=this._tooltipModel,l=this._tooltipContent,c=o[ye]("tooltip");if(c.parentModel?c.parentModel.parentModel=s:c.parentModel=this._tooltipModel,c.get("showContent")&&c.get("show")){var u,d=c.get("formatter"),f=c.get(R),p=t[Q](e,i);if(d){if(typeof d===_e)u=L.formatTpl(d,p);else if(typeof d===Z){var g=this,v="item_"+t.name+"_"+e,m=function(t,e){t===g._ticket&&(l.setContent(e),y(f,n.offsetX,n.offsetY,l,p,n[J],r))};g._ticket=v,u=d(p,v,m)}}else u=t.formatTooltip(e,!1,i);l.show(c),l.setContent(u),y(f,n.offsetX,n.offsetY,l,p,n[J],r)}},_showAxisPointer:function(t){if(t){var e=this._axisPointers[t];e&&C.each(e,function(t){t.show()})}else this.group.eachChild(function(t){t.show()}),this.group.show()},_resetLastHover:function(){var t=this._lastHover;t.payloadBatch&&this._api.dispatchAction({type:"downplay",batch:t.payloadBatch}),this._lastHover={}},_hideAxisPointer:function(t){if(t){var e=this._axisPointers[t];e&&C.each(e,function(t){t.hide()})}else this.group.hide()},_hide:function(){clearTimeout(this._showTimeout),this._hideAxisPointer(),this._resetLastHover(),this._alwaysShowContent||this._tooltipContent.hideLater(this._tooltipModel.get("hideDelay")),this._api.dispatchAction({type:"hideTip",from:this.uid}),this._lastX=this._lastY=null},dispose:function(t,e){if(!D.node){var i=e.getZr();this._tooltipContent.hide(),i.off("click",this._tryShow),i.off("mousemove",this._mousemove),i.off(te,this._hide),i.off("globalout",this._hide),e.off("showTip",this._manuallyShowTip),e.off("hideTip",this._manuallyHideTip)}}})}),e("zrender/vml/graphic",[Ce,"../core/env","../core/vector","../core/BoundingRect","../core/PathProxy","../tool/color","../contain/text","../graphic/mixin/RectText","../graphic/Displayable","../graphic/Image","../graphic/Text","../graphic/Path","../graphic/Gradient","./core"],function(t){if(!t("../core/env").canvasSupported){var e=t("../core/vector"),i=t("../core/BoundingRect"),n=t("../core/PathProxy").CMD,r=t("../tool/color"),a=t("../contain/text"),o=t("../graphic/mixin/RectText"),s=t("../graphic/Displayable"),l=t("../graphic/Image"),c=t("../graphic/Text"),u=t("../graphic/Path"),h=t("../graphic/Gradient"),d=t("./core"),p=Math.round,g=Math.sqrt,v=Math.abs,m=Math.cos,y=Math.sin,w=Math.max,S=e[b],A=",",C="progid:DXImageTransform.Microsoft",T=21600,L=T/2,P=1e5,z=1e3,k=function(t){t.style.cssText="position:absolute;left:0;top:0;width:1px;height:1px;",t.coordsize=T+","+T,t.coordorigin="0,0"},I=function(t){return String(t)[U](/&/g,"&amp;")[U](/"/g,"&quot;")},D=function(t,e,i){return"rgb("+[t,e,i].join(",")+")"},R=function(t,e){e&&t&&e.parentNode!==t&&t.appendChild(e)},V=function(t,e){e&&t&&e.parentNode===t&&t.removeChild(e)},G=function(t,e,i){return(parseFloat(t)||0)*P+(parseFloat(e)||0)*z+i},H=function(t,e){return typeof t===_e?t.lastIndexOf("%")>=0?parseFloat(t)/100*e:parseFloat(t):t},q=function(t,e,i){var n=r.parse(e);i=+i,isNaN(i)&&(i=1),n&&(t.color=D(n[0],n[1],n[2]),t[O]=i*n[3])},W=function(t){var e=r.parse(t);return[D(e[0],e[1],e[2]),e[3]]},Z=function(t,e,i){var n=e.fill;if(null!=n)if(n instanceof h){var r,a=0,o=[0,0],s=0,l=1,c=i[N](),u=c.width,d=c[fe];if("linear"===n.type){r="gradient";var f=i[Me],p=[n.x*u,n.y*d],g=[n.x2*u,n.y2*d];f&&(S(p,p,f),S(g,g,f));var v=g[0]-p[0],m=g[1]-p[1];a=180*Math.atan2(v,m)/Math.PI,0>a&&(a+=360),1e-6>a&&(a=0)}else{r="gradientradial";var p=[n.x*u,n.y*d],f=i[Me],y=i.scale,x=u,_=d;o=[(p[0]-c.x)/x,(p[1]-c.y)/_],f&&S(p,p,f),x/=y[0]*T,_/=y[1]*T;var b=w(x,_);s=0/b,l=2*n.r/b-s}var M=n.colorStops.slice();M.sort(function(t,e){return t.offset-e.offset});for(var A=M[oe],C=[],L=[],P=0;A>P;P++){var z=M[P],k=W(z.color);L.push(z.offset*l+s+" "+k[0]),(0===P||P===A-1)&&C.push(k)}if(A>=2){var I=C[0][0],D=C[1][0],R=C[0][1]*e[O],B=C[1][1]*e[O];t.type=r,t.method="none",t.focus="100%",t.angle=a,t.color=I,t.color2=D,t.colors=L.join(","),t[O]=B,t.opacity2=R}"radial"===r&&(t.focusposition=o.join(","))}else q(t,n,e[O])},X=function(t,e){null!=e.lineJoin&&(t.joinstyle=e.lineJoin),null!=e.miterLimit&&(t.miterlimit=e.miterLimit*T),null!=e.lineCap&&(t.endcap=e.lineCap),null!=e.lineDash&&(t.dashstyle=e.lineDash.join(" ")),null==e[x]||e[x]instanceof h||q(t,e[x],e[O])},j=function(t,e,i,n){var r="fill"==e,a=t.getElementsByTagName(e)[0];null!=i[e]&&"none"!==i[e]&&(r||!r&&i[_])?(t[r?"filled":"stroked"]="true",i[e]instanceof h&&V(t,a),a||(a=d.createNode(e)),r?Z(a,i,n):X(a,i),R(t,a)):(t[r?"filled":"stroked"]="false",V(t,a))},Q=[[],[],[]],$=function(t,e){var i,r,a,o,s,l,c=n.M,u=n.C,h=n.L,d=n.A,f=n.Q,v=[];for(o=0;o<t[oe];){switch(a=t[o++],r="",i=0,a){case c:r=" m ",i=1,s=t[o++],l=t[o++],Q[0][0]=s,Q[0][1]=l;break;case h:r=" l ",i=1,s=t[o++],l=t[o++],Q[0][0]=s,Q[0][1]=l;break;case f:case u:r=" c ",i=3;var x,_,b=t[o++],w=t[o++],M=t[o++],C=t[o++];a===f?(x=M,_=C,M=(M+2*b)/3,C=(C+2*w)/3,b=(s+2*b)/3,w=(l+2*w)/3):(x=t[o++],_=t[o++]),Q[0][0]=b,Q[0][1]=w,Q[1][0]=M,Q[1][1]=C,Q[2][0]=x,Q[2][1]=_,s=x,l=_;break;case d:var P=0,z=0,k=1,I=1,D=0;e&&(P=e[4],z=e[5],k=g(e[0]*e[0]+e[1]*e[1]),I=g(e[2]*e[2]+e[3]*e[3]),D=Math.atan2(-e[1]/I,e[0]/k));var O=t[o++],R=t[o++],B=t[o++],E=t[o++],N=t[o++]+D,V=t[o++]+N+D;o++;var F=t[o++],G=O+m(N)*B,H=R+y(N)*E,b=O+m(V)*B,w=R+y(V)*E,q=F?" wa ":" at ";Math.abs(G-b)<1e-10&&(Math.abs(V-N)>.01?F&&(G+=270/T):Math.abs(H-R)<1e-10?F&&O>G||!F&&G>O?w-=270/T:w+=270/T:F&&R>H||!F&&H>R?b+=270/T:b-=270/T),v.push(q,p(((O-B)*k+P)*T-L),A,p(((R-E)*I+z)*T-L),A,p(((O+B)*k+P)*T-L),A,p(((R+E)*I+z)*T-L),A,p((G*k+P)*T-L),A,p((H*I+z)*T-L),A,p((b*k+P)*T-L),A,p((w*I+z)*T-L)),s=b,l=w;break;case n.R:var W=Q[0],Z=Q[1];W[0]=t[o++],W[1]=t[o++],Z[0]=W[0]+t[o++],Z[1]=W[1]+t[o++],e&&(S(W,W,e),S(Z,Z,e)),W[0]=p(W[0]*T-L),Z[0]=p(Z[0]*T-L),W[1]=p(W[1]*T-L),Z[1]=p(Z[1]*T-L),v.push(" m ",W[0],A,W[1]," l ",Z[0],A,W[1]," l ",Z[0],A,Z[1]," l ",W[0],A,Z[1]);break;case n.Z:v.push(" x ")}if(i>0){v.push(r);for(var X=0;i>X;X++){var j=Q[X];e&&S(j,j,e),v.push(p(j[0]*T-L),A,p(j[1]*T-L),i-1>X?A:"")}}}return v.join("")};u[be].brushVML=function(t){var e=this.style,i=this._vmlEl;i||(i=d.createNode("shape"),k(i),this._vmlEl=i),j(i,"fill",e,this),j(i,x,e,this);var n=this[Me],r=null!=n,a=i.getElementsByTagName(x)[0];if(a){var o=e[_];if(r&&!e.strokeNoScale){var s=n[0]*n[3]-n[1]*n[2];o*=g(v(s))}a.weight=o+"px"}var l=this.path;this.__dirtyPath&&(l.beginPath(),this.buildPath(l,this.shape),l.toStatic(),this.__dirtyPath=!1),i.path=$(l.data,this[Me]),i.style.zIndex=G(this[Y],this.z,this.z2),R(t,i),e.text?this.drawRectText(t,this[N]()):this.removeRectText(t)},u[be].onRemove=function(t){V(t,this._vmlEl),this.removeRectText(t)},u[be].onAdd=function(t){R(t,this._vmlEl),this.appendRectText(t)};var K=function(t){return"object"==typeof t&&t.tagName&&"IMG"===t.tagName.toUpperCase()};l[be].brushVML=function(t){var e,i,n=this.style,r=n.image;if(K(r)){var a=r.src;if(a===this._imageSrc)e=this._imageWidth,i=this._imageHeight;else{var o=r.runtimeStyle,s=o.width,l=o[fe];o.width="auto",o[fe]="auto",e=r.width,i=r[fe],o.width=s,o[fe]=l,this._imageSrc=a,this._imageWidth=e,this._imageHeight=i}r=a}else r===this._imageSrc&&(e=this._imageWidth,i=this._imageHeight);if(r){var c=n.x||0,u=n.y||0,h=n.width,v=n[fe],m=n.sWidth,y=n.sHeight,x=n.sx||0,_=n.sy||0,b=m&&y,M=this._vmlEl;M||(M=d.doc[f]("div"),k(M),this._vmlEl=M);var T,L=M.style,P=!1,z=1,I=1;if(this[Me]&&(T=this[Me],z=g(T[0]*T[0]+T[1]*T[1]),I=g(T[2]*T[2]+T[3]*T[3]),P=T[1]||T[2]),P){var D=[c,u],B=[c+h,u],E=[c,u+v],V=[c+h,u+v];S(D,D,T),S(B,B,T),S(E,E,T),S(V,V,T);var F=w(D[0],B[0],E[0],V[0]),H=w(D[1],B[1],E[1],V[1]),q=[];q.push("M11=",T[0]/z,A,"M12=",T[2]/I,A,"M21=",T[1]/z,A,"M22=",T[3]/I,A,"Dx=",p(c*z+T[4]),A,"Dy=",p(u*I+T[5])),L.padding="0 "+p(F)+"px "+p(H)+"px 0",L[Se]=C+".Matrix("+q.join("")+", SizingMethod=clip)"}else T&&(c=c*z+T[4],u=u*I+T[5]),L[Se]="",L.left=p(c)+"px",L.top=p(u)+"px";var W=this._imageEl,Z=this._cropEl;W||(W=d.doc[f]("div"),this._imageEl=W);var X=W.style;if(b){if(e&&i)X.width=p(z*e*h/m)+"px",X[fe]=p(I*i*v/y)+"px";else{var j=new Image,U=this;j.onload=function(){j.onload=null,e=j.width,i=j[fe],X.width=p(z*e*h/m)+"px",X[fe]=p(I*i*v/y)+"px",U._imageWidth=e,U._imageHeight=i,U._imageSrc=r},j.src=r}Z||(Z=d.doc[f]("div"),Z.style.overflow="hidden",this._cropEl=Z);var Q=Z.style;Q.width=p((h+x*h/m)*z),Q[fe]=p((v+_*v/y)*I),Q[Se]=C+".Matrix(Dx="+-x*h/m*z+",Dy="+-_*v/y*I+")",Z.parentNode||M.appendChild(Z),W.parentNode!=Z&&Z.appendChild(W)}else X.width=p(z*h)+"px",X[fe]=p(I*v)+"px",M.appendChild(W),Z&&Z.parentNode&&(M.removeChild(Z),this._cropEl=null);var $="",J=n[O];1>J&&($+=".Alpha(opacity="+p(100*J)+") "),$+=C+".AlphaImageLoader(src="+r+", SizingMethod=scale)",X[Se]=$,M.style.zIndex=G(this[Y],this.z,this.z2),R(t,M),n.text&&this.drawRectText(t,this[N]())}},l[be].onRemove=function(t){V(t,this._vmlEl),this._vmlEl=null,this._cropEl=null,this._imageEl=null,this.removeRectText(t)},l[be].onAdd=function(t){R(t,this._vmlEl),this.appendRectText(t)};var J,te=M,ee={},ie=0,ne=100,re=document[f]("div"),ae=function(t){var e=ee[t];if(!e){ie>ne&&(ie=0,ee={});var i,n=re.style;try{n.font=t,i=n.fontFamily.split(",")[0]}catch(r){}e={style:n.fontStyle||te,variant:n.fontVariant||te,weight:n.fontWeight||te,size:0|parseFloat(n.fontSize||12),family:i||"Microsoft YaHei"},ee[t]=e,ie++}return e};a.measureText=function(t,e){var i=d.doc;J||(J=i[f]("div"),J.style.cssText="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;",d.doc.body.appendChild(J));try{J.style.font=e}catch(n){}return J.innerHTML="",J.appendChild(i.createTextNode(t)),{width:J.offsetWidth}};for(var se=new i,le=function(t,e,i,n){var r=this.style,o=r.text;if(o){var s,l,c=r[F],u=ae(r.textFont),h=u.style+" "+u.variant+" "+u.weight+" "+u.size+'px "'+u.family+'"',f=r.textBaseline,g=r.textVerticalAlign;i=i||a[N](o,h,c,f);var v=this[Me];if(v&&!n&&(se.copy(e),se[b](v),e=se),n)s=e.x,l=e.y;else{var m=r.textPosition,y=r.textDistance;if(m instanceof Array)s=e.x+H(m[0],e.width),l=e.y+H(m[1],e[fe]),c=c||"left",f=f||"top";else{var _=a.adjustTextPositionOnRect(m,e,i,y);s=_.x,l=_.y,c=c||_[F],f=f||_.textBaseline}}if(g){switch(g){case E:l-=i[fe]/2;break;case pe:l-=i[fe]}f="top"}var w=u.size;switch(f){case"hanging":case"top":l+=w/1.75;break;case E:break;default:l-=w/2.25}switch(c){case"left":break;case B:s-=i.width/2;break;case"right":s-=i.width}var M,C,T,L=d.createNode,P=this._textVmlEl;P?(T=P.firstChild,M=T.nextSibling,C=M.nextSibling):(P=L("line"),M=L("path"),C=L("textpath"),T=L("skew"),C.style["v-text-align"]="left",k(P),M.textpathok=!0,C.on=!0,P.from="0 0",P.to="1000 0.05",R(P,T),R(P,M),R(P,C),this._textVmlEl=P);var z=[s,l],D=P.style;v&&n?(S(z,z,v),T.on=!0,T.matrix=v[0].toFixed(3)+A+v[2].toFixed(3)+A+v[1].toFixed(3)+A+v[3].toFixed(3)+",0,0",T.offset=(p(z[0])||0)+","+(p(z[1])||0),T.origin="0 0",D.left="0px",D.top="0px"):(T.on=!1,D.left=p(s)+"px",D.top=p(l)+"px"),C[_e]=I(o);try{C.style.font=h}catch(V){}j(P,"fill",{fill:n?r.fill:r.textFill,opacity:r[O]},this),j(P,x,{stroke:n?r[x]:r.textStroke,opacity:r[O],lineDash:r.lineDash},this),P.style.zIndex=G(this[Y],this.z,this.z2),R(t,P)}},ce=function(t){V(t,this._textVmlEl),this._textVmlEl=null},ue=function(t){R(t,this._textVmlEl)},he=[o,s,l,u,c],de=0;de<he[oe];de++){var ge=he[de][be];ge.drawRectText=le,ge.removeRectText=ce,ge.appendRectText=ue}c[be].brushVML=function(t){var e=this.style;e.text?this.drawRectText(t,{x:e.x||0,y:e.y||0,width:0,height:0},this[N](),!0):this.removeRectText(t)},c[be].onRemove=function(t){this.removeRectText(t)},c[be].onAdd=function(t){this.appendRectText(t)}}}),e("echarts/scale/Interval",[Ce,"../util/number","../util/format","./Scale"],function(t){var e=t("../util/number"),i=t("../util/format"),n=t("./Scale"),r=Math.floor,a=Math.ceil,o=n[le]({type:"interval",_interval:0,setExtent:function(t,e){var i=this._extent;isNaN(t)||(i[0]=parseFloat(t)),isNaN(e)||(i[1]=parseFloat(e))},unionExtent:function(t){var e=this._extent;t[0]<e[0]&&(e[0]=t[0]),t[1]>e[1]&&(e[1]=t[1]),o[be].setExtent.call(this,e[0],e[1])},getInterval:function(){return this._interval||this.niceTicks(),this._interval},setInterval:function(t){this._interval=t,this._niceExtent=this._extent.slice()},getTicks:function(){this._interval||this.niceTicks();var t=this._interval,i=this._extent,n=[],r=1e4;if(t){var a=this._niceExtent;i[0]<a[0]&&n.push(i[0]);for(var o=a[0];o<=a[1];)if(n.push(o),o=e.round(o+t),n[oe]>r)return[];i[1]>a[1]&&n.push(i[1])}return n},getTicksLabels:function(){for(var t=[],e=this.getTicks(),i=0;i<e[oe];i++)t.push(this[I](e[i]));return t},getLabel:function(t){return i.addCommas(t)},niceTicks:function(t){t=t||5;var i=this._extent,n=i[1]-i[0];if(isFinite(n)){0>n&&(n=-n,i.reverse());var o=e.nice(n/t,!0),s=[e.round(a(i[0]/o)*o),e.round(r(i[1]/o)*o)];this._interval=o,this._niceExtent=s}},niceExtent:function(t,i,n){var o=this._extent;if(o[0]===o[1])if(0!==o[0]){var s=o[0]/2;o[0]-=s,o[1]+=s}else o[1]=1;var l=o[1]-o[0];isFinite(l)||(o[0]=0,o[1]=1),this.niceTicks(t);var c=this._interval;i||(o[0]=e.round(r(o[0]/c)*c)),n||(o[1]=e.round(a(o[1]/c)*c))}});return o[de]=function(){return new o},o}),e("zrender/vml/Painter",[Ce,"../core/log","./core"],function(t){function e(t){return parseInt(t,10)}function i(t,e){a.initVML(),this.root=t,this.storage=e;var i=document[f]("div"),n=document[f]("div");i.style.cssText="display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;",n.style.cssText="position:absolute;left:0;top:0;",t.appendChild(i),this._vmlRoot=n,this._vmlViewport=i,this[xe]();var r=e.delFromMap,o=e.addToMap;e.delFromMap=function(t){var i=e.get(t);r.call(e,t),i&&i.onRemove&&i.onRemove(n)},e.addToMap=function(t){t.onAdd&&t.onAdd(n),o.call(e,t)},this._firstPaint=!0}function n(t){return function(){r('In IE8.0 VML mode painter not support method "'+t+'"')}}var r=t("../core/log"),a=t("./core");i[be]={constructor:i,getViewportRoot:function(){return this._vmlViewport},refresh:function(){var t=this.storage.getDisplayList(!0,!0);this._paintList(t)},_paintList:function(t){for(var e=this._vmlRoot,i=0;i<t[oe];i++){var n=t[i];n.invisible||n[ge]?(n.__alreadyNotVisible||n.onRemove(e),n.__alreadyNotVisible=!0):(n.__alreadyNotVisible&&n.onAdd(e),n.__alreadyNotVisible=!1,n.__dirty&&(n.beforeBrush&&n.beforeBrush(),(n.brushVML||n.brush).call(n,e),n.afterBrush&&n.afterBrush())),n.__dirty=!1}this._firstPaint&&(this._vmlViewport.appendChild(e),this._firstPaint=!1)},resize:function(){var t=this._getWidth(),e=this._getHeight();if(this._width!=t&&this._height!=e){this._width=t,this._height=e;var i=this._vmlViewport.style;i.width=t+"px",i[fe]=e+"px"}},dispose:function(){this.root.innerHTML="",this._vmlRoot=this._vmlViewport=this.storage=null},getWidth:function(){return this._width},getHeight:function(){return this._height},_getWidth:function(){var t=this.root,i=t.currentStyle;return(t.clientWidth||e(i.width))-e(i.paddingLeft)-e(i.paddingRight)|0},_getHeight:function(){var t=this.root,i=t.currentStyle;return(t.clientHeight||e(i[fe]))-e(i.paddingTop)-e(i.paddingBottom)|0}};for(var o=["getLayer","insertLayer","eachLayer","eachBuildinLayer","eachOtherLayer","getLayers","modLayer","delLayer","clearLayer","toDataURL","pathToImage"],s=0;s<o[oe];s++){var l=o[s];i[be][l]=n(l)}return i}),e("echarts/scale/Scale",[Ce,"../util/clazz"],function(t){function e(){this._extent=[1/0,-1/0],this._interval=0,this.init&&this.init.apply(this,arguments)}var i=t("../util/clazz"),n=e[be];return n.parse=function(t){return t},n[D]=function(t){var e=this._extent;return t>=e[0]&&t<=e[1]},n.normalize=function(t){var e=this._extent;return e[1]===e[0]?.5:(t-e[0])/(e[1]-e[0])},n.scale=function(t){var e=this._extent;return t*(e[1]-e[0])+e[0]},n.unionExtent=function(t){var e=this._extent;t[0]<e[0]&&(e[0]=t[0]),t[1]>e[1]&&(e[1]=t[1])},n[k]=function(){return this._extent.slice()},n.setExtent=function(t,e){var i=this._extent;isNaN(t)||(i[0]=t),isNaN(e)||(i[1]=e)},n.getTicksLabels=function(){for(var t=[],e=this.getTicks(),i=0;i<e[oe];i++)t.push(this[I](e[i]));return t},i.enableClassExtend(e),i.enableClassManagement(e,{registerWhenExtend:!0}),e}),e("echarts/util/model",[Ce,"./format","./number",Ae],function(t){var e=t("./format"),i=t("./number"),r=t(Ae),a=["x","y","z",n,"angle"],o={};return o.createNameEach=function(t,e){t=t.slice();var i=r.map(t,o.capitalFirst);e=(e||[]).slice();var n=r.map(e,o.capitalFirst);return function(a,o){r.each(t,function(t,r){for(var s={name:t,capital:i[r]},l=0;l<e[oe];l++)s[e[l]]=t+n[l];a.call(o,s)})}},o.capitalFirst=function(t){return t?t.charAt(0).toUpperCase()+t.substr(1):t},o.eachAxisDim=o.createNameEach(a,["axisIndex","axis","index"]),o.normalizeToArray=function(t){return r[j](t)?t:null==t?[]:[t]},o.createLinkedNodesFinder=function(t,e,i){function n(t,e){return r[X](e.nodes,t)>=0}function a(t,n){var a=!1;return e(function(e){r.each(i(t,e)||[],function(t){n.records[e.name][t]&&(a=!0)})}),a}function o(t,n){n.nodes.push(t),e(function(e){r.each(i(t,e)||[],function(t){n.records[e.name][t]=!0})})}return function(i){function r(t){!n(t,s)&&a(t,s)&&(o(t,s),l=!0)}var s={nodes:[],records:{}};if(e(function(t){s.records[t.name]={}}),!i)return s;o(i,s);var l;do l=!1,t(r);while(l);return s}},o.defaultEmphasis=function(t,e){if(t){var i=t[A]=t[A]||{},n=t[M]=t[M]||{};r.each(e,function(t){var e=r.retrieve(i[t],n[t]);null!=e&&(i[t]=e)})}},o.LABEL_OPTIONS=[R,"show",G,"distance","formatter"],o.getDataItemValue=function(t){return t&&(null==t.value?t:t.value)},o.converDataValue=function(t,e){var n=e&&e.type;return n===l?t:("time"!==n||isFinite(t)||null==t||"-"===t||(t=+i.parseDate(t)),null==t||""===t?0/0:+t)},o.dataFormatMixin={getDataParams:function(t,e){var i=this[ie](e),n=this[$],r=this.name,a=this.getRawValue(t,e),o=i.getRawIndex(t),s=i[T](t,!0),l=i.getRawDataItem(t);return{componentType:this.mainType,componentSubType:this.subType,seriesType:this.mainType===re?this.subType:null,seriesIndex:n,seriesName:r,name:s,dataIndex:o,data:l,dataType:e,value:a,color:i[C](t,"color"),$vars:["seriesName","name","value"]}},getFormattedLabel:function(t,i,n,a){i=i||M;var o=this[ie](n),s=o[h](t),l=this[Q](t,n);null!=a&&r[j](l.value)&&(l.value=l.value[a]);var c=s.get(["label",i,"formatter"]);return typeof c===Z?(l.status=i,c(l)):typeof c===_e?e.formatTpl(c,l):void 0},getRawValue:function(t,e){var i=this[ie](e),n=i.getRawDataItem(t);return null!=n?r[ue](n)&&!r[j](n)?n.value:n:void 0},formatTooltip:r.noop},o.mappingToExists=function(t,e){e=(e||[]).slice();var i=r.map(t||[],function(t){return{exist:t}});return r.each(e,function(t,n){if(r[ue](t))for(var a=0;a<i[oe];a++){var s=i[a].exist;if(!i[a][z]&&(null!=t.id&&s.id===t.id+""||null!=t.name&&!o.isIdInner(t)&&!o.isIdInner(s)&&s.name===t.name+"")){i[a][z]=t,e[n]=null;break}}}),r.each(e,function(t){if(r[ue](t)){for(var e=0;e<i[oe];e++){var n=i[e].exist;if(!i[e][z]&&!o.isIdInner(n)&&null==t.id){i[e][z]=t;break}}e>=i[oe]&&i.push({option:t})}}),i},o.isIdInner=function(t){return r[ue](t)&&t.id&&0===(t.id+"")[X]("\x00_ec_\x00")},o}),e("echarts/model/Model",[Ce,Ae,"../util/clazz","./mixin/lineStyle","./mixin/areaStyle","./mixin/textStyle","./mixin/itemStyle"],function(t){function e(t,e,i,n){this.parentModel=e,this[L]=i,this[z]=t,this.init&&(arguments[oe]<=4?this.init(t,e,i,n):this.init.apply(this,arguments))}var i=t(Ae),n=t("../util/clazz");e[be]={constructor:e,init:null,mergeOption:function(t){i.merge(this[z],t,!0)},get:function(t,e){if(!t)return this[z];typeof t===_e&&(t=t.split("."));for(var i=this[z],n=this.parentModel,r=0;r<t[oe]&&(!t[r]||(i=i&&"object"==typeof i?i[t[r]]:null,null!=i));r++);return null==i&&n&&!e&&(i=n.get(t)),i},getShallow:function(t,e){var i=this[z],n=i&&i[t],r=this.parentModel;return null==n&&r&&!e&&(n=r[y](t)),n},getModel:function(t,i){var n=this.get(t,!0),r=this.parentModel,a=new e(n,i||r&&r[ye](t),this[L]);return a},isEmpty:function(){return null==this[z]},restoreData:function(){},clone:function(){var t=this.constructor;return new t(i.clone(this[z]))},setReadOnly:function(t){n.setReadOnly(this,t)}},n.enableClassExtend(e);var r=i.mixin;return r(e,t("./mixin/lineStyle")),r(e,t("./mixin/areaStyle")),r(e,t("./mixin/textStyle")),r(e,t("./mixin/itemStyle")),e}),e("echarts/model/globalDefault",[],function(){var t="";return typeof navigator!==p&&(t=navigator.platform||""),{color:["#c23531","#2f4554","#61a0a8","#d48265","#91c7ae","#749f83","#ca8622","#bda29a","#6e7074","#546570","#c4ccd3"],grid:{},textStyle:{fontFamily:t.match(/^Win/)?"Microsoft YaHei":"sans-serif",fontSize:12,fontStyle:"normal",fontWeight:"normal"},animation:!0,animationThreshold:2e3,animationDuration:1e3,animationDurationUpdate:300,animationEasing:"exponentialOut",animationEasingUpdate:"cubicOut"}}),e("zrender/tool/path",[Ce,"../graphic/Path","../core/PathProxy","./transformPath","../core/matrix"],function(t){function e(t,e,i,n,r,a,o,s,l,f,v){var m=l*(d/180),y=h(m)*(t-i)/2+u(m)*(e-n)/2,x=-1*u(m)*(t-i)/2+h(m)*(e-n)/2,_=y*y/(o*o)+x*x/(s*s);_>1&&(o*=c(_),s*=c(_));var b=(r===a?-1:1)*c((o*o*s*s-o*o*x*x-s*s*y*y)/(o*o*x*x+s*s*y*y))||0,w=b*o*x/s,S=b*-s*y/o,M=(t+i)/2+h(m)*w-u(m)*S,A=(e+n)/2+u(m)*w+h(m)*S,C=g([1,0],[(y-w)/o,(x-S)/s]),T=[(y-w)/o,(x-S)/s],L=[(-1*y-w)/o,(-1*x-S)/s],P=g(T,L);p(T,L)<=-1&&(P=d),p(T,L)>=1&&(P=0),0===a&&P>0&&(P-=2*d),1===a&&0>P&&(P+=2*d),v.addData(f,M,A,o,s,C,P,m,a)}function i(t){if(!t)return[];var i,n=t[U](/-/g," -")[U](/  /g," ")[U](/ /g,",")[U](/,,/g,",");for(i=0;i<l[oe];i++)n=n[U](new RegExp(l[i],"g"),"|"+l[i]);var r,o=n.split("|"),s=0,c=0,u=new a,h=a.CMD;for(i=1;i<o[oe];i++){var d,f=o[i],p=f.charAt(0),g=0,v=f.slice(1)[U](/e,-/g,"e-").split(",");v[oe]>0&&""===v[0]&&v.shift();for(var m=0;m<v[oe];m++)v[m]=parseFloat(v[m]);for(;g<v[oe]&&!isNaN(v[g])&&!isNaN(v[0]);){var y,x,_,b,w,S,M,A=s,C=c;switch(p){case"l":s+=v[g++],c+=v[g++],d=h.L,u.addData(d,s,c);break;case"L":s=v[g++],c=v[g++],d=h.L,u.addData(d,s,c);break;case"m":s+=v[g++],c+=v[g++],d=h.M,u.addData(d,s,c),p="l";break;case"M":s=v[g++],c=v[g++],d=h.M,u.addData(d,s,c),p="L";break;case"h":s+=v[g++],d=h.L,u.addData(d,s,c);break;case"H":s=v[g++],d=h.L,u.addData(d,s,c);break;case"v":c+=v[g++],d=h.L,u.addData(d,s,c);break;case"V":c=v[g++],d=h.L,u.addData(d,s,c);break;case"C":d=h.C,u.addData(d,v[g++],v[g++],v[g++],v[g++],v[g++],v[g++]),s=v[g-2],c=v[g-1];break;case"c":d=h.C,u.addData(d,v[g++]+s,v[g++]+c,v[g++]+s,v[g++]+c,v[g++]+s,v[g++]+c),s+=v[g-2],c+=v[g-1];break;case"S":y=s,x=c;var T=u.len(),L=u.data;r===h.C&&(y+=s-L[T-4],x+=c-L[T-3]),d=h.C,A=v[g++],C=v[g++],s=v[g++],c=v[g++],u.addData(d,y,x,A,C,s,c);break;case"s":y=s,x=c;var T=u.len(),L=u.data;r===h.C&&(y+=s-L[T-4],x+=c-L[T-3]),d=h.C,A=s+v[g++],C=c+v[g++],s+=v[g++],c+=v[g++],u.addData(d,y,x,A,C,s,c);break;case"Q":A=v[g++],C=v[g++],s=v[g++],c=v[g++],d=h.Q,u.addData(d,A,C,s,c);break;case"q":A=v[g++]+s,C=v[g++]+c,s+=v[g++],c+=v[g++],d=h.Q,u.addData(d,A,C,s,c);break;case"T":y=s,x=c;var T=u.len(),L=u.data;r===h.Q&&(y+=s-L[T-4],x+=c-L[T-3]),s=v[g++],c=v[g++],d=h.Q,u.addData(d,y,x,s,c);break;case"t":y=s,x=c;var T=u.len(),L=u.data;r===h.Q&&(y+=s-L[T-4],x+=c-L[T-3]),s+=v[g++],c+=v[g++],d=h.Q,u.addData(d,y,x,s,c);break;case"A":_=v[g++],b=v[g++],w=v[g++],S=v[g++],M=v[g++],A=s,C=c,s=v[g++],c=v[g++],d=h.A,e(A,C,s,c,S,M,_,b,w,d,u);break;case"a":_=v[g++],b=v[g++],w=v[g++],S=v[g++],M=v[g++],A=s,C=c,s+=v[g++],c+=v[g++],d=h.A,e(A,C,s,c,S,M,_,b,w,d,u)}}("z"===p||"Z"===p)&&(d=h.Z,u.addData(d)),r=d}return u.toStatic(),u}function n(t,e){var n,r=i(t);return e=e||{},e.buildPath=function(t){t.setData(r.data),n&&o(t,n);var e=t.getContext();e&&t.rebuildPath(e)},e[b]=function(t){n||(n=s[de]()),s.mul(n,t,n)},e}var r=t("../graphic/Path"),a=t("../core/PathProxy"),o=t("./transformPath"),s=t("../core/matrix"),l=["m","M","l","L","v","V","h","H","z","Z","c","C","q","Q","t","T","s","S","a","A"],c=Math.sqrt,u=Math.sin,h=Math.cos,d=Math.PI,f=function(t){return Math.sqrt(t[0]*t[0]+t[1]*t[1])},p=function(t,e){return(t[0]*e[0]+t[1]*e[1])/(f(t)*f(e))},g=function(t,e){return(t[0]*e[1]<t[1]*e[0]?-1:1)*Math.acos(p(t,e))
+};return{createFromString:function(t,e){return new r(n(t,e))},extendFromString:function(t,e){return r[le](n(t,e))},mergePath:function(t,e){var i,n,a=[],o=t[oe];for(n=0;o>n;n++)i=t[n],i.__dirty&&i.buildPath(i.path,i.shape),a.push(i.path);var s=new r(e);return s.buildPath=function(t){t.appendPath(a);var e=t.getContext();e&&t.rebuildPath(e)},s}}}),e("zrender/graphic/Path",[Ce,"./Displayable",d,"../core/PathProxy","../contain/path","./Gradient"],function(t){function e(t){var e=t.fill;return null!=e&&"none"!==e}function i(t){var e=t[x];return null!=e&&"none"!==e&&t[_]>0}function n(t){r.call(this,t),this.path=new o}var r=t("./Displayable"),a=t(d),o=t("../core/PathProxy"),s=t("../contain/path"),l=(t("./Gradient"),Math.abs);return n[be]={constructor:n,type:"path",__dirtyPath:!0,strokeContainThreshold:5,brush:function(t){t.save();var n=this.style,r=this.path,a=i(n),o=e(n),s=o&&!!n.fill.colorStops,l=a&&!!n[x].colorStops;if(n.bind(t,this),this.setTransform(t),this.__dirtyPath){var c=this[N]();s&&(this._fillGradient=n.getGradient(t,n.fill,c)),l&&(this._strokeGradient=n.getGradient(t,n[x],c))}s&&(t.fillStyle=this._fillGradient),l&&(t.strokeStyle=this._strokeGradient);var u=n.lineDash,h=n.lineDashOffset,d=!!t.setLineDash,f=this.getGlobalScale();r.setScale(f[0],f[1]),this.__dirtyPath||u&&!d&&a?(r=this.path.beginPath(t),u&&!d&&(r.setLineDash(u),r.setLineDashOffset(h)),this.buildPath(r,this.shape),this.__dirtyPath=!1):(t.beginPath(),this.path.rebuildPath(t)),o&&r.fill(t),u&&d&&(t.setLineDash(u),t.lineDashOffset=h),a&&r[x](t),null!=n.text&&this.drawRectText(t,this[N]()),t.restore()},buildPath:function(){},getBoundingRect:function(){var t=this._rect,n=this.style,r=!t;if(r){var a=this.path;this.__dirtyPath&&(a.beginPath(),this.buildPath(a,this.shape)),t=a[N]()}if(this._rect=t,i(n)){var o=this._rectWithStroke||(this._rectWithStroke=t.clone());if(this.__dirty||r){o.copy(t);var s=n[_],l=n.strokeNoScale?this.getLineScale():1;e(n)||(s=Math.max(s,this.strokeContainThreshold)),l>1e-10&&(o.width+=s/l,o[fe]+=s/l,o.x-=s/l/2,o.y-=s/l/2)}return o}return t},contain:function(t,n){var r=this.transformCoordToLocal(t,n),a=this[N](),o=this.style;if(t=r[0],n=r[1],a[D](t,n)){var l=this.path.data;if(i(o)){var c=o[_],u=o.strokeNoScale?this.getLineScale():1;if(u>1e-10&&(e(o)||(c=Math.max(c,this.strokeContainThreshold)),s.containStroke(l,c/u,t,n)))return!0}if(e(o))return s[D](l,t,n)}return!1},dirty:function(t){0===arguments[oe]&&(t=!0),t&&(this.__dirtyPath=t,this._rect=null),this.__dirty=!0,this.__zr&&this.__zr.refresh(),this.__clipTarget&&this.__clipTarget.dirty()},animateShape:function(t){return this.animate("shape",t)},attrKV:function(t,e){"shape"===t?this.setShape(e):r[be].attrKV.call(this,t,e)},setShape:function(t,e){var i=this.shape;if(i){if(a[ue](t))for(var n in t)i[n]=t[n];else i[t]=e;this.dirty(!0)}return this},getLineScale:function(){var t=this[Me];return t&&l(t[0]-1)>1e-10&&l(t[3]-1)>1e-10?Math.sqrt(l(t[0]*t[3]-t[2]*t[1])):1}},n[le]=function(t){var e=function(e){n.call(this,e),t.style&&this.style.extendFrom(t.style,!1);var i=t.shape;if(i){this.shape=this.shape||{};var r=this.shape;for(var a in i)!r.hasOwnProperty(a)&&i.hasOwnProperty(a)&&(r[a]=i[a])}t.init&&t.init.call(this,e)};a[W](e,n);for(var i in t)"style"!==i&&"shape"!==i&&(e[be][i]=t[i]);return e},a[W](n,r),n}),e("zrender/graphic/Gradient",[Ce],function(){var t=function(t){this.colorStops=t||[]};return t[be]={constructor:t,addColorStop:function(t,e){this.colorStops.push({offset:t,color:e})}},t}),e("zrender/container/Group",[Ce,d,"../Element","../core/BoundingRect"],function(t){var e=t(d),i=t("../Element"),n=t("../core/BoundingRect"),r=function(t){t=t||{},i.call(this,t);for(var e in t)this[e]=t[e];this._children=[],this.__storage=null,this.__dirty=!0};return r[be]={constructor:r,type:"group",silent:!1,children:function(){return this._children.slice()},childAt:function(t){return this._children[t]},childOfName:function(t){for(var e=this._children,i=0;i<e[oe];i++)if(e[i].name===t)return e[i]},childCount:function(){return this._children[oe]},add:function(t){return t&&t!==this&&t.parent!==this&&(this._children.push(t),this._doAdd(t)),this},addBefore:function(t,e){if(t&&t!==this&&t.parent!==this&&e&&e.parent===this){var i=this._children,n=i[X](e);n>=0&&(i[ne](n,0,t),this._doAdd(t))}return this},_doAdd:function(t){t.parent&&t.parent[ce](t),t.parent=this;var e=this.__storage,i=this.__zr;e&&e!==t.__storage&&(e.addToMap(t),t instanceof r&&t.addChildrenToStorage(e)),i&&i.refresh()},remove:function(t){var i=this.__zr,n=this.__storage,a=this._children,o=e[X](a,t);return 0>o?this:(a[ne](o,1),t.parent=null,n&&(n.delFromMap(t.id),t instanceof r&&t.delChildrenFromStorage(n)),i&&i.refresh(),this)},removeAll:function(){var t,e,i=this._children,n=this.__storage;for(e=0;e<i[oe];e++)t=i[e],n&&(n.delFromMap(t.id),t instanceof r&&t.delChildrenFromStorage(n)),t.parent=null;return i[oe]=0,this},eachChild:function(t,e){for(var i=this._children,n=0;n<i[oe];n++){var r=i[n];t.call(e,r,n)}return this},traverse:function(t,e){for(var i=0;i<this._children[oe];i++){var n=this._children[i];t.call(e,n),"group"===n.type&&n.traverse(t,e)}return this},addChildrenToStorage:function(t){for(var e=0;e<this._children[oe];e++){var i=this._children[e];t.addToMap(i),i instanceof r&&i.addChildrenToStorage(t)}},delChildrenFromStorage:function(t){for(var e=0;e<this._children[oe];e++){var i=this._children[e];t.delFromMap(i.id),i instanceof r&&i.delChildrenFromStorage(t)}},dirty:function(){return this.__dirty=!0,this.__zr&&this.__zr.refresh(),this},getBoundingRect:function(t){for(var e=null,i=new n(0,0,0,0),r=t||this._children,a=[],o=0;o<r[oe];o++){var s=r[o];if(!s[ge]&&!s.invisible){var l=s[N](),c=s.getLocalTransform(a);c?(i.copy(l),i[b](c),e=e||i.clone(),e.union(i)):(e=e||l.clone(),e.union(l))}}return e||i}},e[W](r,i),r}),e("zrender/graphic/Image",[Ce,"./Displayable","../core/BoundingRect",d,"./helper/roundRect","../core/LRU"],function(t){function e(t){i.call(this,t)}var i=t("./Displayable"),n=t("../core/BoundingRect"),r=t(d),a=t("./helper/roundRect"),o=t("../core/LRU"),s=new o(50);return e[be]={constructor:e,type:"image",brush:function(t){var e,i=this.style,n=i.image;if(e=typeof n===_e?this._image:n,!e&&n){var r=s.get(n);if(!r)return e=new Image,e.onload=function(){e.onload=null;for(var t=0;t<r.pending[oe];t++)r.pending[t].dirty()},r={image:e,pending:[this]},e.src=n,s.put(n,r),void(this._image=e);if(e=r.image,this._image=e,!e.width||!e[fe])return void r.pending.push(this)}if(e){var o=i.width||e.width,l=i[fe]||e[fe],c=i.x||0,u=i.y||0;if(!e.width||!e[fe])return;if(t.save(),i.bind(t),this.setTransform(t),i.r&&(t.beginPath(),a.buildPath(t,i),t.clip()),i.sWidth&&i.sHeight){var h=i.sx||0,d=i.sy||0;t.drawImage(e,h,d,i.sWidth,i.sHeight,c,u,o,l)}else if(i.sx&&i.sy){var h=i.sx,d=i.sy,f=o-h,p=l-d;t.drawImage(e,h,d,f,p,c,u,o,l)}else t.drawImage(e,c,u,o,l);null==i.width&&(i.width=o),null==i[fe]&&(i[fe]=l),null!=i.text&&this.drawRectText(t,this[N]()),t.restore()}},getBoundingRect:function(){var t=this.style;return this._rect||(this._rect=new n(t.x||0,t.y||0,t.width||0,t[fe]||0)),this._rect}},r[W](e,i),e}),e("zrender/graphic/Text",[Ce,"./Displayable",d,"../contain/text"],function(t){var e=t("./Displayable"),i=t(d),n=t("../contain/text"),r=function(t){e.call(this,t)};return r[be]={constructor:r,type:"text",brush:function(t){var e=this.style,i=e.x||0,r=e.y||0,a=e.text,o=e.fill,s=e[x];if(null!=a&&(a+=""),a){if(t.save(),this.style.bind(t),this.setTransform(t),o&&(t.fillStyle=o),s&&(t.strokeStyle=s),t.font=e.textFont||e.font,t[F]=e[F],e.textVerticalAlign){var l=n[N](a,t.font,e[F],"top");switch(t.textBaseline=E,e.textVerticalAlign){case E:r-=l[fe]/2-l.lineHeight/2;break;case pe:r-=l[fe]-l.lineHeight/2;break;default:r+=l.lineHeight/2}}else t.textBaseline=e.textBaseline;for(var c=n.measureText("国",t.font).width,u=a.split("\n"),h=0;h<u[oe];h++)o&&t.fillText(u[h],i,r),s&&t.strokeText(u[h],i,r),r+=c;t.restore()}},getBoundingRect:function(){if(!this._rect){var t=this.style,e=t.textVerticalAlign,i=n[N](t.text+"",t.textFont||t.font,t[F],e?"top":t.textBaseline);switch(e){case E:i.y-=i[fe]/2;break;case pe:i.y-=i[fe]}i.x+=t.x||0,i.y+=t.y||0,this._rect=i}return this._rect}},i[W](r,e),r}),e("zrender/graphic/shape/Circle",[Ce,"../Path"],function(t){return t("../Path")[le]({type:"circle",shape:{cx:0,cy:0,r:0},buildPath:function(t,e){t[i](e.cx+e.r,e.cy),t.arc(e.cx,e.cy,e.r,0,2*Math.PI,!0)}})}),e("zrender/graphic/shape/Sector",[Ce,"../Path"],function(t){return t("../Path")[le]({type:"sector",shape:{cx:0,cy:0,r0:0,r:0,startAngle:0,endAngle:2*Math.PI,clockwise:!0},buildPath:function(t,e){var n=e.cx,r=e.cy,a=Math.max(e.r0||0,0),o=Math.max(e.r,0),s=e.startAngle,l=e.endAngle,c=e.clockwise,u=Math.cos(s),h=Math.sin(s);t[i](u*a+n,h*a+r),t.lineTo(u*o+n,h*o+r),t.arc(n,r,o,s,l,!c),t.lineTo(Math.cos(l)*a+n,Math.sin(l)*a+r),0!==a&&t.arc(n,r,a,l,s,c),t.closePath()}})}),e("zrender/graphic/shape/Ring",[Ce,"../Path"],function(t){return t("../Path")[le]({type:"ring",shape:{cx:0,cy:0,r:0,r0:0},buildPath:function(t,e){var n=e.cx,r=e.cy,a=2*Math.PI;t[i](n+e.r,r),t.arc(n,r,e.r,0,a,!1),t[i](n+e.r0,r),t.arc(n,r,e.r0,0,a,!0)}})}),e("zrender/graphic/shape/Polygon",[Ce,"../helper/poly","../Path"],function(t){var e=t("../helper/poly");return t("../Path")[le]({type:"polygon",shape:{points:null,smooth:!1,smoothConstraint:null},buildPath:function(t,i){e.buildPath(t,i,!0)}})}),e("zrender/graphic/shape/Polyline",[Ce,"../helper/poly","../Path"],function(t){var e=t("../helper/poly");return t("../Path")[le]({type:"polyline",shape:{points:null,smooth:!1,smoothConstraint:null},style:{stroke:"#000",fill:null},buildPath:function(t,i){e.buildPath(t,i,!1)}})}),e("zrender/graphic/shape/Rect",[Ce,"../helper/roundRect","../Path"],function(t){var e=t("../helper/roundRect");return t("../Path")[le]({type:"rect",shape:{r:0,x:0,y:0,width:0,height:0},buildPath:function(t,i){var n=i.x,r=i.y,a=i.width,o=i[fe];i.r?e.buildPath(t,i):t.rect(n,r,a,o),t.closePath()}})}),e("zrender/graphic/shape/Line",[Ce,"../Path"],function(t){return t("../Path")[le]({type:"line",shape:{x1:0,y1:0,x2:0,y2:0,percent:1},style:{stroke:"#000",fill:null},buildPath:function(t,e){var n=e.x1,r=e.y1,a=e.x2,o=e.y2,s=e.percent;0!==s&&(t[i](n,r),1>s&&(a=n*(1-s)+a*s,o=r*(1-s)+o*s),t.lineTo(a,o))},pointAt:function(t){var e=this.shape;return[e.x1*(1-t)+e.x2*t,e.y1*(1-t)+e.y2*t]}})}),e("zrender/graphic/shape/BezierCurve",[Ce,"../../core/curve","../../core/vector","../Path"],function(t){function e(t,e,i){var n=t.cpx2,r=t.cpy2;return null===n||null===r?[(i?u:l)(t.x1,t.cpx1,t.cpx2,t.x2,e),(i?u:l)(t.y1,t.cpy1,t.cpy2,t.y2,e)]:[(i?c:s)(t.x1,t.cpx1,t.x2,e),(i?c:s)(t.y1,t.cpy1,t.y2,e)]}var n=t("../../core/curve"),r=t("../../core/vector"),a=n.quadraticSubdivide,o=n.cubicSubdivide,s=n.quadraticAt,l=n.cubicAt,c=n.quadraticDerivativeAt,u=n.cubicDerivativeAt,h=[];return t("../Path")[le]({type:"bezier-curve",shape:{x1:0,y1:0,x2:0,y2:0,cpx1:0,cpy1:0,percent:1},style:{stroke:"#000",fill:null},buildPath:function(t,e){var n=e.x1,r=e.y1,s=e.x2,l=e.y2,c=e.cpx1,u=e.cpy1,d=e.cpx2,f=e.cpy2,p=e.percent;0!==p&&(t[i](n,r),null==d||null==f?(1>p&&(a(n,c,s,p,h),c=h[1],s=h[2],a(r,u,l,p,h),u=h[1],l=h[2]),t.quadraticCurveTo(c,u,s,l)):(1>p&&(o(n,c,d,s,p,h),c=h[1],d=h[2],s=h[3],o(r,u,f,l,p,h),u=h[1],f=h[2],l=h[3]),t.bezierCurveTo(c,u,d,f,s,l)))},pointAt:function(t){return e(this.shape,t,!1)},tangentAt:function(t){var i=e(this.shape,t,!0);return r.normalize(i,i)}})}),e("zrender/graphic/shape/Arc",[Ce,"../Path"],function(t){return t("../Path")[le]({type:"arc",shape:{cx:0,cy:0,r:0,startAngle:0,endAngle:2*Math.PI,clockwise:!0},style:{stroke:"#000",fill:null},buildPath:function(t,e){var n=e.cx,r=e.cy,a=Math.max(e.r,0),o=e.startAngle,s=e.endAngle,l=e.clockwise,c=Math.cos(o),u=Math.sin(o);t[i](c*a+n,u*a+r),t.arc(n,r,a,o,s,!l)}})}),e("zrender/graphic/CompoundPath",[Ce,"./Path"],function(t){var e=t("./Path");return e[le]({type:"compound",shape:{paths:null},_updatePathDirty:function(){for(var t=this.__dirtyPath,e=this.shape.paths,i=0;i<e[oe];i++)t=t||e[i].__dirtyPath;this.__dirtyPath=t,this.__dirty=this.__dirty||t},beforeBrush:function(){this._updatePathDirty();for(var t=this.shape.paths||[],e=this.getGlobalScale(),i=0;i<t[oe];i++)t[i].path.setScale(e[0],e[1])},buildPath:function(t,e){for(var i=e.paths||[],n=0;n<i[oe];n++)i[n].buildPath(t,i[n].shape)},afterBrush:function(){for(var t=this.shape.paths,e=0;e<t[oe];e++)t[e].__dirtyPath=!1},getBoundingRect:function(){return this._updatePathDirty(),e[be][N].call(this)}})}),e("zrender/graphic/LinearGradient",[Ce,d,"./Gradient"],function(t){var e=t(d),i=t("./Gradient"),n=function(t,e,n,r,a){this.x=null==t?0:t,this.y=null==e?0:e,this.x2=null==n?1:n,this.y2=null==r?0:r,i.call(this,a)};return n[be]={constructor:n,type:"linear"},e[W](n,i),n}),e("zrender/core/BoundingRect",[Ce,"./vector","./matrix"],function(t){function e(t,e,i,n){this.x=t,this.y=e,this.width=i,this[fe]=n}var i=t("./vector"),n=t("./matrix"),r=i[b],a=Math.min,o=Math.abs,s=Math.max;return e[be]={constructor:e,union:function(t){var e=a(t.x,this.x),i=a(t.y,this.y);this.width=s(t.x+t.width,this.x+this.width)-e,this[fe]=s(t.y+t[fe],this.y+this[fe])-i,this.x=e,this.y=i},applyTransform:function(){var t=[],e=[];return function(i){i&&(t[0]=this.x,t[1]=this.y,e[0]=this.x+this.width,e[1]=this.y+this[fe],r(t,t,i),r(e,e,i),this.x=a(t[0],e[0]),this.y=a(t[1],e[1]),this.width=o(e[0]-t[0]),this[fe]=o(e[1]-t[1]))}}(),calculateTransform:function(t){var e=this,i=t.width/e.width,r=t[fe]/e[fe],a=n[de]();return n.translate(a,a,[-e.x,-e.y]),n.scale(a,a,[i,r]),n.translate(a,a,[t.x,t.y]),a},intersect:function(t){var e=this,i=e.x,n=e.x+e.width,r=e.y,a=e.y+e[fe],o=t.x,s=t.x+t.width,l=t.y,c=t.y+t[fe];return!(o>n||i>s||l>a||r>c)},contain:function(t,e){var i=this;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i[fe]},clone:function(){return new e(this.x,this.y,this.width,this[fe])},copy:function(t){this.x=t.x,this.y=t.y,this.width=t.width,this[fe]=t[fe]}},e}),e("zrender/graphic/RadialGradient",[Ce,d,"./Gradient"],function(t){var e=t(d),i=t("./Gradient"),n=function(t,e,n,r){this.x=null==t?.5:t,this.y=null==e?.5:e,this.r=null==n?.5:n,i.call(this,r)};return n[be]={constructor:n,type:"radial"},e[W](n,i),n}),e("echarts/coord/polar/Polar",[Ce,"./RadiusAxis","./AngleAxis"],function(t){var e=t("./RadiusAxis"),i=t("./AngleAxis"),r=function(t){this.name=t||"",this.cx=0,this.cy=0,this._radiusAxis=new e,this._angleAxis=new i};return r[be]={constructor:r,type:"polar",dimensions:[n,"angle"],containPoint:function(t){var e=this.pointToCoord(t);return this._radiusAxis[D](e[0])&&this._angleAxis[D](e[1])},containData:function(t){return this._radiusAxis.containData(t[0])&&this._angleAxis.containData(t[1])},getAxis:function(t){return this["_"+t+"Axis"]},getAxesByScale:function(t){var e=[],i=this._angleAxis,n=this._radiusAxis;return i.scale.type===t&&e.push(i),n.scale.type===t&&e.push(n),e},getAngleAxis:function(){return this._angleAxis},getRadiusAxis:function(){return this._radiusAxis},getOtherAxis:function(t){var e=this._angleAxis;return t===e?this._radiusAxis:e},getBaseAxis:function(){return this.getAxesByScale(l)[0]||this.getAxesByScale("time")[0]||this.getAngleAxis()},dataToPoints:function(t){return t.mapArray(this[s],function(t,e){return this[o]([t,e])},this)},dataToPoint:function(t,e){return this.coordToPoint([this._radiusAxis.dataToRadius(t[0],e),this._angleAxis.dataToAngle(t[1],e)])},pointToData:function(t,e){var i=this.pointToCoord(t);return[this._radiusAxis.radiusToData(i[0],e),this._angleAxis.angleToData(i[1],e)]},pointToCoord:function(t){var e=t[0]-this.cx,i=t[1]-this.cy,n=this.getAngleAxis(),r=n[k](),a=Math.min(r[0],r[1]),o=Math.max(r[0],r[1]);n.inverse?a=o-360:o=a+360;var s=Math.sqrt(e*e+i*i);e/=s,i/=s;for(var l=Math.atan2(-i,e)/Math.PI*180,c=a>l?1:-1;a>l||l>o;)l+=360*c;return[s,l]},coordToPoint:function(t){var e=t[0],i=t[1]/180*Math.PI,n=Math.cos(i)*e+this.cx,r=-Math.sin(i)*e+this.cy;return[n,r]}},r}),e("echarts/coord/axisHelper",[Ce,"../scale/Ordinal","../scale/Interval","../scale/Time","../scale/Log","../scale/Scale","../util/number",Ae,"zrender/contain/text"],function(t){var e=t("../scale/Ordinal"),i=t("../scale/Interval");t("../scale/Time"),t("../scale/Log");var n=t("../scale/Scale"),r=t("../util/number"),a=t(Ae),o=t("zrender/contain/text"),s={};return s.getScaleExtent=function(t,e){var i=t.scale,n=i[k](),o=n[1]-n[0];if(i.type===l)return isFinite(o)?n:[0,0];var s=e.getMin?e.getMin():e.get("min"),c=e.getMax?e.getMax():e.get("max"),h=e.getNeedCrossZero?e.getNeedCrossZero():!e.get("scale"),d=e.get("boundaryGap");a[j](d)||(d=[d||0,d||0]),d[0]=r[u](d[0],1),d[1]=r[u](d[1],1);var f=!0,p=!0;return null==s&&(s=n[0]-d[0]*o,f=!1),null==c&&(c=n[1]+d[1]*o,p=!1),"dataMin"===s&&(s=n[0]),"dataMax"===c&&(c=n[1]),h&&(s>0&&c>0&&!f&&(s=0),0>s&&0>c&&!p&&(c=0)),[s,c]},s.niceScaleExtent=function(t,e){var i=t.scale,n=s.getScaleExtent(t,e),r=null!=(e.getMin?e.getMin():e.get("min")),a=null!=(e.getMax?e.getMax():e.get("max")),o=e.get("splitNumber");i.setExtent(n[0],n[1]),i.niceExtent(o,r,a);var l=e.get("minInterval");if(isFinite(l)&&!r&&!a&&"interval"===i.type){var c=i.getInterval(),u=Math.max(Math.abs(c),l)/c;n=i[k](),i.setExtent(u*n[0],n[1]*u),i.niceExtent(o)}var c=e.get("interval");null!=c&&i.setInterval&&i.setInterval(c)},s.createScaleByModel=function(t,r){if(r=r||t.get("type"))switch(r){case c:return new e(t.getCategories(),[1/0,-1/0]);case"value":return new i;default:return(n.getClass(r)||i)[de](t)}},s.ifAxisCrossZero=function(t){var e=t.scale[k](),i=e[0],n=e[1];return!(i>0&&n>0||0>i&&0>n)},s.getAxisLabelInterval=function(t,e,i,n){var r,a=0,s=0,l=1;e[oe]>40&&(l=Math.round(e[oe]/40));for(var c=0;c<t[oe];c+=l){var u=t[c],h=o[N](e[c],i,B,"top");h[n?"x":"y"]+=u,h[n?"width":fe]*=1.5,r?r.intersect(h)?(s++,a=Math.max(a,s)):(r.union(h),s=0):r=h.clone()}return 0===a&&l>1?l:a*l},s.getFormattedLabels=function(t,e){var i=t.scale,n=i.getTicksLabels(),r=i.getTicks();return typeof e===_e?(e=function(t){return function(e){return t[U]("{value}",e)}}(e),a.map(n,e)):typeof e===Z?a.map(r,function(n,r){return e(t.type===c?i[I](n):n,r)},this):n},s}),e("echarts/coord/polar/PolarModel",[Ce,"./AxisModel",r],function(t){t("./AxisModel"),t(r).extendComponentModel({type:"polar",dependencies:["polarAxis","angleAxis"],coordinateSystem:null,findAxisModel:function(t){var e,i=this[L];return i.eachComponent(t,function(t){i[P]("polar",t[y]("polarIndex"))===this&&(e=t)},this),e},defaultOption:{zlevel:0,z:0,center:["50%","50%"],radius:"80%"}})}),e("zrender/core/PathProxy",[Ce,"./curve","./vector","./bbox","./BoundingRect","../config"],function(t){var e=t("./curve"),n=t("./vector"),r=t("./bbox"),a=t("./BoundingRect"),o=t("../config").devicePixelRatio,s={M:1,L:2,C:3,Q:4,A:5,Z:6,R:7},l=[],c=[],u=[],h=[],d=Math.min,f=Math.max,g=Math.cos,v=Math.sin,m=Math.sqrt,y=Math.abs,_=typeof Float32Array!=p,b=function(){this.data=[],this._len=0,this._ctx=null,this._xi=0,this._yi=0,this._x0=0,this._y0=0,this._ux=0,this._uy=0};return b[be]={constructor:b,_lineDash:null,_dashOffset:0,_dashIdx:0,_dashSum:0,setScale:function(t,e){this._ux=y(1/o/t)||0,this._uy=y(1/o/e)||0},getContext:function(){return this._ctx},beginPath:function(t){return this._ctx=t,t&&t.beginPath(),this._len=0,this._lineDash&&(this._lineDash=null,this._dashOffset=0),this},moveTo:function(t,e){return this.addData(s.M,t,e),this._ctx&&this._ctx[i](t,e),this._x0=t,this._y0=e,this._xi=t,this._yi=e,this},lineTo:function(t,e){var i=y(t-this._xi)>this._ux||y(e-this._yi)>this._uy||0===this._len;return this.addData(s.L,t,e),this._ctx&&i&&(this._needsDash()?this._dashedLineTo(t,e):this._ctx.lineTo(t,e)),i&&(this._xi=t,this._yi=e),this},bezierCurveTo:function(t,e,i,n,r,a){return this.addData(s.C,t,e,i,n,r,a),this._ctx&&(this._needsDash()?this._dashedBezierTo(t,e,i,n,r,a):this._ctx.bezierCurveTo(t,e,i,n,r,a)),this._xi=r,this._yi=a,this},quadraticCurveTo:function(t,e,i,n){return this.addData(s.Q,t,e,i,n),this._ctx&&(this._needsDash()?this._dashedQuadraticTo(t,e,i,n):this._ctx.quadraticCurveTo(t,e,i,n)),this._xi=i,this._yi=n,this},arc:function(t,e,i,n,r,a){return this.addData(s.A,t,e,i,i,n,r-n,0,a?0:1),this._ctx&&this._ctx.arc(t,e,i,n,r,a),this._xi=g(r)*i+t,this._xi=v(r)*i+t,this},arcTo:function(t,e,i,n,r){return this._ctx&&this._ctx.arcTo(t,e,i,n,r),this},rect:function(t,e,i,n){return this._ctx&&this._ctx.rect(t,e,i,n),this.addData(s.R,t,e,i,n),this},closePath:function(){this.addData(s.Z);var t=this._ctx,e=this._x0,i=this._y0;return t&&(this._needsDash()&&this._dashedLineTo(e,i),t.closePath()),this._xi=e,this._yi=i,this},fill:function(t){t&&t.fill(),this.toStatic()},stroke:function(t){t&&t[x](),this.toStatic()},setLineDash:function(t){if(t instanceof Array){this._lineDash=t,this._dashIdx=0;for(var e=0,i=0;i<t[oe];i++)e+=t[i];this._dashSum=e}return this},setLineDashOffset:function(t){return this._dashOffset=t,this},len:function(){return this._len},setData:function(t){var e=t[oe];this.data&&this.data[oe]==e||!_||(this.data=new Float32Array(e));for(var i=0;e>i;i++)this.data[i]=t[i];this._len=e},appendPath:function(t){t instanceof Array||(t=[t]);for(var e=t[oe],i=0,n=this._len,r=0;e>r;r++)i+=t[r].len();_&&this.data instanceof Float32Array&&(this.data=new Float32Array(n+i));for(var r=0;e>r;r++)for(var a=t[r].data,o=0;o<a[oe];o++)this.data[n++]=a[o];this._len=n},addData:function(t){var e=this.data;this._len+arguments[oe]>e[oe]&&(this._expandData(),e=this.data);for(var i=0;i<arguments[oe];i++)e[this._len++]=arguments[i];this._prevCmd=t},_expandData:function(){if(!(this.data instanceof Array)){for(var t=[],e=0;e<this._len;e++)t[e]=this.data[e];this.data=t}},_needsDash:function(){return this._lineDash},_dashedLineTo:function(t,e){var n,r,a=this._dashSum,o=this._dashOffset,s=this._lineDash,l=this._ctx,c=this._xi,u=this._yi,h=t-c,p=e-u,g=m(h*h+p*p),v=c,y=u,x=s[oe];for(h/=g,p/=g,0>o&&(o=a+o),o%=a,v-=o*h,y-=o*p;h>=0&&t>=v||0>h&&v>t;)r=this._dashIdx,n=s[r],v+=h*n,y+=p*n,this._dashIdx=(r+1)%x,h>0&&c>v||0>h&&v>c||l[r%2?i:"lineTo"](h>=0?d(v,t):f(v,t),p>=0?d(y,e):f(y,e));h=v-t,p=y-e,this._dashOffset=-m(h*h+p*p)},_dashedBezierTo:function(t,n,r,a,o,s){var l,c,u,h,d,f=this._dashSum,p=this._dashOffset,g=this._lineDash,v=this._ctx,y=this._xi,x=this._yi,_=e.cubicAt,b=0,w=this._dashIdx,S=g[oe],M=0;for(0>p&&(p=f+p),p%=f,l=0;1>l;l+=.1)c=_(y,t,r,o,l+.1)-_(y,t,r,o,l),u=_(x,n,a,s,l+.1)-_(x,n,a,s,l),b+=m(c*c+u*u);for(;S>w&&(M+=g[w],!(M>p));w++);for(l=(M-p)/b;1>=l;)h=_(y,t,r,o,l),d=_(x,n,a,s,l),w%2?v[i](h,d):v.lineTo(h,d),l+=g[w]/b,w=(w+1)%S;w%2!==0&&v.lineTo(o,s),c=o-h,u=s-d,this._dashOffset=-m(c*c+u*u)},_dashedQuadraticTo:function(t,e,i,n){var r=i,a=n;i=(i+2*t)/3,n=(n+2*e)/3,t=(this._xi+2*t)/3,e=(this._yi+2*e)/3,this._dashedBezierTo(t,e,i,n,r,a)},toStatic:function(){var t=this.data;t instanceof Array&&(t[oe]=this._len,_&&(this.data=new Float32Array(t)))},getBoundingRect:function(){l[0]=l[1]=u[0]=u[1]=Number.MAX_VALUE,c[0]=c[1]=h[0]=h[1]=-Number.MAX_VALUE;for(var t=this.data,e=0,i=0,o=0,d=0,f=0;f<t[oe];){var p=t[f++];switch(1==f&&(e=t[f],i=t[f+1],o=e,d=i),p){case s.M:o=t[f++],d=t[f++],e=o,i=d,u[0]=o,u[1]=d,h[0]=o,h[1]=d;break;case s.L:r.fromLine(e,i,t[f],t[f+1],u,h),e=t[f++],i=t[f++];break;case s.C:r.fromCubic(e,i,t[f++],t[f++],t[f++],t[f++],t[f],t[f+1],u,h),e=t[f++],i=t[f++];break;case s.Q:r.fromQuadratic(e,i,t[f++],t[f++],t[f],t[f+1],u,h),e=t[f++],i=t[f++];break;case s.A:var m=t[f++],y=t[f++],x=t[f++],_=t[f++],b=t[f++],w=t[f++]+b,S=(t[f++],1-t[f++]);1==f&&(o=g(b)*x+m,d=v(b)*_+y),r.fromArc(m,y,x,_,b,w,S,u,h),e=g(w)*x+m,i=v(w)*_+y;break;case s.R:o=e=t[f++],d=i=t[f++];var M=t[f++],A=t[f++];r.fromLine(o,d,o+M,d+A,u,h);break;case s.Z:e=o,i=d}n.min(l,l,u),n.max(c,c,h)}return 0===f&&(l[0]=l[1]=c[0]=c[1]=0),new a(l[0],l[1],c[0]-l[0],c[1]-l[1])},rebuildPath:function(t){for(var e,n,r,a,o,l,c=this.data,u=this._ux,h=this._uy,d=this._len,f=0;d>f;){var p=c[f++];switch(1==f&&(r=c[f],a=c[f+1],e=r,n=a),p){case s.M:e=r=c[f++],n=a=c[f++],t[i](r,a);break;case s.L:o=c[f++],l=c[f++],(y(o-r)>u||y(l-a)>h||f===d-1)&&(t.lineTo(o,l),r=o,a=l);break;case s.C:t.bezierCurveTo(c[f++],c[f++],c[f++],c[f++],c[f++],c[f++]),r=c[f-2],a=c[f-1];break;case s.Q:t.quadraticCurveTo(c[f++],c[f++],c[f++],c[f++]),r=c[f-2],a=c[f-1];break;case s.A:var m=c[f++],x=c[f++],_=c[f++],b=c[f++],w=c[f++],S=c[f++],M=c[f++],A=c[f++],C=_>b?_:b,T=_>b?1:_/b,L=_>b?b/_:1,P=Math.abs(_-b)>.001,z=w+S;P?(t.translate(m,x),t.rotate(M),t.scale(T,L),t.arc(0,0,C,w,z,1-A),t.scale(1/T,1/L),t.rotate(-M),t.translate(-m,-x)):t.arc(m,x,C,w,z,1-A),1==f&&(e=g(w)*_+m,n=v(w)*b+x),r=g(z)*_+m,a=v(z)*b+x;break;case s.R:e=r=c[f],n=a=c[f+1],t.rect(c[f++],c[f++],c[f++],c[f++]);break;case s.Z:t.closePath(),r=e,a=n}}}},b.CMD=s,b}),e("zrender/contain/text",[Ce,d,"../core/BoundingRect"],function(t){function e(t,e){var i=t+":"+e;if(s[i])return s[i];for(var n=(t+"").split("\n"),r=0,a=0,o=n[oe];o>a;a++)r=Math.max(f.measureText(n[a],e).width,r);return l>c&&(l=0,s={}),l++,s[i]=r,r}function i(t,i,n,r){var a=((t||"")+"").split("\n")[oe],o=e(t,i),s=e("国",i),l=a*s,c=new h(0,0,o,l);switch(c.lineHeight=s,r){case pe:case"alphabetic":c.y-=s;break;case E:c.y-=s/2}switch(n){case"end":case"right":c.x-=c.width;break;case B:c.x-=c.width/2}return c}function n(t,e,i,n){var r=e.x,a=e.y,o=e[fe],s=e.width,l=i[fe],c=o/2-l/2,u="left";switch(t){case"left":r-=n,a+=c,u="right";break;case"right":r+=n+s,a+=c,u="left";break;case"top":r+=s/2,a-=n+l,u=B;break;case pe:r+=s/2,a+=o+n,u=B;break;case m:r+=s/2,a+=c,u=B;break;case"insideLeft":r+=n,a+=c,u="left";break;case"insideRight":r+=s-n,a+=c,u="right";break;case"insideTop":r+=s/2,a+=n,u=B;break;case"insideBottom":r+=s/2,a+=o-l-n,u=B;break;case"insideTopLeft":r+=n,a+=n,u="left";break;case"insideTopRight":r+=s-n,a+=n,u="right";break;case"insideBottomLeft":r+=n,a+=o-l-n;break;case"insideBottomRight":r+=s-n,a+=o-l-n,u="right"}return{x:r,y:a,textAlign:u,textBaseline:"top"}}function r(t,i,n,r){if(!n)return"";r=u[se]({ellipsis:"...",minCharacters:3,maxIterations:3,cnCharWidth:e("国",i),ascCharWidth:e("a",i)},r,!0),n-=e(r.ellipsis);for(var o=(t+"").split("\n"),s=0,l=o[oe];l>s;s++)o[s]=a(o[s],i,n,r);return o.join("\n")}function a(t,i,n,r){for(var a=0;;a++){var s=e(t,i);if(n>s||a>=r.maxIterations){t+=r.ellipsis;break}var l=0===a?o(t,n,r):Math.floor(t[oe]*n/s);if(l<r.minCharacters){t="";break}t=t.substr(0,l)}return t}function o(t,e,i){for(var n=0,r=0,a=t[oe];a>r&&e>n;r++){var o=t.charCodeAt(r);n+=o>=0&&127>=o?i.ascCharWidth:i.cnCharWidth}return r}var s={},l=0,c=5e3,u=t(d),h=t("../core/BoundingRect"),f={getWidth:e,getBoundingRect:i,adjustTextPositionOnRect:n,ellipsis:r,measureText:function(t,e){var i=u.getContext();return i.font=e,i.measureText(t)}};return f}),e("zrender/graphic/mixin/RectText",[Ce,"../../contain/text","../../core/BoundingRect"],function(t){function e(t,e){return typeof t===_e?t.lastIndexOf("%")>=0?parseFloat(t)/100*e:parseFloat(t):t}function i(t,e){t[Me](e[0],e[1],e[2],e[3],e[4],e[5])}var n=t("../../contain/text"),r=t("../../core/BoundingRect"),a=new r,o=function(){};return o[be]={constructor:o,drawRectText:function(t,r,o){var s=this.style,l=s.text;if(null!=l&&(l+=""),l){var c,u,h=s.textPosition,d=s.textDistance,f=s[F],p=s.textFont||s.font,g=s.textBaseline,v=s.textVerticalAlign;o=o||n[N](l,p,f,g);var m=this[Me],y=this.invTransform;if(m&&(a.copy(r),a[b](m),r=a,i(t,y)),h instanceof Array){if(c=r.x+e(h[0],r.width),u=r.y+e(h[1],r[fe]),f=f||"left",g=g||"top",v){switch(v){case E:u-=o[fe]/2-o.lineHeight/2;break;case pe:u-=o[fe]-o.lineHeight/2;break;default:u+=o.lineHeight/2}g=E}}else{var x=n.adjustTextPositionOnRect(h,r,o,d);c=x.x,u=x.y,f=f||x[F],g=g||x.textBaseline}t[F]=f,t.textBaseline=g;var _=s.textFill,w=s.textStroke;_&&(t.fillStyle=_),w&&(t.strokeStyle=w),t.font=p,t.shadowColor=s.textShadowColor,t.shadowBlur=s.textShadowBlur,t.shadowOffsetX=s.textShadowOffsetX,t.shadowOffsetY=s.textShadowOffsetY;for(var S=l.split("\n"),M=0;M<S[oe];M++)_&&t.fillText(S[M],c,u),w&&t.strokeText(S[M],c,u),u+=o.lineHeight;m&&i(t,m)}}},o}),e("zrender/graphic/Displayable",[Ce,d,"./Style","../Element","./mixin/RectText"],function(t){function e(t){t=t||{},r.call(this,t);for(var e in t)t.hasOwnProperty(e)&&"style"!==e&&(this[e]=t[e]);this.style=new n(t.style),this._rect=null,this.__clipPaths=[]}var i=t(d),n=t("./Style"),r=t("../Element"),a=t("./mixin/RectText");return e[be]={constructor:e,type:"displayable",__dirty:!0,invisible:!1,z:0,z2:0,zlevel:0,draggable:!1,dragging:!1,silent:!1,culling:!1,cursor:"pointer",rectHover:!1,beforeBrush:function(){},afterBrush:function(){},brush:function(){},getBoundingRect:function(){},contain:function(t,e){return this.rectContain(t,e)},traverse:function(t,e){t.call(e,this)},rectContain:function(t,e){var i=this.transformCoordToLocal(t,e),n=this[N]();return n[D](i[0],i[1])},dirty:function(){this.__dirty=!0,this._rect=null,this.__zr&&this.__zr.refresh()},animateStyle:function(t){return this.animate("style",t)},attrKV:function(t,e){"style"!==t?r[be].attrKV.call(this,t,e):this.style.set(e)},setStyle:function(t,e){return this.style.set(t,e),this.dirty(!1),this},useStyle:function(t){return this.style=new n(t),this.dirty(!1),this}},i[W](e,r),i.mixin(e,a),e}),e("zrender/vml/core",[Ce,"exports","module","../core/env"],function(t,e,i){if(!t("../core/env").canvasSupported){var n,r="urn:schemas-microsoft-com:vml",a=window,o=a.document,s=!1;try{!o.namespaces.zrvml&&o.namespaces.add("zrvml",r),n=function(t){return o[f]("<zrvml:"+t+' class="zrvml">')}}catch(l){n=function(t){return o[f]("<"+t+' xmlns="'+r+'" class="zrvml">')}}var c=function(){if(!s){s=!0;var t=o.styleSheets;t[oe]<31?o.createStyleSheet().addRule(".zrvml","behavior:url(#default#VML)"):t[0].addRule(".zrvml","behavior:url(#default#VML)")}};i.exports={doc:o,initVML:c,createNode:n}}}),e("echarts/util/clazz",[Ce,Ae],function(t){function e(t,e){var i=n.slice(arguments,2);return this.superClass[be][e].apply(t,i)}function i(t,e,i){return this.superClass[be][e].apply(t,i)}var n=t(Ae),r={},a=".",o="___EC__COMPONENT__CONTAINER___",s=r.parseClassType=function(t){var e={main:"",sub:""};return t&&(t=t.split(a),e.main=t[0]||"",e.sub=t[1]||""),e};return r.enableClassExtend=function(t,r){t[le]=function(a){var o=function(){r&&r.apply(this,arguments),t.apply(this,arguments)};return n[le](o[be],a),o[le]=this[le],o.superCall=e,o.superApply=i,n[W](o,this),o.superClass=this,o}},r.enableClassManagement=function(t,e){function i(t){var e=r[t.main];return e&&e[o]||(e=r[t.main]={},e[o]=!0),e}e=e||{};var r={};if(t.registerClass=function(t,e){if(e)if(e=s(e),e.sub){if(e.sub!==o){var n=i(e);n[e.sub]=t}}else{if(r[e.main])throw new Error(e.main+"exists.");r[e.main]=t}return t},t.getClass=function(t,e,i){var n=r[t];if(n&&n[o]&&(n=e?n[e]:null),i&&!n)throw new Error("Component "+t+"."+(e||"")+" not exists. Load it first.");return n},t.getClassesByMainType=function(t){t=s(t);var e=[],i=r[t.main];return i&&i[o]?n.each(i,function(t,i){i!==o&&e.push(t)}):e.push(i),e},t.hasClass=function(t){return t=s(t),!!r[t.main]},t.getAllClassMainTypes=function(){var t=[];return n.each(r,function(e,i){t.push(i)}),t},t.hasSubTypes=function(t){t=s(t);var e=r[t.main];return e&&e[o]},t.parseClassType=s,e.registerWhenExtend){var a=t[le];a&&(t[le]=function(e){var i=a.call(this,e);return t.registerClass(i,e.type)})}return t},r.setReadOnly=function(){},r}),e("echarts/model/mixin/lineStyle",[Ce,"./makeStyleMapper"],function(t){var e=t("./makeStyleMapper")([[_,"width"],[x,"color"],[O],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["shadowColor"]]);return{getLineStyle:function(t){var i=e.call(this,t),n=this.getLineDash();return n&&(i.lineDash=n),i},getLineDash:function(){var t=this.get("type");return"solid"===t||null==t?null:"dashed"===t?[5,5]:[1,1]}}}),e("echarts/model/mixin/areaStyle",[Ce,"./makeStyleMapper"],function(t){return{getAreaStyle:t("./makeStyleMapper")([["fill","color"],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],[O],["shadowColor"]])}}),e("echarts/model/mixin/textStyle",[Ce,"zrender/contain/text"],function(t){function e(t,e){return t&&t[y](e)}var i=t("zrender/contain/text");return{getTextColor:function(){var t=this[L];return this[y]("color")||t&&t.get("textStyle.color")},getFont:function(){var t=this[L],i=t&&t[ye](G);
+return[this[y]("fontStyle")||e(i,"fontStyle"),this[y]("fontWeight")||e(i,"fontWeight"),(this[y]("fontSize")||e(i,"fontSize")||12)+"px",this[y]("fontFamily")||e(i,"fontFamily")||"sans-serif"].join(" ")},getTextRect:function(t){var e=this.get(G)||{};return i[N](t,this[V](),e.align,e.baseline)},ellipsis:function(t,e,n){return i.ellipsis(t,this[V](),e,n)}}}),e("echarts/model/mixin/itemStyle",[Ce,"./makeStyleMapper"],function(t){return{getItemStyle:t("./makeStyleMapper")([["fill","color"],[x,"borderColor"],[_,"borderWidth"],[O],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["shadowColor"]])}}),e("echarts/coord/cartesian/Cartesian2D",[Ce,Ae,"./Cartesian"],function(t){function e(t){n.call(this,t)}var i=t(Ae),n=t("./Cartesian");return e[be]={constructor:e,type:"cartesian2d",dimensions:["x","y"],getBaseAxis:function(){return this.getAxesByScale(l)[0]||this.getAxesByScale("time")[0]||this.getAxis("x")},containPoint:function(t){var e=this.getAxis("x"),i=this.getAxis("y");return e[D](e.toLocalCoord(t[0]))&&i[D](i.toLocalCoord(t[1]))},containData:function(t){return this.getAxis("x").containData(t[0])&&this.getAxis("y").containData(t[1])},dataToPoints:function(t,e){return t.mapArray(["x","y"],function(t,e){return this[o]([t,e])},e,this)},dataToPoint:function(t,e){var i=this.getAxis("x"),n=this.getAxis("y");return[i.toGlobalCoord(i.dataToCoord(t[0],e)),n.toGlobalCoord(n.dataToCoord(t[1],e))]},pointToData:function(t,e){var i=this.getAxis("x"),n=this.getAxis("y");return[i.coordToData(i.toLocalCoord(t[0]),e),n.coordToData(n.toLocalCoord(t[1]),e)]},getOtherAxis:function(t){return this.getAxis("x"===t.dim?"y":"x")}},i[W](e,n),e}),e("echarts/coord/cartesian/Axis2D",[Ce,Ae,"../Axis","./axisLabelInterval"],function(t){var e=t(Ae),i=t("../Axis"),n=t("./axisLabelInterval"),r=function(t,e,n,r,a){i.call(this,t,e,n),this.type=r||"value",this[R]=a||pe};return r[be]={constructor:r,index:0,onZero:!1,model:null,isHorizontal:function(){var t=this[R];return"top"===t||t===pe},getGlobalExtent:function(){var t=this[k]();return t[0]=this.toGlobalCoord(t[0]),t[1]=this.toGlobalCoord(t[1]),t},getLabelInterval:function(){var t=this._labelInterval;return t||(t=this._labelInterval=n(this)),t},isLabelIgnored:function(t){if(this.type===c){var e=this.getLabelInterval();return typeof e===Z&&!e(t,this.scale[I](t))||t%(e+1)}},toLocalCoord:null,toGlobalCoord:null},e[W](r,i),r}),e("echarts/coord/cartesian/GridModel",[Ce,"./AxisModel","../../model/Component"],function(t){t("./AxisModel");var e=t("../../model/Component");return e[le]({type:"grid",dependencies:["xAxis","yAxis"],layoutMode:"box",coordinateSystem:null,defaultOption:{show:!1,zlevel:0,z:0,left:"10%",top:60,right:"10%",bottom:60,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"}})}),e("zrender/tool/transformPath",[Ce,"../core/PathProxy","../core/vector"],function(t){function e(t,e){var n,l,c,u,h,d,f=t.data,p=i.M,g=i.C,v=i.L,m=i.R,y=i.A,x=i.Q;for(c=0,u=0;c<f[oe];){switch(n=f[c++],u=c,l=0,n){case p:l=1;break;case v:l=1;break;case g:l=3;break;case x:l=2;break;case y:var _=e[4],b=e[5],w=o(e[0]*e[0]+e[1]*e[1]),S=o(e[2]*e[2]+e[3]*e[3]),M=s(-e[1]/S,e[0]/w);f[c++]+=_,f[c++]+=b,f[c++]*=w,f[c++]*=S,f[c++]+=M,f[c++]+=M,c+=2,u=c;break;case m:d[0]=f[c++],d[1]=f[c++],r(d,d,e),f[u++]=d[0],f[u++]=d[1],d[0]+=f[c++],d[1]+=f[c++],r(d,d,e),f[u++]=d[0],f[u++]=d[1]}for(h=0;l>h;h++){var d=a[h];d[0]=f[c++],d[1]=f[c++],r(d,d,e),f[u++]=d[0],f[u++]=d[1]}}}var i=t("../core/PathProxy").CMD,n=t("../core/vector"),r=n[b],a=[[],[],[]],o=Math.sqrt,s=Math.atan2;return e}),e("zrender/contain/path",[Ce,"../core/PathProxy","./line","./cubic","./quadratic","./arc","./util","../core/curve","./windingLine"],function(t){function e(t,e){return Math.abs(t-e)<m}function i(){var t=x[0];x[0]=x[1],x[1]=t}function n(t,e,n,r,a,o,s,l,c,u){if(u>e&&u>r&&u>o&&u>l||e>u&&r>u&&o>u&&l>u)return 0;var h=f.cubicRootAt(e,r,o,l,u,y);if(0===h)return 0;for(var d,p,g=0,v=-1,m=0;h>m;m++){var _=y[m],b=f.cubicAt(t,n,a,s,_);c>b||(0>v&&(v=f.cubicExtrema(e,r,o,l,x),x[1]<x[0]&&v>1&&i(),d=f.cubicAt(e,r,o,l,x[0]),v>1&&(p=f.cubicAt(e,r,o,l,x[1]))),g+=2==v?_<x[0]?e>d?1:-1:_<x[1]?d>p?1:-1:p>l?1:-1:_<x[0]?e>d?1:-1:d>l?1:-1)}return g}function r(t,e,i,n,r,a,o,s){if(s>e&&s>n&&s>a||e>s&&n>s&&a>s)return 0;var l=f.quadraticRootAt(e,n,a,s,y);if(0===l)return 0;var c=f.quadraticExtremum(e,n,a);if(c>=0&&1>=c){for(var u=0,h=f.quadraticAt(e,n,a,c),d=0;l>d;d++){var p=f.quadraticAt(t,i,r,y[d]);o>p||(u+=y[d]<c?e>h?1:-1:h>a?1:-1)}return u}var p=f.quadraticAt(t,i,r,y[0]);return o>p?0:e>a?1:-1}function a(t,e,i,n,r,a,o,s){if(s-=e,s>i||-i>s)return 0;var l=Math.sqrt(i*i-s*s);y[0]=-l,y[1]=l;var c=Math.abs(n-r);if(1e-4>c)return 0;if(1e-4>c%v){n=0,r=v;var u=a?1:-1;return o>=y[0]+t&&o<=y[1]+t?u:0}if(a){var l=n;n=d(r),r=d(l)}else n=d(n),r=d(r);n>r&&(r+=v);for(var h=0,f=0;2>f;f++){var p=y[f];if(p+t>o){var g=Math.atan2(s,p),u=a?1:-1;0>g&&(g=v+g),(g>=n&&r>=g||g+v>=n&&r>=g+v)&&(g>Math.PI/2&&g<1.5*Math.PI&&(u=-u),h+=u)}}return h}function o(t,i,o,l,d){for(var f=0,v=0,m=0,y=0,x=0,_=0;_<t[oe];){var b=t[_++];if(b===s.M&&_>1&&(o||(f+=p(v,m,y,x,l,d)),0!==f))return!0;switch(1==_&&(v=t[_],m=t[_+1],y=v,x=m),b){case s.M:y=t[_++],x=t[_++],v=y,m=x;break;case s.L:if(o){if(g(v,m,t[_],t[_+1],i,l,d))return!0}else f+=p(v,m,t[_],t[_+1],l,d)||0;v=t[_++],m=t[_++];break;case s.C:if(o){if(c.containStroke(v,m,t[_++],t[_++],t[_++],t[_++],t[_],t[_+1],i,l,d))return!0}else f+=n(v,m,t[_++],t[_++],t[_++],t[_++],t[_],t[_+1],l,d)||0;v=t[_++],m=t[_++];break;case s.Q:if(o){if(u.containStroke(v,m,t[_++],t[_++],t[_],t[_+1],i,l,d))return!0}else f+=r(v,m,t[_++],t[_++],t[_],t[_+1],l,d)||0;v=t[_++],m=t[_++];break;case s.A:var w=t[_++],S=t[_++],M=t[_++],A=t[_++],C=t[_++],T=t[_++],L=(t[_++],1-t[_++]),P=Math.cos(C)*M+w,z=Math.sin(C)*A+S;_>1?f+=p(v,m,P,z,l,d):(y=P,x=z);var k=(l-w)*A/M+w;if(o){if(h.containStroke(w,S,A,C,C+T,L,i,k,d))return!0}else f+=a(w,S,A,C,C+T,L,k,d);v=Math.cos(C+T)*M+w,m=Math.sin(C+T)*A+S;break;case s.R:y=v=t[_++],x=m=t[_++];var I=t[_++],D=t[_++],P=y+I,z=x+D;if(o){if(g(y,x,P,x,i,l,d)||g(P,x,P,z,i,l,d)||g(P,z,y,z,i,l,d)||g(y,z,P,z,i,l,d))return!0}else f+=p(P,x,P,z,l,d),f+=p(y,z,y,x,l,d);break;case s.Z:if(o){if(g(v,m,y,x,i,l,d))return!0}else if(f+=p(v,m,y,x,l,d),0!==f)return!0;v=y,m=x}}return o||e(m,x)||(f+=p(v,m,y,x,l,d)||0),0!==f}var s=t("../core/PathProxy").CMD,l=t("./line"),c=t("./cubic"),u=t("./quadratic"),h=t("./arc"),d=t("./util").normalizeRadian,f=t("../core/curve"),p=t("./windingLine"),g=l.containStroke,v=2*Math.PI,m=1e-4,y=[-1,-1,-1],x=[-1,-1];return{contain:function(t,e,i){return o(t,0,!1,e,i)},containStroke:function(t,e,i,n){return o(t,e,!0,i,n)}}}),e("echarts/coord/polar/RadiusAxis",[Ce,Ae,"../Axis"],function(t){function e(t,e){r.call(this,n,t,e),this.type=c}var i=t(Ae),r=t("../Axis");return e[be]={constructor:e,dataToRadius:r[be].dataToCoord,radiusToData:r[be].coordToData},i[W](e,r),e}),e("echarts/coord/polar/AngleAxis",[Ce,Ae,"../Axis"],function(t){function e(t,e){e=e||[0,360],n.call(this,"angle",t,e),this.type=c}var i=t(Ae),n=t("../Axis");return e[be]={constructor:e,dataToAngle:n[be].dataToCoord,angleToData:n[be].coordToData},i[W](e,n),e}),e("echarts/scale/Ordinal",[Ce,Ae,"./Scale"],function(t){var e=t(Ae),i=t("./Scale"),n=i[be],r=i[le]({type:"ordinal",init:function(t,e){this._data=t,this._extent=e||[0,t[oe]-1]},parse:function(t){return typeof t===_e?e[X](this._data,t):Math.round(t)},contain:function(t){return t=this.parse(t),n[D].call(this,t)&&null!=this._data[t]},normalize:function(t){return n.normalize.call(this,this.parse(t))},scale:function(t){return Math.round(n.scale.call(this,t))},getTicks:function(){for(var t=[],e=this._extent,i=e[0];i<=e[1];)t.push(i),i++;return t},getLabel:function(t){return this._data[t]},count:function(){return this._extent[1]-this._extent[0]+1},niceTicks:e.noop,niceExtent:e.noop});return r[de]=function(){return new r},r}),e("zrender/core/curve",[Ce,"./vector"],function(t){function e(t){return t>-_&&_>t}function i(t){return t>_||-_>t}function n(t,e,i,n,r){var a=1-r;return a*a*(a*t+3*r*e)+r*r*(r*n+3*a*i)}function r(t,e,i,n,r){var a=1-r;return 3*(((e-t)*a+2*(i-e)*r)*a+(n-i)*r*r)}function a(t,i,n,r,a,o){var s=r+3*(i-n)-t,l=3*(n-2*i+t),c=3*(i-t),u=t-a,h=l*l-3*s*c,d=l*c-9*s*u,f=c*c-3*l*u,p=0;if(e(h)&&e(d))if(e(l))o[0]=0;else{var g=-c/l;g>=0&&1>=g&&(o[p++]=g)}else{var v=d*d-4*h*f;if(e(v)){var m=d/h,g=-l/s+m,_=-m/2;g>=0&&1>=g&&(o[p++]=g),_>=0&&1>=_&&(o[p++]=_)}else if(v>0){var b=x(v),M=h*l+1.5*s*(-d+b),A=h*l+1.5*s*(-d-b);M=0>M?-y(-M,S):y(M,S),A=0>A?-y(-A,S):y(A,S);var g=(-l-(M+A))/(3*s);g>=0&&1>=g&&(o[p++]=g)}else{var C=(2*h*l-3*s*d)/(2*x(h*h*h)),T=Math.acos(C)/3,L=x(h),P=Math.cos(T),g=(-l-2*L*P)/(3*s),_=(-l+L*(P+w*Math.sin(T)))/(3*s),z=(-l+L*(P-w*Math.sin(T)))/(3*s);g>=0&&1>=g&&(o[p++]=g),_>=0&&1>=_&&(o[p++]=_),z>=0&&1>=z&&(o[p++]=z)}}return p}function o(t,n,r,a,o){var s=6*r-12*n+6*t,l=9*n+3*a-3*t-9*r,c=3*n-3*t,u=0;if(e(l)){if(i(s)){var h=-c/s;h>=0&&1>=h&&(o[u++]=h)}}else{var d=s*s-4*l*c;if(e(d))o[0]=-s/(2*l);else if(d>0){var f=x(d),h=(-s+f)/(2*l),p=(-s-f)/(2*l);h>=0&&1>=h&&(o[u++]=h),p>=0&&1>=p&&(o[u++]=p)}}return u}function s(t,e,i,n,r,a){var o=(e-t)*r+t,s=(i-e)*r+e,l=(n-i)*r+i,c=(s-o)*r+o,u=(l-s)*r+s,h=(u-c)*r+c;a[0]=t,a[1]=o,a[2]=c,a[3]=h,a[4]=h,a[5]=u,a[6]=l,a[7]=n}function l(t,e,i,r,a,o,s,l,c,u,h){var d,f,p,g,v,y=.005,_=1/0;M[0]=c,M[1]=u;for(var w=0;1>w;w+=.05)A[0]=n(t,i,a,s,w),A[1]=n(e,r,o,l,w),g=m(M,A),_>g&&(d=w,_=g);_=1/0;for(var S=0;32>S&&!(b>y);S++)f=d-y,p=d+y,A[0]=n(t,i,a,s,f),A[1]=n(e,r,o,l,f),g=m(A,M),f>=0&&_>g?(d=f,_=g):(C[0]=n(t,i,a,s,p),C[1]=n(e,r,o,l,p),v=m(C,M),1>=p&&_>v?(d=p,_=v):y*=.5);return h&&(h[0]=n(t,i,a,s,d),h[1]=n(e,r,o,l,d)),x(_)}function c(t,e,i,n){var r=1-n;return r*(r*t+2*n*e)+n*n*i}function u(t,e,i,n){return 2*((1-n)*(e-t)+n*(i-e))}function h(t,n,r,a,o){var s=t-2*n+r,l=2*(n-t),c=t-a,u=0;if(e(s)){if(i(l)){var h=-c/l;h>=0&&1>=h&&(o[u++]=h)}}else{var d=l*l-4*s*c;if(e(d)){var h=-l/(2*s);h>=0&&1>=h&&(o[u++]=h)}else if(d>0){var f=x(d),h=(-l+f)/(2*s),p=(-l-f)/(2*s);h>=0&&1>=h&&(o[u++]=h),p>=0&&1>=p&&(o[u++]=p)}}return u}function d(t,e,i){var n=t+i-2*e;return 0===n?.5:(t-e)/n}function f(t,e,i,n,r){var a=(e-t)*n+t,o=(i-e)*n+e,s=(o-a)*n+a;r[0]=t,r[1]=a,r[2]=s,r[3]=s,r[4]=o,r[5]=i}function p(t,e,i,n,r,a,o,s,l){var u,h=.005,d=1/0;M[0]=o,M[1]=s;for(var f=0;1>f;f+=.05){A[0]=c(t,i,r,f),A[1]=c(e,n,a,f);var p=m(M,A);d>p&&(u=f,d=p)}d=1/0;for(var g=0;32>g&&!(b>h);g++){var v=u-h,y=u+h;A[0]=c(t,i,r,v),A[1]=c(e,n,a,v);var p=m(A,M);if(v>=0&&d>p)u=v,d=p;else{C[0]=c(t,i,r,y),C[1]=c(e,n,a,y);var _=m(C,M);1>=y&&d>_?(u=y,d=_):h*=.5}}return l&&(l[0]=c(t,i,r,u),l[1]=c(e,n,a,u)),x(d)}var g=t("./vector"),v=g[de],m=g.distSquare,y=Math.pow,x=Math.sqrt,_=1e-8,b=1e-4,w=x(3),S=1/3,M=v(),A=v(),C=v();return{cubicAt:n,cubicDerivativeAt:r,cubicRootAt:a,cubicExtrema:o,cubicSubdivide:s,cubicProjectPoint:l,quadraticAt:c,quadraticDerivativeAt:u,quadraticRootAt:h,quadraticExtremum:d,quadraticSubdivide:f,quadraticProjectPoint:p}}),e("zrender/config",[],function(){var t=1;typeof window!==p&&(t=Math.max(window.devicePixelRatio||1,1));var e={debugMode:0,devicePixelRatio:t};return e}),e("zrender/core/bbox",[Ce,"./vector","./curve"],function(t){var e=t("./vector"),i=t("./curve"),n={},r=Math.min,a=Math.max,o=Math.sin,s=Math.cos,l=e[de](),c=e[de](),u=e[de](),h=2*Math.PI;n.fromPoints=function(t,e,i){if(0!==t[oe]){var n,o=t[0],s=o[0],l=o[0],c=o[1],u=o[1];for(n=1;n<t[oe];n++)o=t[n],s=r(s,o[0]),l=a(l,o[0]),c=r(c,o[1]),u=a(u,o[1]);e[0]=s,e[1]=c,i[0]=l,i[1]=u}},n.fromLine=function(t,e,i,n,o,s){o[0]=r(t,i),o[1]=r(e,n),s[0]=a(t,i),s[1]=a(e,n)};var d=[],f=[];return n.fromCubic=function(t,e,n,o,s,l,c,u,h,p){var g,v=i.cubicExtrema,m=i.cubicAt,y=v(t,n,s,c,d);for(h[0]=1/0,h[1]=1/0,p[0]=-1/0,p[1]=-1/0,g=0;y>g;g++){var x=m(t,n,s,c,d[g]);h[0]=r(x,h[0]),p[0]=a(x,p[0])}for(y=v(e,o,l,u,f),g=0;y>g;g++){var _=m(e,o,l,u,f[g]);h[1]=r(_,h[1]),p[1]=a(_,p[1])}h[0]=r(t,h[0]),p[0]=a(t,p[0]),h[0]=r(c,h[0]),p[0]=a(c,p[0]),h[1]=r(e,h[1]),p[1]=a(e,p[1]),h[1]=r(u,h[1]),p[1]=a(u,p[1])},n.fromQuadratic=function(t,e,n,o,s,l,c,u){var h=i.quadraticExtremum,d=i.quadraticAt,f=a(r(h(t,n,s),1),0),p=a(r(h(e,o,l),1),0),g=d(t,n,s,f),v=d(e,o,l,p);c[0]=r(t,s,g),c[1]=r(e,l,v),u[0]=a(t,s,g),u[1]=a(e,l,v)},n.fromArc=function(t,i,n,r,a,d,f,p,g){var v=e.min,m=e.max,y=Math.abs(a-d);if(1e-4>y%h&&y>1e-4)return p[0]=t-n,p[1]=i-r,g[0]=t+n,void(g[1]=i+r);if(l[0]=s(a)*n+t,l[1]=o(a)*r+i,c[0]=s(d)*n+t,c[1]=o(d)*r+i,v(p,l,c),m(g,l,c),a%=h,0>a&&(a+=h),d%=h,0>d&&(d+=h),a>d&&!f?d+=h:d>a&&f&&(a+=h),f){var x=d;d=a,a=x}for(var _=0;d>_;_+=Math.PI/2)_>a&&(u[0]=s(_)*n+t,u[1]=o(_)*r+i,v(p,u,p),m(g,u,g))},n}),e("zrender/graphic/Style",[Ce],function(){var t=["lineCap","lineJoin","miterLimit","shadowBlur","shadowOffsetX","shadowOffsetY","shadowColor"],e=function(t){this.extendFrom(t)};e[be]={constructor:e,fill:"#000000",stroke:null,opacity:1,lineDash:null,lineDashOffset:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,lineWidth:1,strokeNoScale:!1,text:null,textFill:"#000",textStroke:null,textPosition:"inside",textBaseline:null,textAlign:null,textVerticalAlign:null,textDistance:5,textShadowBlur:0,textShadowOffsetX:0,textShadowOffsetY:0,bind:function(e,i){for(var n=this.fill,r=this[x],a=0;a<t[oe];a++){var o=t[a];null!=this[o]&&(e[o]=this[o])}if(null!=r){var s=this[_];e[_]=s/(this.strokeNoScale&&i&&i.getLineScale?i.getLineScale():1)}null==n||"none"===n||n.colorStops||(e.fillStyle=n),null==r||"none"===r||r.colorStops||(e.strokeStyle=r),null!=this[O]&&(e.globalAlpha=this[O])},extendFrom:function(t,e){if(t){var i=this;for(var n in t)!t.hasOwnProperty(n)||!e&&i.hasOwnProperty(n)||(i[n]=t[n])}},set:function(t,e){typeof t===_e?this[t]=e:this.extendFrom(t,!0)},clone:function(){var t=new this.constructor;return t.extendFrom(this,!0),t},createLinearGradient:function(t,e,i){var n=e.x*i.width+i.x,r=e.x2*i.width+i.x,a=e.y*i[fe]+i.y,o=e.y2*i[fe]+i.y,s=t.createLinearGradient(n,a,r,o);return s},createRadialGradient:function(t,e,i){var n=i.width,r=i[fe],a=Math.min(n,r),o=e.x*n+i.x,s=e.y*r+i.y,l=e.r*a,c=t.createRadialGradient(o,s,0,o,s,l);return c},getGradient:function(t,e,i){for(var n="radial"===e.type?"createRadialGradient":"createLinearGradient",r=this[n](t,e,i),a=e.colorStops,o=0;o<a[oe];o++)r.addColorStop(a[o].offset,a[o].color);return r}};var i,n,r=e[be];for(n=0;n<t[oe];n++)i=t[n],i in r||(r[i]=null);return e}),e("zrender/Element",[Ce,"./core/guid","./mixin/Eventful","./mixin/Transformable","./mixin/Animatable","./core/util"],function(t){var e=t("./core/guid"),i=t("./mixin/Eventful"),n=t("./mixin/Transformable"),r=t("./mixin/Animatable"),a=t("./core/util"),o=function(t){n.call(this,t),i.call(this,t),r.call(this,t),this.id=t.id||e()};return o[be]={type:"element",name:"",__zr:null,ignore:!1,clipPath:null,drift:function(t,e){switch(this.draggable){case"horizontal":e=0;break;case"vertical":t=0}var i=this[Me];i||(i=this[Me]=[1,0,0,1,0,0]),i[4]+=t,i[5]+=e,this.decomposeTransform(),this.dirty()},beforeUpdate:function(){},afterUpdate:function(){},update:function(){this.updateTransform()},traverse:function(){},attrKV:function(t,e){if(t===R||"scale"===t||"origin"===t){if(e){var i=this[t];i||(i=this[t]=[]),i[0]=e[0],i[1]=e[1]}}else this[t]=e},hide:function(){this[ge]=!0,this.__zr&&this.__zr.refresh()},show:function(){this[ge]=!1,this.__zr&&this.__zr.refresh()},attr:function(t,e){if(typeof t===_e)this.attrKV(t,e);else if(a[ue](t))for(var i in t)t.hasOwnProperty(i)&&this.attrKV(i,t[i]);return this.dirty(),this},setClipPath:function(t){var e=this.__zr;e&&t.addSelfToZr(e),this.clipPath&&this.clipPath!==t&&this.removeClipPath(),this.clipPath=t,t.__zr=e,t.__clipTarget=this,this.dirty()},removeClipPath:function(){var t=this.clipPath;t&&(t.__zr&&t.removeSelfFromZr(t.__zr),t.__zr=null,t.__clipTarget=null,this.clipPath=null,this.dirty())},addSelfToZr:function(t){this.__zr=t;var e=this.animators;if(e)for(var i=0;i<e[oe];i++)t[v].addAnimator(e[i]);this.clipPath&&this.clipPath.addSelfToZr(t)},removeSelfFromZr:function(t){this.__zr=null;var e=this.animators;if(e)for(var i=0;i<e[oe];i++)t[v].removeAnimator(e[i]);this.clipPath&&this.clipPath.removeSelfFromZr(t)}},a.mixin(o,r),a.mixin(o,n),a.mixin(o,i),o}),e("echarts/model/mixin/makeStyleMapper",[Ce,Ae],function(t){var e=t(Ae);return function(t){for(var i=0;i<t[oe];i++)t[i][1]||(t[i][1]=t[i][0]);return function(i){for(var n={},r=0;r<t[oe];r++){var a=t[r][1];if(!(i&&e[X](i,a)>=0)){var o=this[y](a);null!=o&&(n[t[r][0]]=o)}}return n}}}),e("echarts/coord/Axis",[Ce,"../util/number",Ae],function(t){function e(t,e){var i=t[1]-t[0],n=e,r=i/n/2;t[0]+=r,t[1]-=r}var i=t("../util/number"),n=i.linearMap,r=t(Ae),a=[0,1],o=function(t,e,i){this.dim=t,this.scale=e,this._extent=i||[0,0],this.inverse=!1,this.onBand=!1};return o[be]={constructor:o,contain:function(t){var e=this._extent,i=Math.min(e[0],e[1]),n=Math.max(e[0],e[1]);return t>=i&&n>=t},containData:function(t){return this[D](this.dataToCoord(t))},getExtent:function(){var t=this._extent.slice();return t},getPixelPrecision:function(t){return i.getPixelPrecision(t||this.scale[k](),this._extent)},setExtent:function(t,e){var i=this._extent;i[0]=t,i[1]=e},dataToCoord:function(t,i){var r=this._extent,o=this.scale;return t=o.normalize(t),this.onBand&&o.type===l&&(r=r.slice(),e(r,o.count())),n(t,a,r,i)},coordToData:function(t,i){var r=this._extent,o=this.scale;this.onBand&&o.type===l&&(r=r.slice(),e(r,o.count()));var s=n(t,r,a,i);return this.scale.scale(s)},getTicksCoords:function(){if(this.onBand){for(var t=this.getBands(),e=[],i=0;i<t[oe];i++)e.push(t[i][0]);return t[i-1]&&e.push(t[i-1][1]),e}return r.map(this.scale.getTicks(),this.dataToCoord,this)},getLabelsCoords:function(){if(this.onBand){for(var t,e=this.getBands(),i=[],n=0;n<e[oe];n++)t=e[n],i.push((t[0]+t[1])/2);return i}return r.map(this.scale.getTicks(),this.dataToCoord,this)},getBands:function(){for(var t=this[k](),e=[],i=this.scale.count(),n=t[0],r=t[1],a=r-n,o=0;i>o;o++)e.push([a*o/i+n,a*(o+1)/i+n]);return e},getBandWidth:function(){var t=this._extent,e=this.scale[k](),i=e[1]-e[0]+(this.onBand?1:0);0===i&&(i=1);var n=Math.abs(t[1]-t[0]);return Math.abs(n)/i}},o}),e("echarts/coord/cartesian/Cartesian",[Ce,Ae],function(t){function e(t){return this._axes[t]}var i=t(Ae),n=function(t){this._axes={},this._dimList=[],this.name=t||""};return n[be]={constructor:n,type:"cartesian",getAxis:function(t){return this._axes[t]},getAxes:function(){return i.map(this._dimList,e,this)},getAxesByScale:function(t){return t=t[we](),i[Se](this.getAxes(),function(e){return e.scale.type===t})},addAxis:function(t){var e=t.dim;this._axes[e]=t,this._dimList.push(e)},dataToCoord:function(t){return this._dataCoordConvert(t,"dataToCoord")},coordToData:function(t){return this._dataCoordConvert(t,"coordToData")},_dataCoordConvert:function(t,e){for(var i=this._dimList,n=t instanceof Array?[]:{},r=0;r<i[oe];r++){var a=i[r],o=this._axes[a];n[a]=o[e](t[a])}return n}},n}),e("zrender/core/guid",[],function(){var t=2311;return function(){return"zr_"+t++}}),e("zrender/mixin/Transformable",[Ce,"../core/matrix","../core/vector"],function(t){function e(t){return t>a||-a>t}var i=t("../core/matrix"),n=t("../core/vector"),r=i.identity,a=5e-5,o=function(t){t=t||{},t[R]||(this[R]=[0,0]),null==t.rotation&&(this.rotation=0),t.scale||(this.scale=[1,1]),this.origin=this.origin||null},s=o[be];s[Me]=null,s.needLocalTransform=function(){return e(this.rotation)||e(this[R][0])||e(this[R][1])||e(this.scale[0]-1)||e(this.scale[1]-1)},s.updateTransform=function(){var t=this.parent,e=t&&t[Me],n=this.needLocalTransform(),a=this[Me];return n||e?(a=a||i[de](),n?this.getLocalTransform(a):r(a),e&&(n?i.mul(a,t[Me],a):i.copy(a,t[Me])),this[Me]=a,this.invTransform=this.invTransform||i[de](),void i.invert(this.invTransform,a)):void(a&&r(a))},s.getLocalTransform=function(t){t=t||[],r(t);var e=this.origin,n=this.scale,a=this.rotation,o=this[R];return e&&(t[4]-=e[0],t[5]-=e[1]),i.scale(t,t,n),a&&i.rotate(t,t,a),e&&(t[4]+=e[0],t[5]+=e[1]),t[4]+=o[0],t[5]+=o[1],t},s.setTransform=function(t){var e=this[Me];e&&t[Me](e[0],e[1],e[2],e[3],e[4],e[5])};var l=[];return s.decomposeTransform=function(){if(this[Me]){var t=this.parent,n=this[Me];t&&t[Me]&&(i.mul(l,t.invTransform,n),n=l);var r=n[0]*n[0]+n[1]*n[1],a=n[2]*n[2]+n[3]*n[3],o=this[R],s=this.scale;e(r-1)&&(r=Math.sqrt(r)),e(a-1)&&(a=Math.sqrt(a)),n[0]<0&&(r=-r),n[3]<0&&(a=-a),o[0]=n[4],o[1]=n[5],s[0]=r,s[1]=a,this.rotation=Math.atan2(-n[1]/a,n[0]/r)}},s.getGlobalScale=function(){var t=this[Me];if(!t)return[1,1];var e=Math.sqrt(t[0]*t[0]+t[1]*t[1]),i=Math.sqrt(t[2]*t[2]+t[3]*t[3]);return t[0]<0&&(e=-e),t[3]<0&&(i=-i),[e,i]},s.transformCoordToLocal=function(t,e){var i=[t,e],r=this.invTransform;return r&&n[b](i,i,r),i},s.transformCoordToGlobal=function(t,e){var i=[t,e],r=this[Me];return r&&n[b](i,i,r),i},o}),e("zrender/mixin/Animatable",[Ce,"../animation/Animator",d,"../core/log"],function(t){var e=t("../animation/Animator"),i=t(d),n=i.isString,r=i.isFunction,a=i[ue],o=t("../core/log"),s=function(){this.animators=[]};return s[be]={constructor:s,animate:function(t,n){var r,a=!1,s=this,l=this.__zr;if(t){var c=t.split("."),u=s;a="shape"===c[0];for(var h=0,d=c[oe];d>h;h++)u&&(u=u[c[h]]);u&&(r=u)}else r=s;if(!r)return void o('Property "'+t+'" is not existed in element '+s.id);var f=s.animators,p=new e(r,n);return p.during(function(){s.dirty(a)}).done(function(){f[ne](i[X](f,p),1)}),f.push(p),l&&l[v].addAnimator(p),p},stopAnimation:function(t){for(var e=this.animators,i=e[oe],n=0;i>n;n++)e[n].stop(t);return e[oe]=0,this},animateTo:function(t,e,i,a,o){function s(){c--,c||o&&o()}n(i)?(o=a,a=i,i=0):r(a)?(o=a,a="linear",i=0):r(i)?(o=i,i=0):r(e)?(o=e,e=500):e||(e=500),this.stopAnimation(),this._animateToShallow("",this,t,e,i,a,o);var l=this.animators.slice(),c=l[oe];c||o&&o();for(var u=0;u<l[oe];u++)l[u].done(s).start(a)},_animateToShallow:function(t,e,n,r,o){var s={},l=0;for(var c in n)if(null!=e[c])a(n[c])&&!i.isArrayLike(n[c])?this._animateToShallow(t?t+"."+c:c,e[c],n[c],r,o):(s[c]=n[c],l++);else if(null!=n[c])if(t){var u={};u[t]={},u[t][c]=n[c],this.attr(u)}else this.attr(c,n[c]);return l>0&&this.animate(t,!1).when(null==r?500:r,s).delay(o||0),this}},s}),e("echarts/util/component",[Ce,Ae,"./clazz"],function(t){var e=t(Ae),i=t("./clazz"),n=i.parseClassType,r=0,a={},o="_";return a.getUID=function(t){return[t||"",r++,Math.random()].join(o)},a.enableSubTypeDefaulter=function(t){var e={};return t.registerSubTypeDefaulter=function(t,i){t=n(t),e[t.main]=i},t.determineSubType=function(i,r){var a=r.type;if(!a){var o=n(i).main;t.hasSubTypes(i)&&e[o]&&(a=e[o](r))}return a},t},a.enableTopologicalTravel=function(t,i){function n(t){var n={},o=[];return e.each(t,function(s){var l=r(n,s),c=l.originalDeps=i(s),u=a(c,t);l.entryCount=u[oe],0===l.entryCount&&o.push(s),e.each(u,function(t){e[X](l.predecessor,t)<0&&l.predecessor.push(t);var i=r(n,t);e[X](i.successor,t)<0&&i.successor.push(s)})}),{graph:n,noEntryList:o}}function r(t,e){return t[e]||(t[e]={predecessor:[],successor:[]}),t[e]}function a(t,i){var n=[];return e.each(t,function(t){e[X](i,t)>=0&&n.push(t)}),n}t.topologicalTravel=function(t,i,r,a){function o(t){c[t].entryCount--,0===c[t].entryCount&&u.push(t)}function s(t){h[t]=!0,o(t)}if(t[oe]){var l=n(i),c=l.graph,u=l.noEntryList,h={};for(e.each(t,function(t){h[t]=!0});u[oe];){var d=u.pop(),f=c[d],p=!!h[d];p&&(r.call(a,d,f.originalDeps.slice()),delete h[d]),e.each(f.successor,p?s:o)}e.each(h,function(){throw new Error("Circle dependency may exists")})}}},a}),e("echarts/model/mixin/boxLayout",[Ce],function(){return{getBoxLayoutParams:function(){return{left:this.get("left"),top:this.get("top"),right:this.get("right"),bottom:this.get(pe),width:this.get("width"),height:this.get(fe)}}}}),e("echarts/coord/polar/AxisModel",[Ce,Ae,"../../model/Component","../axisModelCreator","../axisModelCommonMixin"],function(t){function e(t,e){return e.type||(e.data?c:"value")}var i=t(Ae),r=t("../../model/Component"),a=t("../axisModelCreator"),o=r[le]({type:"polarAxis",axis:null});i.merge(o[be],t("../axisModelCommonMixin"));var s={angle:{polarIndex:0,startAngle:90,clockwise:!0,splitNumber:12,axisLabel:{rotate:!1}},radius:{polarIndex:0,splitNumber:5}};a("angle",o,e,s.angle),a(n,o,e,s[n])}),e("echarts/coord/cartesian/axisLabelInterval",[Ce,Ae,"../axisHelper"],function(t){var e=t(Ae),i=t("../axisHelper");return function(t){var n=t.model,r=n[ye]("axisLabel"),a=r.get("interval");return t.type!==c||"auto"!==a?"auto"===a?0:a:i.getAxisLabelInterval(e.map(t.scale.getTicks(),t.dataToCoord,t),n.getFormattedLabels(),r[ye](G)[V](),t.isHorizontal())}}),e("zrender/core/log",[Ce,"../config"],function(t){var e=t("../config");return function(){if(0!==e.debugMode)if(1==e.debugMode)for(var t in arguments)throw new Error(arguments[t]);else if(e.debugMode>1)for(var t in arguments)console.log(arguments[t])}}),e("zrender/animation/Animator",[Ce,"./Clip","../tool/color",d],function(t){function e(t,e){return t[e]}function i(t,e,i){t[e]=i}function n(t,e,i){return(e-t)*i+t}function r(t,e,i){return i>.5?e:t}function a(t,e,i,r,a){var o=t[oe];if(1==a)for(var s=0;o>s;s++)r[s]=n(t[s],e[s],i);else for(var l=t[0][oe],s=0;o>s;s++)for(var c=0;l>c;c++)r[s][c]=n(t[s][c],e[s][c],i)}function o(t,e,i){var n=t[oe],r=e[oe];if(n!==r){var a=n>r;if(a)t[oe]=r;else for(var o=n;r>o;o++)t.push(1===i?e[o]:x.call(e[o]))}for(var s=t[0]&&t[0][oe],o=0;o<t[oe];o++)if(1===i)isNaN(t[o])&&(t[o]=e[o]);else for(var l=0;s>l;l++)isNaN(t[o][l])&&(t[o][l]=e[o][l])}function s(t,e,i){if(t===e)return!0;var n=t[oe];if(n!==e[oe])return!1;if(1===i){for(var r=0;n>r;r++)if(t[r]!==e[r])return!1}else for(var a=t[0][oe],r=0;n>r;r++)for(var o=0;a>o;o++)if(t[r][o]!==e[r][o])return!1;return!0}function l(t,e,i,n,r,a,o,s,l){var u=t[oe];if(1==l)for(var h=0;u>h;h++)s[h]=c(t[h],e[h],i[h],n[h],r,a,o);else for(var d=t[0][oe],h=0;u>h;h++)for(var f=0;d>f;f++)s[h][f]=c(t[h][f],e[h][f],i[h][f],n[h][f],r,a,o)}function c(t,e,i,n,r,a,o){var s=.5*(i-t),l=.5*(n-e);return(2*(e-i)+s+l)*o+(-3*(e-i)-2*s-l)*a+s*r+e}function u(t){if(y(t)){var e=t[oe];if(y(t[0])){for(var i=[],n=0;e>n;n++)i.push(x.call(t[n]));return i}return x.call(t)}return t}function h(t){return t[0]=Math.floor(t[0]),t[1]=Math.floor(t[1]),t[2]=Math.floor(t[2]),"rgba("+t.join(",")+")"}function f(t,e,i,u,d){var f=t._getter,v=t._setter,m="spline"===e,x=u[oe];if(x){var _,b=u[0].value,w=y(b),S=!1,M=!1,A=w&&y(b[0])?2:1;u.sort(function(t,e){return t.time-e.time}),_=u[x-1].time;for(var C=[],T=[],L=u[0].value,P=!0,z=0;x>z;z++){C.push(u[z].time/_);var k=u[z].value;if(w&&s(k,L,A)||!w&&k===L||(P=!1),L=k,typeof k==_e){var I=g.parse(k);I?(k=I,S=!0):M=!0}T.push(k)}if(!P){for(var D=T[x-1],z=0;x-1>z;z++)w?o(T[z],D,A):!isNaN(T[z])||isNaN(D)||M||S||(T[z]=D);w&&o(f(t._target,d),D,A);var O,R,B,E,N,V,F=0,G=0;if(S)var H=[0,0,0,0];var q=function(t,e){var i;if(G>e){for(O=Math.min(F+1,x-1),i=O;i>=0&&!(C[i]<=e);i--);i=Math.min(i,x-2)}else{for(i=F;x>i&&!(C[i]>e);i++);i=Math.min(i-1,x-2)}F=i,G=e;var o=C[i+1]-C[i];if(0!==o)if(R=(e-C[i])/o,m)if(E=T[i],B=T[0===i?i:i-1],N=T[i>x-2?x-1:i+1],V=T[i>x-3?x-1:i+2],w)l(B,E,N,V,R,R*R,R*R*R,f(t,d),A);else{var s;if(S)s=l(B,E,N,V,R,R*R,R*R*R,H,1),s=h(H);else{if(M)return r(E,N,R);s=c(B,E,N,V,R,R*R,R*R*R)}v(t,d,s)}else if(w)a(T[i],T[i+1],R,f(t,d),A);else{var s;if(S)a(T[i],T[i+1],R,H,1),s=h(H);else{if(M)return r(T[i],T[i+1],R);s=n(T[i],T[i+1],R)}v(t,d,s)}},W=new p({target:t._target,life:_,loop:t._loop,delay:t._delay,onframe:q,ondestroy:i});return e&&"spline"!==e&&(W.easing=e),W}}}var p=t("./Clip"),g=t("../tool/color"),m=t(d),y=m.isArrayLike,x=Array[be].slice,_=function(t,n,r,a){this._tracks={},this._target=t,this._loop=n||!1,this._getter=r||e,this._setter=a||i,this._clipCount=0,this._delay=0,this._doneList=[],this._onframeList=[],this._clipList=[]};return _[be]={when:function(t,e){var i=this._tracks;for(var n in e){if(!i[n]){i[n]=[];var r=this._getter(this._target,n);if(null==r)continue;0!==t&&i[n].push({time:0,value:u(r)})}i[n].push({time:t,value:e[n]})}return this},during:function(t){return this._onframeList.push(t),this},_doneCallback:function(){this._tracks={},this._clipList[oe]=0;for(var t=this._doneList,e=t[oe],i=0;e>i;i++)t[i].call(this)},start:function(t){var e,i=this,n=0,r=function(){n--,n||i._doneCallback()};for(var a in this._tracks){var o=f(this,t,r,this._tracks[a],a);o&&(this._clipList.push(o),n++,this[v]&&this[v].addClip(o),e=o)}if(e){var s=e.onframe;e.onframe=function(t,e){s(t,e);for(var n=0;n<i._onframeList[oe];n++)i._onframeList[n](t,e)}}return n||this._doneCallback(),this},stop:function(t){for(var e=this._clipList,i=this[v],n=0;n<e[oe];n++){var r=e[n];t&&r.onframe(this._target,1),i&&i.removeClip(r)}e[oe]=0},delay:function(t){return this._delay=t,this},done:function(t){return t&&this._doneList.push(t),this},getClips:function(){return this._clipList}},_}),e("echarts/coord/axisModelCreator",[Ce,"./axisDefault",Ae,"../model/Component","../util/layout"],function(t){var e=t("./axisDefault"),i=t(Ae),n=t("../model/Component"),r=t("../util/layout"),a=["value",c,"time","log"];return function(t,o,s,l){i.each(a,function(n){o[le]({type:t+"Axis."+n,mergeDefaultAndTheme:function(e,a){var o=this.layoutMode,l=o?r.getLayoutParams(e):{},c=a.getTheme();i.merge(e,c.get(n+"Axis")),i.merge(e,this.getDefaultOption()),e.type=s(t,e),o&&r.mergeLayoutParam(e,l,o)},defaultOption:i.mergeAll([{},e[n+"Axis"],l],!0)})}),n.registerSubTypeDefaulter(t+"Axis",i.curry(s,t))}}),e("echarts/coord/axisModelCommonMixin",[Ce,Ae,"./axisHelper"],function(t){function e(t){return r[ue](t)&&null!=t.value?t.value:t}function i(){return this.get("type")===c&&r.map(this.get("data"),e)}function n(){return a.getFormattedLabels(this.axis,this.get("axisLabel.formatter"))}var r=t(Ae),a=t("./axisHelper");return{getFormattedLabels:n,getCategories:i}}),e("echarts/coord/cartesian/AxisModel",[Ce,"../../model/Component",Ae,"../axisModelCreator","../axisModelCommonMixin"],function(t){function e(t,e){return e.type||(e.data?c:"value")}var i=t("../../model/Component"),n=t(Ae),r=t("../axisModelCreator"),a=i[le]({type:"cartesian2dAxis",axis:null,init:function(){a.superApply(this,"init",arguments),this._resetRange()},mergeOption:function(){a.superApply(this,"mergeOption",arguments),this._resetRange()},restoreData:function(){a.superApply(this,"restoreData",arguments),this._resetRange()},setRange:function(t,e){this[z].rangeStart=t,this[z].rangeEnd=e},getMin:function(){var t=this[z];return null!=t.rangeStart?t.rangeStart:t.min},getMax:function(){var t=this[z];return null!=t.rangeEnd?t.rangeEnd:t.max},getNeedCrossZero:function(){var t=this[z];return null!=t.rangeStart||null!=t.rangeEnd?!1:!t.scale},_resetRange:function(){this[z].rangeStart=this[z].rangeEnd=null}});n.merge(a[be],t("../axisModelCommonMixin"));var o={gridIndex:0};return r("x",a,e,o),r("y",a,e,o),a}),e("zrender/animation/Clip",[Ce,"./easing"],function(t){function e(t){this._target=t[J],this._life=t.life||1e3,this._delay=t.delay||0,this._initialized=!1,this.loop=null==t.loop?!1:t.loop,this.gap=t.gap||0,this.easing=t.easing||"Linear",this.onframe=t.onframe,this.ondestroy=t.ondestroy,this.onrestart=t.onrestart}var i=t("./easing");return e[be]={constructor:e,step:function(t){this._initialized||(this._startTime=(new Date).getTime()+this._delay,this._initialized=!0);var e=(t-this._startTime)/this._life;if(!(0>e)){e=Math.min(e,1);var n=this.easing,r=typeof n==_e?i[n]:n,a=typeof r===Z?r(e):e;return this.fire("frame",a),1==e?this.loop?(this.restart(),"restart"):(this._needsRemove=!0,"destroy"):null}},restart:function(){var t=(new Date).getTime(),e=(t-this._startTime)%this._life;this._startTime=(new Date).getTime()-e+this.gap,this._needsRemove=!1},fire:function(t,e){t="on"+t,this[t]&&this[t](this._target,e)}},e}),e("echarts/coord/axisDefault",[Ce,Ae],function(t){var e=t(Ae),i={show:!0,zlevel:0,z:0,inverse:!1,name:"",nameLocation:"end",nameTextStyle:{},nameGap:15,silent:!0,axisLine:{show:!0,onZero:!0,lineStyle:{color:"#333",width:1,type:"solid"}},axisTick:{show:!0,inside:!1,length:5,lineStyle:{color:"#333",width:1}},axisLabel:{show:!0,inside:!1,rotate:0,margin:8,textStyle:{color:"#333",fontSize:12}},splitLine:{show:!0,lineStyle:{color:["#ccc"],width:1,type:"solid"}},splitArea:{show:!1,areaStyle:{color:["rgba(250,250,250,0.3)","rgba(200,200,200,0.3)"]}}},n=e.merge({boundaryGap:!0,axisTick:{interval:"auto"},axisLabel:{interval:"auto"}},i),r=e[se]({boundaryGap:[0,0],splitNumber:5},i),a=e[se]({scale:!0,min:"dataMin",max:"dataMax"},r),o=e[se]({},r);
+return o.scale=!0,{categoryAxis:n,valueAxis:r,timeAxis:a,logAxis:o}}),e("zrender/animation/easing",[],function(){var t={linear:function(t){return t},quadraticIn:function(t){return t*t},quadraticOut:function(t){return t*(2-t)},quadraticInOut:function(t){return(t*=2)<1?.5*t*t:-.5*(--t*(t-2)-1)},cubicIn:function(t){return t*t*t},cubicOut:function(t){return--t*t*t+1},cubicInOut:function(t){return(t*=2)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},quarticIn:function(t){return t*t*t*t},quarticOut:function(t){return 1- --t*t*t*t},quarticInOut:function(t){return(t*=2)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},quinticIn:function(t){return t*t*t*t*t},quinticOut:function(t){return--t*t*t*t*t+1},quinticInOut:function(t){return(t*=2)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},sinusoidalIn:function(t){return 1-Math.cos(t*Math.PI/2)},sinusoidalOut:function(t){return Math.sin(t*Math.PI/2)},sinusoidalInOut:function(t){return.5*(1-Math.cos(Math.PI*t))},exponentialIn:function(t){return 0===t?0:Math.pow(1024,t-1)},exponentialOut:function(t){return 1===t?1:1-Math.pow(2,-10*t)},exponentialInOut:function(t){return 0===t?0:1===t?1:(t*=2)<1?.5*Math.pow(1024,t-1):.5*(-Math.pow(2,-10*(t-1))+2)},circularIn:function(t){return 1-Math.sqrt(1-t*t)},circularOut:function(t){return Math.sqrt(1- --t*t)},circularInOut:function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},elasticIn:function(t){var e,i=.1,n=.4;return 0===t?0:1===t?1:(!i||1>i?(i=1,e=n/4):e=n*Math.asin(1/i)/(2*Math.PI),-(i*Math.pow(2,10*(t-=1))*Math.sin(2*(t-e)*Math.PI/n)))},elasticOut:function(t){var e,i=.1,n=.4;return 0===t?0:1===t?1:(!i||1>i?(i=1,e=n/4):e=n*Math.asin(1/i)/(2*Math.PI),i*Math.pow(2,-10*t)*Math.sin(2*(t-e)*Math.PI/n)+1)},elasticInOut:function(t){var e,i=.1,n=.4;return 0===t?0:1===t?1:(!i||1>i?(i=1,e=n/4):e=n*Math.asin(1/i)/(2*Math.PI),(t*=2)<1?-.5*i*Math.pow(2,10*(t-=1))*Math.sin(2*(t-e)*Math.PI/n):i*Math.pow(2,-10*(t-=1))*Math.sin(2*(t-e)*Math.PI/n)*.5+1)},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){var e=1.70158;return--t*t*((e+1)*t+e)+1},backInOut:function(t){var e=2.5949095;return(t*=2)<1?.5*t*t*((e+1)*t-e):.5*((t-=2)*t*((e+1)*t+e)+2)},bounceIn:function(e){return 1-t.bounceOut(1-e)},bounceOut:function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},bounceInOut:function(e){return.5>e?.5*t.bounceIn(2*e):.5*t.bounceOut(2*e-1)+.5}};return t}),e("echarts/chart/helper/createListFromArray",[Ce,"../../data/List","../../data/helper/completeDimensions",Ae,"../../util/model","../../CoordinateSystem"],function(t){function e(t){for(var e=0;e<t[oe]&&null==t[e];)e++;return t[e]}function i(t){var i=e(t);return null!=i&&!f[j](v(i))}function r(t,e,n){if(t=t||[],!f[j](t))throw new Error("Invalid data.");var r=e.get(H),a=y[r],o=g.get(r),c=a&&a(t,e,n),p=c&&c[s];p||(p=o&&o[s]||["x","y"],p=d(p,t,p.concat(["value"])));var x,_=c&&c.categoryAxisModel,b=p[0].type===l?0:p[1].type===l?1:-1,w=new h(p,e),S=u(c,t),M=_&&i(t)?function(t,e,i,n){return n===b?i:m(v(t),p[n])}:function(t,e,i,n){var r=v(t),a=m(r&&r[n],p[n]);return b===n&&typeof a===_e&&(x=x||_.getCategories(),a=f[X](x,a),0>a&&!isNaN(a)&&(a=+a)),a};return w.initData(t,S,M),w}function a(t){return t!==c&&"time"!==t}function o(t){return t===c?l:"time"===t?"time":"float"}function u(t,e){var i=[];if(t&&t.categoryAxisModel){var n=t.categoryAxisModel.getCategories();if(n){var r=e[oe];if(f[j](e[0])&&e[0][oe]>1){i=[];for(var a=0;r>a;a++)i[a]=n[e[a][t.categoryIndex||0]]}else i=n.slice(0)}}return i}var h=t("../../data/List"),d=t("../../data/helper/completeDimensions"),f=t(Ae),p=t("../../util/model"),g=t("../../CoordinateSystem"),v=p.getDataItemValue,m=p.converDataValue,y={cartesian2d:function(t,e,i){var n=i[P]("xAxis",e.get("xAxisIndex")),r=i[P]("yAxis",e.get("yAxisIndex"));if(!n||!r)throw new Error("Axis option not found");var s=n.get("type"),l=r.get("type"),u=[{name:"x",type:o(s),stackable:a(s)},{name:"y",type:o(l),stackable:a(l)}],h=s===c;return d(u,t,["x","y","z"]),{dimensions:u,categoryIndex:h?0:1,categoryAxisModel:h?n:l===c?r:null}},polar:function(t,e,i){var r=e.get("polarIndex")||0,s=function(t){return t.get("polarIndex")===r},l=i.findComponents({mainType:"angleAxis",filter:s})[0],u=i.findComponents({mainType:"radiusAxis",filter:s})[0];if(!l||!u)throw new Error("Axis option not found");var h=u.get("type"),f=l.get("type"),p=[{name:"radius",type:o(h),stackable:a(h)},{name:"angle",type:o(f),stackable:a(f)}],g=f===c;return d(p,t,[n,"angle","value"]),{dimensions:p,categoryIndex:g?1:0,categoryAxisModel:g?l:h===c?u:null}},geo:function(t){return{dimensions:d([{name:"lng"},{name:"lat"}],t,["lng","lat","value"])}}};return r}),e("zrender/contain/line",[],function(){return{containStroke:function(t,e,i,n,r,a,o){if(0===r)return!1;var s=r,l=0,c=t;if(o>e+s&&o>n+s||e-s>o&&n-s>o||a>t+s&&a>i+s||t-s>a&&i-s>a)return!1;if(t===i)return Math.abs(a-t)<=s/2;l=(e-n)/(t-i),c=(t*n-i*e)/(t-i);var u=l*a-o+c,h=u*u/(l*l+1);return s/2*s/2>=h}}}),e("zrender/contain/cubic",[Ce,"../core/curve"],function(t){var e=t("../core/curve");return{containStroke:function(t,i,n,r,a,o,s,l,c,u,h){if(0===c)return!1;var d=c;if(h>i+d&&h>r+d&&h>o+d&&h>l+d||i-d>h&&r-d>h&&o-d>h&&l-d>h||u>t+d&&u>n+d&&u>a+d&&u>s+d||t-d>u&&n-d>u&&a-d>u&&s-d>u)return!1;var f=e.cubicProjectPoint(t,i,n,r,a,o,s,l,u,h,null);return d/2>=f}}}),e("zrender/contain/quadratic",[Ce,"../core/curve"],function(t){var e=t("../core/curve");return{containStroke:function(t,i,n,r,a,o,s,l,c){if(0===s)return!1;var u=s;if(c>i+u&&c>r+u&&c>o+u||i-u>c&&r-u>c&&o-u>c||l>t+u&&l>n+u&&l>a+u||t-u>l&&n-u>l&&a-u>l)return!1;var h=e.quadraticProjectPoint(t,i,n,r,a,o,l,c,null);return u/2>=h}}}),e("zrender/contain/arc",[Ce,"./util"],function(t){var e=t("./util").normalizeRadian,i=2*Math.PI;return{containStroke:function(t,n,r,a,o,s,l,c,u){if(0===l)return!1;var h=l;c-=t,u-=n;var d=Math.sqrt(c*c+u*u);if(d-h>r||r>d+h)return!1;if(Math.abs(a-o)%i<1e-4)return!0;if(s){var f=a;a=e(o),o=e(f)}else a=e(a),o=e(o);a>o&&(o+=i);var p=Math.atan2(u,c);return 0>p&&(p+=i),p>=a&&o>=p||p+i>=a&&o>=p+i}}}),e("zrender/contain/util",[Ce],function(){var t=2*Math.PI;return{normalizeRadian:function(e){return e%=t,0>e&&(e+=t),e}}}),e("zrender/contain/windingLine",[],function(){return function(t,e,i,n,r,a){if(a>e&&a>n||e>a&&n>a)return 0;if(n===e)return 0;var o=e>n?1:-1,s=(a-e)/(n-e),l=s*(i-t)+t;return l>r?o:0}}),e("zrender/graphic/helper/roundRect",[Ce],function(){return{buildPath:function(t,e){var n,r,a,o,s=e.x,l=e.y,c=e.width,u=e[fe],h=e.r;0>c&&(s+=c,c=-c),0>u&&(l+=u,u=-u),"number"==typeof h?n=r=a=o=h:h instanceof Array?1===h[oe]?n=r=a=o=h[0]:2===h[oe]?(n=a=h[0],r=o=h[1]):3===h[oe]?(n=h[0],r=o=h[1],a=h[2]):(n=h[0],r=h[1],a=h[2],o=h[3]):n=r=a=o=0;var d;n+r>c&&(d=n+r,n*=c/d,r*=c/d),a+o>c&&(d=a+o,a*=c/d,o*=c/d),r+a>u&&(d=r+a,r*=u/d,a*=u/d),n+o>u&&(d=n+o,n*=u/d,o*=u/d),t[i](s+n,l),t.lineTo(s+c-r,l),0!==r&&t.quadraticCurveTo(s+c,l,s+c,l+r),t.lineTo(s+c,l+u-a),0!==a&&t.quadraticCurveTo(s+c,l+u,s+c-a,l+u),t.lineTo(s+o,l+u),0!==o&&t.quadraticCurveTo(s,l+u,s,l+u-o),t.lineTo(s,l+n),0!==n&&t.quadraticCurveTo(s,l,s+n,l)}}}),e("zrender/core/LRU",[Ce],function(){var t=function(){this.head=null,this.tail=null,this._len=0},e=t[be];e.insert=function(t){var e=new i(t);return this.insertEntry(e),e},e.insertEntry=function(t){this.head?(this.tail.next=t,t.prev=this.tail,this.tail=t):this.head=this.tail=t,this._len++},e[ce]=function(t){var e=t.prev,i=t.next;e?e.next=i:this.head=i,i?i.prev=e:this.tail=e,t.next=t.prev=null,this._len--},e.len=function(){return this._len};var i=function(t){this.value=t,this.next,this.prev},n=function(e){this._list=new t,this._map={},this._maxSize=e||10},r=n[be];return r.put=function(t,e){var i=this._list,n=this._map;if(null==n[t]){var r=i.len();if(r>=this._maxSize&&r>0){var a=i.head;i[ce](a),delete n[a.key]}var o=i.insert(e);o.key=t,n[t]=o}},r.get=function(t){var e=this._map[t],i=this._list;return null!=e?(e!==i.tail&&(i[ce](e),i.insertEntry(e)),e.value):void 0},r.clear=function(){this._list.clear(),this._map={}},n}),e("echarts/data/List",[Ce,"../model/Model","./DataDiffer",Ae,"../util/model"],function(t){function e(t){return f[j](t)||(t=[t]),t}function i(t,e){var i=t[s],n=new x(f.map(i,t.getDimensionInfo,t),t.hostModel);y(n,t);for(var r=n._storage={},a=t._storage,o=0;o<i[oe];o++){var l=i[o],c=a[l];r[l]=f[X](e,l)>=0?new c.constructor(a[l][oe]):a[l]}return n}var n=p,r=typeof window===p?global:window,a=typeof r.Float64Array===n?Array:r.Float64Array,o=typeof r.Int32Array===n?Array:r.Int32Array,c={"float":a,"int":o,ordinal:Array,number:Array,time:Array},u=t("../model/Model"),d=t("./DataDiffer"),f=t(Ae),g=t("../util/model"),v=f[ue],m=["stackedOn","_nameList","_idList","_rawData"],y=function(t,e){f.each(m.concat(e.__wrappedMethods||[]),function(i){e.hasOwnProperty(i)&&(t[i]=e[i])}),t.__wrappedMethods=e.__wrappedMethods},x=function(t,e){t=t||["x","y"];for(var i={},n=[],r=0;r<t[oe];r++){var a,o={};typeof t[r]===_e?(a=t[r],o={name:a,stackable:!1,type:"number"}):(o=t[r],a=o.name,o.type=o.type||"number"),n.push(a),i[a]=o}this[s]=n,this._dimensionInfos=i,this.hostModel=e,this.dataType,this.indices=[],this._storage={},this._nameList=[],this._idList=[],this._optionModels=[],this.stackedOn=null,this._visual={},this._layout={},this._itemVisuals=[],this._itemLayouts=[],this._graphicEls=[],this._rawData,this._extent},_=x[be];_.type="list",_.getDimension=function(t){return isNaN(t)||(t=this[s][t]||t),t},_.getDimensionInfo=function(t){return f.clone(this._dimensionInfos[this.getDimension(t)])},_.initData=function(t,e,i){if(t=t||[],!f[j](t))throw new Error("Invalid data.");this._rawData=t;var n=this._storage={},r=this.indices=[],a=this[s],o=t[oe],l=this._dimensionInfos,u=[],h={};e=e||[];for(var d=0;d<a[oe];d++){var p=l[a[d]],v=c[p.type];n[a[d]]=new v(o)}i=i||function(t,e,i,n){var r=g.getDataItemValue(t);return g.converDataValue(f[j](r)?r[n]:r,l[e])};for(var m=0;m<t[oe];m++){for(var y=t[m],x=0;x<a[oe];x++){var _=a[x],b=n[_];b[m]=i(y,_,m,x)}r.push(m)}for(var d=0;d<t[oe];d++){var w="";e[d]||(e[d]=t[d].name,w=t[d].id);var S=e[d]||"";!w&&S&&(h[S]=h[S]||0,w=S,h[S]>0&&(w+="__ec__"+h[S]),h[S]++),w&&(u[d]=w)}this._nameList=e,this._idList=u},_.count=function(){return this.indices[oe]},_.get=function(t,e,i){var n=this._storage,r=this.indices[e];if(null==r)return 0/0;var a=n[t]&&n[t][r];if(i){var o=this._dimensionInfos[t];if(o&&o.stackable)for(var s=this.stackedOn;s;){var l=s.get(t,e);(a>=0&&l>0||0>=a&&0>l)&&(a+=l),s=s.stackedOn}}return a},_.getValues=function(t,e,i){var n=[];f[j](t)||(i=e,e=t,t=this[s]);for(var r=0,a=t[oe];a>r;r++)n.push(this.get(t[r],e,i));return n},_.hasValue=function(t){for(var e=this[s],i=this._dimensionInfos,n=0,r=e[oe];r>n;n++)if(i[e[n]].type!==l&&isNaN(this.get(e[n],t)))return!1;return!0},_.getDataExtent=function(t,e){var i=this._storage[t],n=this.getDimensionInfo(t);e=n&&n.stackable&&e;var r,a=(this._extent||(this._extent={}))[t+!!e];if(a)return a;if(i){for(var o=1/0,s=-1/0,l=0,c=this.count();c>l;l++)r=this.get(t,l,e),o>r&&(o=r),r>s&&(s=r);return this._extent[t+e]=[o,s]}return[1/0,-1/0]},_.getSum=function(t,e){var i=this._storage[t],n=0;if(i)for(var r=0,a=this.count();a>r;r++){var o=this.get(t,r,e);isNaN(o)||(n+=o)}return n},_[X]=function(t,e){var i=this._storage,n=i[t],r=this.indices;if(n)for(var a=0,o=r[oe];o>a;a++){var s=r[a];if(n[s]===e)return a}return-1},_.indexOfName=function(t){for(var e=this.indices,i=this._nameList,n=0,r=e[oe];r>n;n++){var a=e[n];if(i[a]===t)return n}return-1},_.indexOfNearest=function(t,e,i){var n=this._storage,r=n[t];if(r){for(var a=Number.MAX_VALUE,o=-1,s=0,l=this.count();l>s;s++){var c=e-this.get(t,s,i),u=Math.abs(c);(a>u||u===a&&c>0)&&(a=u,o=s)}return o}return-1},_.getRawIndex=function(t){var e=this.indices[t];return null==e?-1:e},_.getRawDataItem=function(t){return this._rawData[this.getRawIndex(t)]},_[T]=function(t){return this._nameList[this.indices[t]]||""},_.getId=function(t){return this._idList[this.indices[t]]||this.getRawIndex(t)+""},_.each=function(t,i,n,r){typeof t===Z&&(r=n,n=i,i=t,t=[]),t=f.map(e(t),this.getDimension,this);var a=[],o=t[oe],s=this.indices;r=r||this;for(var l=0;l<s[oe];l++)if(0===o)i.call(r,l);else if(1===o)i.call(r,this.get(t[0],l,n),l);else{for(var c=0;o>c;c++)a[c]=this.get(t[c],l,n);a[c]=l,i.apply(r,a)}},_.filterSelf=function(t,i,n,r){typeof t===Z&&(r=n,n=i,i=t,t=[]),t=f.map(e(t),this.getDimension,this);var a=[],o=[],s=t[oe],l=this.indices;r=r||this;for(var c=0;c<l[oe];c++){var u;if(1===s)u=i.call(r,this.get(t[0],c,n),c);else{for(var h=0;s>h;h++)o[h]=this.get(t[h],c,n);o[h]=c,u=i.apply(r,o)}u&&a.push(l[c])}return this.indices=a,this._extent={},this},_.mapArray=function(t,e,i,n){typeof t===Z&&(n=i,i=e,e=t,t=[]);var r=[];return this.each(t,function(){r.push(e&&e.apply(this,arguments))},i,n),r},_.map=function(t,n,r,a){t=f.map(e(t),this.getDimension,this);var o=i(this,t),s=o.indices=this.indices,l=o._storage,c=[];return this.each(t,function(){var e=arguments[arguments[oe]-1],i=n&&n.apply(this,arguments);if(null!=i){"number"==typeof i&&(c[0]=i,i=c);for(var r=0;r<i[oe];r++){var a=t[r],o=l[a],u=s[e];o&&(o[u]=i[r])}}},r,a),o},_.downSample=function(t,e,n,r){for(var a=i(this,[t]),o=this._storage,s=a._storage,l=this.indices,c=a.indices=[],u=[],h=[],d=Math.floor(1/e),f=s[t],p=this.count(),g=0;g<o[t][oe];g++)s[t][g]=o[t][g];for(var g=0;p>g;g+=d){d>p-g&&(d=p-g,u[oe]=d);for(var v=0;d>v;v++){var m=l[g+v];u[v]=f[m],h[v]=m}var y=n(u),m=h[r(u,y)||0];f[m]=y,c.push(m)}return a},_[h]=function(t){var e=this.hostModel;return t=this.indices[t],new u(this._rawData[t],e,e&&e[L])},_.diff=function(t){var e=this._idList,i=t&&t._idList;return new d(t?t.indices:[],this.indices,function(t){return i[t]||t+""},function(t){return e[t]||t+""})},_.getVisual=function(t){var e=this._visual;return e&&e[t]},_.setVisual=function(t,e){if(v(t))for(var i in t)t.hasOwnProperty(i)&&this.setVisual(i,t[i]);else this._visual=this._visual||{},this._visual[t]=e},_.setLayout=function(t,e){if(v(t))for(var i in t)t.hasOwnProperty(i)&&this.setLayout(i,t[i]);else this._layout[t]=e},_.getLayout=function(t){return this._layout[t]},_.getItemLayout=function(t){return this._itemLayouts[t]},_.setItemLayout=function(t,e,i){this._itemLayouts[t]=i?f[le](this._itemLayouts[t]||{},e):e},_.clearItemLayouts=function(){this._itemLayouts[oe]=0},_[C]=function(t,e,i){var n=this._itemVisuals[t],r=n&&n[e];return null!=r||i?r:this.getVisual(e)},_.setItemVisual=function(t,e,i){var n=this._itemVisuals[t]||{};if(this._itemVisuals[t]=n,v(e))for(var r in e)e.hasOwnProperty(r)&&(n[r]=e[r]);else n[e]=i};var b=function(t){t[$]=this[$],t[K]=this[K],t.dataType=this.dataType};return _.setItemGraphicEl=function(t,e){var i=this.hostModel;e&&(e[K]=t,e.dataType=this.dataType,e[$]=i&&i[$],"group"===e.type&&e.traverse(b,e)),this._graphicEls[t]=e},_[S]=function(t){return this._graphicEls[t]},_.eachItemGraphicEl=function(t,e){f.each(this._graphicEls,function(i,n){i&&t&&t.call(e,i,n)})},_.cloneShallow=function(){var t=f.map(this[s],this.getDimensionInfo,this),e=new x(t,this.hostModel);return e._storage=this._storage,y(e,this),e.indices=this.indices.slice(),e},_.wrapMethod=function(t,e){var i=this[t];typeof i===Z&&(this.__wrappedMethods=this.__wrappedMethods||[],this.__wrappedMethods.push(t),this[t]=function(){var t=i.apply(this,arguments);return e.apply(this,[t].concat(f.slice(arguments)))})},_.TRANSFERABLE_METHODS=["cloneShallow","downSample","map"],_.CHANGABLE_METHODS=["filterSelf"],x}),e("echarts/data/helper/completeDimensions",[Ce,Ae],function(t){function e(t,e,a,o){if(!e)return t;var s=n(e[0]),l=r[j](s)&&s[oe]||1;a=a||[],o=o||"extra";for(var c=0;l>c;c++)if(!t[c]){var u=a[c]||o+(c-a[oe]);t[c]=i(e,c)?{type:"ordinal",name:u}:u}return t}function i(t,e){for(var i=0,a=t[oe];a>i;i++){var o=n(t[i]);if(!r[j](o))return!1;var o=o[e];if(null!=o&&isFinite(o))return!1;if(r.isString(o)&&"-"!==o)return!0}return!1}function n(t){return r[j](t)?t:r[ue](t)?t.value:t}var r=t(Ae);return e}),e("zrender/graphic/helper/poly",[Ce,"./smoothSpline","./smoothBezier"],function(t){var e=t("./smoothSpline"),n=t("./smoothBezier");return{buildPath:function(t,r,a){var o=r.points,s=r.smooth;if(o&&o[oe]>=2){if(s&&"spline"!==s){var l=n(o,s,a,r.smoothConstraint);t[i](o[0][0],o[0][1]);for(var c=o[oe],u=0;(a?c:c-1)>u;u++){var h=l[2*u],d=l[2*u+1],f=o[(u+1)%c];t.bezierCurveTo(h[0],h[1],d[0],d[1],f[0],f[1])}}else{"spline"===s&&(o=e(o,a)),t[i](o[0][0],o[0][1]);for(var u=1,p=o[oe];p>u;u++)t.lineTo(o[u][0],o[u][1])}a&&t.closePath()}}}}),e("zrender/Handler",[Ce,"./core/env","./core/event","./core/util","./mixin/Draggable","./core/GestureMgr","./mixin/Eventful"],function(t){function e(t,e,i){return{type:t,event:i,target:e,cancelBubble:!1,offsetX:i.zrX,offsetY:i.zrY,gestureEvent:i.gestureEvent,pinchX:i.pinchX,pinchY:i.pinchY,pinchScale:i.pinchScale,wheelDelta:i.zrDelta}}function i(t,e,i){var n=t._gestureMgr;"start"===i&&n.clear();var r=n.recognize(e,t.findHover(e.zrX,e.zrY,null));if("end"===i&&n.clear(),r){var a=r.type;e.gestureEvent=a,t._dispatchProxy(r[J],a,r.event)}}function n(t){function e(t,e){return function(){return e._touching?void 0:t.apply(e,arguments)}}for(var i=v.concat(m),n=0;n<i[oe];n++){var r=i[n];t._handlers[r]=h.bind(w[r],t)}for(var n=0;n<g[oe];n++){var r=g[n];t._handlers[r]=e(w[r],t)}}function r(t,e,i){if(t[t.rectHover?"rectContain":D](e,i)){for(var n=t;n;){if(n.silent||n.clipPath&&!n.clipPath[D](e,i))return!1;n=n.parent}return!0}return!1}function a(t){t._touching=!0,clearTimeout(t._touchTimer),t._touchTimer=setTimeout(function(){t._touching=!1},700)}function o(){return!1}function s(){return c.touchEventsSupported}function l(t){return"mousewheel"===t&&c.browser.firefox?"DOMMouseScroll":t}var c=t("./core/env"),u=t("./core/event"),h=t("./core/util"),d=t("./mixin/Draggable"),f=t("./core/GestureMgr"),p=t("./mixin/Eventful"),g=["click","dblclick","mousewheel",te];!o()&&g.push("mouseup","mousedown","mousemove");var v=["touchstart","touchend","touchmove"],m=["pointerdown","pointerup","pointermove"],y=300,x=u.addEventListener,_=u.removeEventListener,b=u.normalizeEvent,w={mousemove:function(t){t=b(this.root,t);var e=t.zrX,i=t.zrY,n=this.findHover(e,i,null),r=this._hovered;this._hovered=n,this.root.style.cursor=n?n.cursor:this._defaultCursorStyle,r&&n!==r&&r.__zr&&this._dispatchProxy(r,te,t),this._dispatchProxy(n,"mousemove",t),n&&n!==r&&this._dispatchProxy(n,ee,t)},mouseout:function(t){t=b(this.root,t);var e=t.toElement||t.relatedTarget;if(e!=this.root)for(;e&&9!=e.nodeType;){if(e===this.root)return;e=e.parentNode}this._dispatchProxy(this._hovered,te,t),this[ae]("globalout",{event:t})},touchstart:function(t){t=b(this.root,t),this._lastTouchMoment=new Date,i(this,t,"start"),w.mousemove.call(this,t),w.mousedown.call(this,t),a(this)},touchmove:function(t){t=b(this.root,t),i(this,t,"change"),w.mousemove.call(this,t),a(this)},touchend:function(t){t=b(this.root,t),i(this,t,"end"),w.mouseup.call(this,t),+new Date-this._lastTouchMoment<y&&w.click.call(this,t),a(this)}};h.each(["click","mousedown","mouseup","mousewheel","dblclick"],function(t){w[t]=function(e){e=b(this.root,e);var i=this.findHover(e.zrX,e.zrY,null);if("mousedown"===t)this._downel=i,this._upel=i;else if("mosueup"===t)this._upel=i;else if("click"===t&&this._downel!==this._upel)return;this._dispatchProxy(i,t,e)}});var S=function(t,e,i){function r(e,i){h.each(e,function(e){x(t,l(e),i._handlers[e])},i)}p.call(this),this.root=t,this.storage=e,this.painter=i,this._hovered,this._lastTouchMoment,this._lastX,this._lastY,this._defaultCursorStyle="default",this._gestureMgr=new f,this._handlers=[],this._touching=!1,this._touchTimer,n(this),o()?r(m,this):s()&&r(v,this),r(g,this),d.call(this)};return S[be]={constructor:S,resize:function(){this._hovered=null},dispatch:function(t,e){var i=this._handlers[t];i&&i.call(this,e)},dispose:function(){for(var t=this.root,e=g.concat(v),i=0;i<e[oe];i++){var n=e[i];_(t,l(n),this._handlers[n])}this.root=this.storage=this.painter=null},setDefaultCursorStyle:function(t){this._defaultCursorStyle=t},_dispatchProxy:function(t,i,n){for(var r="on"+i,a=e(i,t,n),o=t;o&&(o[r]&&(a.cancelBubble=o[r].call(o,a)),o[ae](i,a),o=o.parent,!a.cancelBubble););a.cancelBubble||(this[ae](i,a),this.painter&&this.painter.eachOtherLayer(function(t){typeof t[r]==Z&&t[r].call(t,a),t[ae]&&t[ae](i,a)}))},findHover:function(t,e,i){for(var n=this.storage.getDisplayList(),a=n[oe]-1;a>=0;a--)if(!n[a].silent&&n[a]!==i&&!n[a][ge]&&r(n[a],t,e))return n[a]}},h.mixin(S,p),h.mixin(S,d),S}),e("zrender/Storage",[Ce,"./core/util","./container/Group"],function(t){function e(t,e){return t[Y]===e[Y]?t.z===e.z?t.z2===e.z2?t.__renderidx-e.__renderidx:t.z2-e.z2:t.z-e.z:t[Y]-e[Y]}var i=t("./core/util"),n=t("./container/Group"),r=function(){this._elements={},this._roots=[],this._displayList=[],this._displayListLen=0};return r[be]={constructor:r,getDisplayList:function(t,e){return e=e||!1,t&&this.updateDisplayList(e),this._displayList},updateDisplayList:function(t){this._displayListLen=0;for(var i=this._roots,n=this._displayList,r=0,a=i[oe];a>r;r++)this._updateAndAddDisplayable(i[r],null,t);n[oe]=this._displayListLen;for(var r=0,a=n[oe];a>r;r++)n[r].__renderidx=r;n.sort(e)},_updateAndAddDisplayable:function(t,e,i){if(!t[ge]||i){t.beforeUpdate(),t[he](),t.afterUpdate();var n=t.clipPath;if(n&&(n.parent=t,n.updateTransform(),e?(e=e.slice(),e.push(n)):e=[n]),"group"==t.type){for(var r=t._children,a=0;a<r[oe];a++){var o=r[a];o.__dirty=t.__dirty||o.__dirty,this._updateAndAddDisplayable(o,e,i)}t.__dirty=!1}else t.__clipPaths=e,this._displayList[this._displayListLen++]=t}},addRoot:function(t){this._elements[t.id]||(t instanceof n&&t.addChildrenToStorage(this),this.addToMap(t),this._roots.push(t))},delRoot:function(t){if(null==t){for(var e=0;e<this._roots[oe];e++){var r=this._roots[e];r instanceof n&&r.delChildrenFromStorage(this)}return this._elements={},this._roots=[],this._displayList=[],void(this._displayListLen=0)}if(t instanceof Array)for(var e=0,a=t[oe];a>e;e++)this.delRoot(t[e]);else{var o;o=typeof t==_e?this._elements[t]:t;var s=i[X](this._roots,o);s>=0&&(this.delFromMap(o.id),this._roots[ne](s,1),o instanceof n&&o.delChildrenFromStorage(this))}},addToMap:function(t){return t instanceof n&&(t.__storage=this),t.dirty(),this._elements[t.id]=t,this},get:function(t){return this._elements[t]},delFromMap:function(t){var e=this._elements,i=e[t];return i&&(delete e[t],i instanceof n&&(i.__storage=null)),this},dispose:function(){this._elements=this._renderList=this._roots=null}},r}),e("zrender/animation/Animation",[Ce,d,"../core/event","./Animator"],function(t){var e=t(d),i=t("../core/event").Dispatcher,n=typeof window!==p&&(window.requestAnimationFrame||window.msRequestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame)||function(t){setTimeout(t,16)},r=t("./Animator"),a=function(t){t=t||{},this.stage=t.stage||{},this.onframe=t.onframe||function(){},this._clips=[],this._running=!1,this._time=0,i.call(this)};return a[be]={constructor:a,addClip:function(t){this._clips.push(t)},addAnimator:function(t){t[v]=this;for(var e=t.getClips(),i=0;i<e[oe];i++)this.addClip(e[i])},removeClip:function(t){var i=e[X](this._clips,t);i>=0&&this._clips[ne](i,1)},removeAnimator:function(t){for(var e=t.getClips(),i=0;i<e[oe];i++)this.removeClip(e[i]);t[v]=null},_update:function(){for(var t=(new Date).getTime(),e=t-this._time,i=this._clips,n=i[oe],r=[],a=[],o=0;n>o;o++){var s=i[o],l=s.step(t);l&&(r.push(l),a.push(s))}for(var o=0;n>o;)i[o]._needsRemove?(i[o]=i[n-1],i.pop(),n--):o++;n=r[oe];for(var o=0;n>o;o++)a[o].fire(r[o]);this._time=t,this.onframe(e),this[ae]("frame",e),this.stage[he]&&this.stage[he]()},start:function(){function t(){e._running&&(n(t),e._update())}var e=this;this._running=!0,this._time=(new Date).getTime(),n(t)},stop:function(){this._running=!1},clear:function(){this._clips=[]},animate:function(t,e){e=e||{};var i=new r(t,e.loop,e.getter,e.setter);return i}},e.mixin(a,i),a}),e("zrender/Painter",[Ce,"./config","./core/util","./core/log","./core/BoundingRect","./Layer","./graphic/Image"],function(t){function e(t){return parseInt(t,10)}function i(t){return t?t.isBuildin?!0:typeof t[xe]!==Z||typeof t.refresh!==Z?!1:!0:!1}function n(t){t.__unusedCount++}function r(t){t.__dirty=!1,1==t.__unusedCount&&t.clear()}function a(t,e,i){return p.copy(t[N]()),t[Me]&&p[b](t[Me]),g.width=e,g[fe]=i,!p.intersect(g)}function o(t,e){if(!t||!e||t[oe]!==e[oe])return!0;for(var i=0;i<t[oe];i++)if(t[i]!==e[i])return!0}function s(t,e){for(var i=0;i<t[oe];i++){var n,r=t[i];r[Me]&&(n=r[Me],e[Me](n[0],n[1],n[2],n[3],n[4],n[5]));var a=r.path;a.beginPath(e),r.buildPath(a,r.shape),e.clip(),r[Me]&&(n=r.invTransform,e[Me](n[0],n[1],n[2],n[3],n[4],n[5]))}}var l=t("./config"),c=t("./core/util"),u=t("./core/log"),h=t("./core/BoundingRect"),d=t("./Layer"),p=new h(0,0,0,0),g=new h(0,0,0,0),v=function(t,e,i){var n=!t.nodeName||"CANVAS"===t.nodeName.toUpperCase();i=i||{},this.dpr=i.devicePixelRatio||l.devicePixelRatio,this._singleCanvas=n,this.root=t;var r=t.style;if(r&&(r["-webkit-tap-highlight-color"]="transparent",r["-webkit-user-select"]="none",r["user-select"]="none",r["-webkit-touch-callout"]="none",t.innerHTML=""),this.storage=e,n){var a=t.width,o=t[fe];this._width=a,this._height=o;var s=new d(t,this,1);s.initContext(),this._layers={0:s},this._zlevelList=[0]}else{var a=this._getWidth(),o=this._getHeight();this._width=a,this._height=o;var c=document[f]("div");this._domRoot=c;var u=c.style;u[R]="relative",u.overflow="hidden",u.width=this._width+"px",u[fe]=this._height+"px",t.appendChild(c),this._layers={},this._zlevelList=[]}this._layerConfig={},this.pathToImage=this._createPathToImage()};return v[be]={constructor:v,isSingleCanvas:function(){return this._singleCanvas},getViewportRoot:function(){return this._singleCanvas?this._layers[0].dom:this._domRoot},refresh:function(t){var e=this.storage.getDisplayList(!0),i=this._zlevelList;this._paintList(e,t);for(var n=0;n<i[oe];n++){var r=i[n],a=this._layers[r];!a.isBuildin&&a.refresh&&a.refresh()}return this},_paintList:function(t,e){null==e&&(e=!1),this._updateLayerStatus(t);var i,l,c,h=this._width,d=this._height;this.eachBuildinLayer(n);for(var f=null,p=0,g=t[oe];g>p;p++){var v=t[p],m=this._singleCanvas?0:v[Y];if(l!==m&&(l=m,i=this.getLayer(l),i.isBuildin||u("ZLevel "+l+" has been used by unkown layer "+i.id),c=i.ctx,i.__unusedCount=0,(i.__dirty||e)&&i.clear()),(i.__dirty||e)&&!v.invisible&&0!==v.style[O]&&v.scale[0]&&v.scale[1]&&(!v.culling||!a(v,h,d))){var y=v.__clipPaths;o(y,f)&&(f&&c.restore(),y&&(c.save(),s(y,c)),f=y),v.beforeBrush&&v.beforeBrush(c),v.brush(c,!1),v.afterBrush&&v.afterBrush(c)}v.__dirty=!1}f&&c.restore(),this.eachBuildinLayer(r)},getLayer:function(t){if(this._singleCanvas)return this._layers[0];var e=this._layers[t];return e||(e=new d("zr_"+t,this,this.dpr),e.isBuildin=!0,this._layerConfig[t]&&c.merge(e,this._layerConfig[t],!0),this.insertLayer(t,e),e.initContext()),e},insertLayer:function(t,e){var n=this._layers,r=this._zlevelList,a=r[oe],o=null,s=-1,l=this._domRoot;if(n[t])return void u("ZLevel "+t+" has been used already");if(!i(e))return void u("Layer of zlevel "+t+" is not valid");if(a>0&&t>r[0]){for(s=0;a-1>s&&!(r[s]<t&&r[s+1]>t);s++);o=n[r[s]]}if(r[ne](s+1,0,t),o){var c=o.dom;c.nextSibling?l.insertBefore(e.dom,c.nextSibling):l.appendChild(e.dom)}else l.firstChild?l.insertBefore(e.dom,l.firstChild):l.appendChild(e.dom);n[t]=e},eachLayer:function(t,e){var i,n,r=this._zlevelList;for(n=0;n<r[oe];n++)i=r[n],t.call(e,this._layers[i],i)},eachBuildinLayer:function(t,e){var i,n,r,a=this._zlevelList;for(r=0;r<a[oe];r++)n=a[r],i=this._layers[n],i.isBuildin&&t.call(e,i,n)},eachOtherLayer:function(t,e){var i,n,r,a=this._zlevelList;for(r=0;r<a[oe];r++)n=a[r],i=this._layers[n],i.isBuildin||t.call(e,i,n)},getLayers:function(){return this._layers},_updateLayerStatus:function(t){var e=this._layers,i={};this.eachBuildinLayer(function(t,e){i[e]=t.elCount,t.elCount=0});for(var n=0,r=t[oe];r>n;n++){var a=t[n],o=this._singleCanvas?0:a[Y],s=e[o];if(s){if(s.elCount++,s.__dirty)continue;s.__dirty=a.__dirty}}this.eachBuildinLayer(function(t,e){i[e]!==t.elCount&&(t.__dirty=!0)})},clear:function(){return this.eachBuildinLayer(this._clearLayer),this},_clearLayer:function(t){t.clear()},configLayer:function(t,e){if(e){var i=this._layerConfig;i[t]?c.merge(i[t],e,!0):i[t]=e;var n=this._layers[t];n&&c.merge(n,i[t],!0)}},delLayer:function(t){var e=this._layers,i=this._zlevelList,n=e[t];n&&(n.dom.parentNode.removeChild(n.dom),delete e[t],i[ne](c[X](i,t),1))},resize:function(t,e){var i=this._domRoot;if(i.style.display="none",t=t||this._getWidth(),e=e||this._getHeight(),i.style.display="",this._width!=t||e!=this._height){i.style.width=t+"px",i.style[fe]=e+"px";for(var n in this._layers)this._layers[n][xe](t,e);this.refresh(!0)}return this._width=t,this._height=e,this},clearLayer:function(t){var e=this._layers[t];e&&e.clear()},dispose:function(){this.root.innerHTML="",this.root=this.storage=this._domRoot=this._layers=null},getRenderedCanvas:function(t){if(t=t||{},this._singleCanvas)return this._layers[0].dom;var e=new d("image",this,t.pixelRatio||this.dpr);e.initContext();var i=e.ctx;e.clearColor=t.backgroundColor,e.clear();for(var n=this.storage.getDisplayList(!0),r=0;r<n[oe];r++){var a=n[r];a.invisible||(a.beforeBrush&&a.beforeBrush(i),a.brush(i,!1),a.afterBrush&&a.afterBrush(i))}return e.dom},getWidth:function(){return this._width},getHeight:function(){return this._height},_getWidth:function(){var t=this.root,i=document.defaultView.getComputedStyle(t);return(t.clientWidth||e(i.width)||e(t.style.width))-(e(i.paddingLeft)||0)-(e(i.paddingRight)||0)|0},_getHeight:function(){var t=this.root,i=document.defaultView.getComputedStyle(t);return(t.clientHeight||e(i[fe])||e(t.style[fe]))-(e(i.paddingTop)||0)-(e(i.paddingBottom)||0)|0},_pathToImage:function(e,i,n,r,a){var o=document[f]("canvas"),s=o.getContext("2d");o.width=n*a,o[fe]=r*a,s.clearRect(0,0,n*a,r*a);var l={position:i[R],rotation:i.rotation,scale:i.scale};i[R]=[0,0,0],i.rotation=0,i.scale=[1,1],i&&i.brush(s);var c=t("./graphic/Image"),u=new c({id:e,style:{x:0,y:0,image:o}});return null!=l[R]&&(u[R]=i[R]=l[R]),null!=l.rotation&&(u.rotation=i.rotation=l.rotation),null!=l.scale&&(u.scale=i.scale=l.scale),u},_createPathToImage:function(){var t=this;return function(e,i,n,r){return t._pathToImage(e,i,n,r,t.dpr)}}},v}),e("echarts/data/DataDiffer",[Ce],function(){function t(t){return t}function e(e,i,n,r){this._old=e,this._new=i,this._oldKeyGetter=n||t,this._newKeyGetter=r||t}function i(t,e,i){for(var n=0;n<t[oe];n++){var r=i(t[n]),a=e[r];null==a?e[r]=n:(a[oe]||(e[r]=a=[a]),a.push(n))}}return e[be]={constructor:e,add:function(t){return this._add=t,this},update:function(t){return this._update=t,this},remove:function(t){return this._remove=t,this},execute:function(){var t,e=this._old,n=this._new,r=this._oldKeyGetter,a=this._newKeyGetter,o={},s={};for(i(e,o,r),i(n,s,a),t=0;t<e[oe];t++){var l=r(e[t]),c=s[l];if(null!=c){var u=c[oe];u?(1===u&&(s[l]=null),c=c.unshift()):s[l]=null,this._update&&this._update(c,t)}else this._remove&&this._remove(t)}for(var l in s)if(s.hasOwnProperty(l)){var c=s[l];if(null==c)continue;if(c[oe])for(var t=0,u=c[oe];u>t;t++)this._add&&this._add(c[t]);else this._add&&this._add(c)}}},e}),e("zrender/graphic/helper/smoothSpline",[Ce,"../../core/vector"],function(t){function e(t,e,i,n,r,a,o){var s=.5*(i-t),l=.5*(n-e);return(2*(e-i)+s+l)*o+(-3*(e-i)-2*s-l)*a+s*r+e}var i=t("../../core/vector");return function(t,n){for(var r=t[oe],a=[],o=0,s=1;r>s;s++)o+=i.distance(t[s-1],t[s]);var l=o/2;l=r>l?r:l;for(var s=0;l>s;s++){var c,u,h,d=s/(l-1)*(n?r:r-1),f=Math.floor(d),p=d-f,g=t[f%r];n?(c=t[(f-1+r)%r],u=t[(f+1)%r],h=t[(f+2)%r]):(c=t[0===f?f:f-1],u=t[f>r-2?r-1:f+1],h=t[f>r-3?r-1:f+2]);var v=p*p,m=p*v;a.push([e(c[0],g[0],u[0],h[0],p,v,m),e(c[1],g[1],u[1],h[1],p,v,m)])}return a}}),e("zrender/graphic/helper/smoothBezier",[Ce,"../../core/vector"],function(t){var e=t("../../core/vector"),i=e.min,n=e.max,r=e.scale,a=e.distance,o=e.add;return function(t,s,l,c){var u,h,d,f,p=[],g=[],v=[],m=[];if(c){d=[1/0,1/0],f=[-1/0,-1/0];
+for(var y=0,x=t[oe];x>y;y++)i(d,d,t[y]),n(f,f,t[y]);i(d,d,c[0]),n(f,f,c[1])}for(var y=0,x=t[oe];x>y;y++){var _=t[y];if(l)u=t[y?y-1:x-1],h=t[(y+1)%x];else{if(0===y||y===x-1){p.push(e.clone(t[y]));continue}u=t[y-1],h=t[y+1]}e.sub(g,h,u),r(g,g,s);var b=a(_,u),w=a(_,h),S=b+w;0!==S&&(b/=S,w/=S),r(v,g,-b),r(m,g,w);var M=o([],_,v),A=o([],_,m);c&&(n(M,M,d),i(M,M,f),n(A,A,d),i(A,A,f)),p.push(M),p.push(A)}return l&&p.push(p.shift()),p}}),e("zrender/core/event",[Ce,"../mixin/Eventful"],function(t){function e(t){return t.getBoundingClientRect?t.getBoundingClientRect():{left:0,top:0}}function i(t,i){if(i=i||window.event,null!=i.zrX)return i;var n=i.type,r=n&&n[X]("touch")>=0;if(r){var a="touchend"!=n?i.targetTouches[0]:i.changedTouches[0];if(a){var o=e(t);i.zrX=a.clientX-o.left,i.zrY=a.clientY-o.top}}else{var s=e(t);i.zrX=i.clientX-s.left,i.zrY=i.clientY-s.top,i.zrDelta=i.wheelDelta?i.wheelDelta/120:-(i.detail||0)/3}return i}function n(t,e,i){o?t.addEventListener(e,i):t.attachEvent("on"+e,i)}function r(t,e,i){o?t.removeEventListener(e,i):t.detachEvent("on"+e,i)}var a=t("../mixin/Eventful"),o=typeof window!==p&&!!window.addEventListener,s=o?function(t){t.preventDefault(),t.stopPropagation(),t.cancelBubble=!0}:function(t){t.returnValue=!1,t.cancelBubble=!0};return{normalizeEvent:i,addEventListener:n,removeEventListener:r,stop:s,Dispatcher:a}}),e("zrender/mixin/Draggable",[Ce],function(){function t(){this.on("mousedown",this._dragStart,this),this.on("mousemove",this._drag,this),this.on("mouseup",this._dragEnd,this),this.on("globalout",this._dragEnd,this)}return t[be]={constructor:t,_dragStart:function(t){var e=t[J];e&&e.draggable&&(this._draggingTarget=e,e.dragging=!0,this._x=t.offsetX,this._y=t.offsetY,this._dispatchProxy(e,"dragstart",t.event))},_drag:function(t){var e=this._draggingTarget;if(e){var i=t.offsetX,n=t.offsetY,r=i-this._x,a=n-this._y;this._x=i,this._y=n,e.drift(r,a,t),this._dispatchProxy(e,"drag",t.event);var o=this.findHover(i,n,e),s=this._dropTarget;this._dropTarget=o,e!==o&&(s&&o!==s&&this._dispatchProxy(s,"dragleave",t.event),o&&o!==s&&this._dispatchProxy(o,"dragenter",t.event))}},_dragEnd:function(t){var e=this._draggingTarget;e&&(e.dragging=!1),this._dispatchProxy(e,"dragend",t.event),this._dropTarget&&this._dispatchProxy(this._dropTarget,"drop",t.event),this._draggingTarget=null,this._dropTarget=null}},t}),e("zrender/core/GestureMgr",[Ce],function(){function t(t){var e=t[1][0]-t[0][0],i=t[1][1]-t[0][1];return Math.sqrt(e*e+i*i)}function e(t){return[(t[0][0]+t[1][0])/2,(t[0][1]+t[1][1])/2]}var i=function(){this._track=[]};i[be]={constructor:i,recognize:function(t,e){return this._doTrack(t,e),this._recognize(t)},clear:function(){return this._track[oe]=0,this},_doTrack:function(t,e){var i=t.touches;if(i){for(var n={points:[],touches:[],target:e,event:t},r=0,a=i[oe];a>r;r++){var o=i[r];n.points.push([o.clientX,o.clientY]),n.touches.push(o)}this._track.push(n)}},_recognize:function(t){for(var e in n)if(n.hasOwnProperty(e)){var i=n[e](this._track,t);if(i)return i}}};var n={pinch:function(i,n){var r=i[oe];if(r){var a=(i[r-1]||{}).points,o=(i[r-2]||{}).points||a;if(o&&o[oe]>1&&a&&a[oe]>1){var s=t(a)/t(o);!isFinite(s)&&(s=1),n.pinchScale=s;var l=e(a);return n.pinchX=l[0],n.pinchY=l[1],{type:"pinch",target:i[0][J],event:n}}}}};return i}),e("echarts/chart/bar/barItemStyle",[Ce,"../../model/mixin/makeStyleMapper"],function(t){return{getBarItemStyle:t("../../model/mixin/makeStyleMapper")([["fill","color"],[x,"borderColor"],[_,"borderWidth"],[x,"barBorderColor"],[_,"barBorderWidth"],[O],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["shadowColor"]])}}),e("echarts/component/axis/AxisView",[Ce,Ae,a,"./AxisBuilder",r],function(t){function e(t,e){function i(t){var e=n.getAxis(t);return e.toGlobalCoord(e.dataToCoord(0))}var n=t[H],r=e.axis,a={},o=r[R],s=r.onZero?"onZero":o,l=r.dim,c=n.getRect(),u=[c.x,c.x+c.width,c.y,c.y+c[fe]],h={x:{top:u[2],bottom:u[3]},y:{left:u[0],right:u[1]}};h.x.onZero=Math.max(Math.min(i("y"),h.x[pe]),h.x.top),h.y.onZero=Math.max(Math.min(i("x"),h.y.right),h.y.left),a[R]=["y"===l?h.y[s]:u[0],"x"===l?h.x[s]:u[3]];var d={x:0,y:1};a.rotation=Math.PI/2*d[l];var f={top:-1,bottom:1,left:-1,right:1};a.labelDirection=a.tickDirection=a.nameDirection=f[o],r.onZero&&(a.labelOffset=h[l][o]-h[l].onZero),e[ye]("axisTick").get(m)&&(a.tickDirection=-a.tickDirection),e[ye]("axisLabel").get(m)&&(a.labelDirection=-a.labelDirection);var p=e[ye]("axisLabel").get("rotate");return a.labelRotation="top"===s?-p:p,a.labelInterval=r.getLabelInterval(),a.z2=1,a}var i=t(Ae),n=t(a),o=t("./AxisBuilder"),s=o.ifIgnoreOnTick,l=o.getInterval,c=["axisLine","axisLabel","axisTick","axisName"],u=["splitLine","splitArea"],h=t(r).extendComponentView({type:"axis",render:function(t,n){if(this.group[q](),t.get("show")){var r=n[P]("grid",t.get("gridIndex")),a=e(r,t),s=new o(t,a);i.each(c,s.add,s),this.group.add(s.getGroup()),i.each(u,function(e){t.get(e+".show")&&this["_"+e](t,r,a.labelInterval)},this)}},_splitLine:function(t,e,r){var a=t.axis,o=t[ye]("splitLine"),c=o[ye]("lineStyle"),u=c.get("width"),h=c.get("color"),d=l(o,r);h=i[j](h)?h:[h];for(var f=e[H].getRect(),p=a.isHorizontal(),g=[],v=0,m=a.getTicksCoords(),y=[],x=[],_=0;_<m[oe];_++)if(!s(a,_,d)){var b=a.toGlobalCoord(m[_]);p?(y[0]=b,y[1]=f.y,x[0]=b,x[1]=f.y+f[fe]):(y[0]=f.x,y[1]=b,x[0]=f.x+f.width,x[1]=b);var w=v++%h[oe];g[w]=g[w]||[],g[w].push(new n.Line(n.subPixelOptimizeLine({shape:{x1:y[0],y1:y[1],x2:x[0],y2:x[1]},style:{lineWidth:u},silent:!0})))}for(var S=c.getLineStyle(),_=0;_<g[oe];_++)this.group.add(n.mergePath(g[_],{style:i[se]({stroke:h[_%h[oe]]},S),silent:!0}))},_splitArea:function(t,e,r){var a=t.axis,o=t[ye]("splitArea"),c=o[ye]("areaStyle"),u=c.get("color"),h=e[H].getRect(),d=a.getTicksCoords(),f=a.toGlobalCoord(d[0]),p=a.toGlobalCoord(d[0]),g=[],v=0,m=l(o,r);u=i[j](u)?u:[u];for(var y=1;y<d[oe];y++)if(!s(a,y,m)){var x,_,b,w,S=a.toGlobalCoord(d[y]);a.isHorizontal()?(x=f,_=h.y,b=S-x,w=h[fe]):(x=h.x,_=p,b=h.width,w=S-_);var M=v++%u[oe];g[M]=g[M]||[],g[M].push(new n.Rect({shape:{x:x,y:_,width:b,height:w},silent:!0})),f=x+b,p=_+w}for(var A=c.getAreaStyle(),y=0;y<g[oe];y++)this.group.add(n.mergePath(g[y],{style:i[se]({fill:u[y%u[oe]]},A),silent:!0}))}});h[le]({type:"xAxis"}),h[le]({type:"yAxis"})}),e("zrender/Layer",[Ce,"./core/util","./config"],function(t){function e(){return!1}function i(t,e,i,n){var r=document[f](e),a=i[me](),o=i[ve](),s=r.style;return s[R]="absolute",s.left=0,s.top=0,s.width=a+"px",s[fe]=o+"px",r.width=a*n,r[fe]=o*n,r.setAttribute("data-zr-dom-id",t),r}var n=t("./core/util"),r=t("./config"),a=function(t,a,o){var s;o=o||r.devicePixelRatio,typeof t===_e?s=i(t,"canvas",a,o):n[ue](t)&&(s=t,t=s.id),this.id=t,this.dom=s;var l=s.style;l&&(s.onselectstart=e,l["-webkit-user-select"]="none",l["user-select"]="none",l["-webkit-touch-callout"]="none",l["-webkit-tap-highlight-color"]="rgba(0,0,0,0)"),this.domBack=null,this.ctxBack=null,this.painter=a,this.config=null,this.clearColor=0,this.motionBlur=!1,this.lastFrameAlpha=.7,this.dpr=o};return a[be]={constructor:a,elCount:0,__dirty:!0,initContext:function(){this.ctx=this.dom.getContext("2d");var t=this.dpr;1!=t&&this.ctx.scale(t,t)},createBackBuffer:function(){var t=this.dpr;this.domBack=i("back-"+this.id,"canvas",this.painter,t),this.ctxBack=this.domBack.getContext("2d"),1!=t&&this.ctxBack.scale(t,t)},resize:function(t,e){var i=this.dpr,n=this.dom,r=n.style,a=this.domBack;r.width=t+"px",r[fe]=e+"px",n.width=t*i,n[fe]=e*i,1!=i&&this.ctx.scale(i,i),a&&(a.width=t*i,a[fe]=e*i,1!=i&&this.ctxBack.scale(i,i))},clear:function(t){var e=this.dom,i=this.ctx,n=e.width,r=e[fe],a=this.clearColor,o=this.motionBlur&&!t,s=this.lastFrameAlpha,l=this.dpr;if(o&&(this.domBack||this.createBackBuffer(),this.ctxBack.globalCompositeOperation="copy",this.ctxBack.drawImage(e,0,0,n/l,r/l)),i.clearRect(0,0,n/l,r/l),a&&(i.save(),i.fillStyle=this.clearColor,i.fillRect(0,0,n/l,r/l),i.restore()),o){var c=this.domBack;i.save(),i.globalAlpha=s,i.drawImage(c,0,0,n/l,r/l),i.restore()}}},a}),e("echarts/component/axis/AxisBuilder",[Ce,Ae,a,"../../model/Model","../../util/number"],function(t){function e(t){var e={componentType:t.mainType};return e[t.mainType+"Index"]=t.componentIndex,e}function i(t,e,i){var n,r,a=h(e-t.rotation);return d(a)?(r=i>0?"top":pe,n=B):d(a-f)?(r=i>0?pe:"top",n=B):(r=E,n=a>0&&f>a?i>0?"right":"left":i>0?"left":"right"),{rotation:a,textAlign:n,verticalAlign:r}}function n(t,e,i){var n,r,a=h(-t.rotation),o=i[0]>i[1],s="start"===e&&!o||"start"!==e&&o;return d(a-f/2)?(r=s?pe:"top",n=B):d(a-1.5*f)?(r=s?"top":pe,n=B):(r=E,n=1.5*f>a&&a>f/2?s?"left":"right":s?"right":"left"),{rotation:a,textAlign:n,verticalAlign:r}}var r=t(Ae),o=t(a),s=t("../../model/Model"),u=t("../../util/number"),h=u.remRadian,d=u.isRadianAroundZero,f=Math.PI,p=function(t,e){this.opt=e,this.axisModel=t,r[se](e,{labelOffset:0,nameDirection:1,tickDirection:1,labelDirection:1,silent:!0}),this.group=new o.Group({position:e[R].slice(),rotation:e.rotation})};p[be]={constructor:p,hasBuilder:function(t){return!!g[t]},add:function(t){g[t].call(this)},getGroup:function(){return this.group}};var g={axisLine:function(){var t=this.opt,e=this.axisModel;if(e.get("axisLine.show")){var i=this.axisModel.axis[k]();this.group.add(new o.Line({shape:{x1:i[0],y1:0,x2:i[1],y2:0},style:r[le]({lineCap:"round"},e[ye]("axisLine.lineStyle").getLineStyle()),strokeContainThreshold:t.strokeContainThreshold,silent:!!t.axisLineSilent,z2:1}))}},axisTick:function(){var t=this.axisModel;if(t.get("axisTick.show")){for(var e=t.axis,i=t[ye]("axisTick"),n=this.opt,r=i[ye]("lineStyle"),a=i.get(oe),s=m(i,n.labelInterval),l=e.getTicksCoords(),c=[],u=0;u<l[oe];u++)if(!v(e,u,s)){var h=l[u];c.push(new o.Line(o.subPixelOptimizeLine({shape:{x1:h,y1:0,x2:h,y2:n.tickDirection*a},style:{lineWidth:r.get("width")},silent:!0})))}this.group.add(o.mergePath(c,{style:r.getLineStyle(),z2:2,silent:!0}))}},axisLabel:function(){function t(t,e){var i=t&&t[N]().clone(),n=e&&e[N]().clone();return i&&n?(i[b](t.getLocalTransform()),n[b](e.getLocalTransform()),i.intersect(n)):void 0}var n=this.axisModel;if(n.get("axisLabel.show")){var r=this.opt,a=n.axis,l=n[ye]("axisLabel"),u=l[ye](G),h=l.get("margin"),d=a.scale.getTicks(),p=n.getFormattedLabels(),g=r.labelRotation;null==g&&(g=l.get("rotate")||0),g=g*f/180;for(var m=i(r,g,r.labelDirection),y=n.get("data"),x=[],_=n.get("silent"),w=0;w<d[oe];w++)if(!v(a,w,r.labelInterval)){var S=u;y&&y[w]&&y[w][G]&&(S=new s(y[w][G],u,n[L]));var M=S.getTextColor(),A=a.dataToCoord(d[w]),C=[A,r.labelOffset+r.labelDirection*h],T=a.scale[I](d[w]),P=new o.Text({style:{text:p[w],textAlign:S.get("align",!0)||m[F],textVerticalAlign:S.get("baseline",!0)||m.verticalAlign,textFont:S[V](),fill:typeof M===Z?M(T):M},position:C,rotation:m.rotation,silent:_,z2:10});P.eventData=e(n),P.eventData.targetType="axisLabel",P.eventData.value=T,x.push(P),this.group.add(P)}if(a.type!==c){if(n.getMin?n.getMin():n.get("min")){var z=x[0],k=x[1];t(z,k)&&(z[ge]=!0)}if(n.getMax?n.getMax():n.get("max")){var D=x[x[oe]-1],O=x[x[oe]-2];t(O,D)&&(D[ge]=!0)}}}},axisName:function(){var t=this.opt,r=this.axisModel,a=this.opt.axisName;if(null==a&&(a=r.get("name")),a){var s,l=r.get("nameLocation"),c=t.nameDirection,u=r[ye]("nameTextStyle"),h=r.get("nameGap")||0,d=this.axisModel.axis[k](),f=d[0]>d[1]?-1:1,p=["start"===l?d[0]-f*h:"end"===l?d[1]+f*h:(d[0]+d[1])/2,l===E?t.labelOffset+c*h:0];s=l===E?i(t,t.rotation,c):n(t,l,d);var g=new o.Text({style:{text:a,textFont:u[V](),fill:u.getTextColor()||r.get("axisLine.lineStyle.color"),textAlign:s[F],textVerticalAlign:s.verticalAlign},position:p,rotation:s.rotation,silent:r.get("silent"),z2:1});g.eventData=e(r),g.eventData.targetType="axisName",g.eventData.name=a,this.group.add(g)}}},v=p.ifIgnoreOnTick=function(t,e,i){var n,r=t.scale;return r.type===l&&(typeof i===Z?(n=r.getTicks()[e],!i(n,r[I](n))):e%(i+1))},m=p.getInterval=function(t,e){var i=t.get("interval");return(null==i||"auto"==i)&&(i=e),i};return p}),e("echarts/preprocessor/helper/compatStyle",[Ce,Ae],function(t){function e(t){var e=t&&t.itemStyle;e&&i.each(n,function(n){var r=e[M],a=e[A];r&&r[n]&&(t[n]=t[n]||{},t[n][M]?i.merge(t[n][M],r[n]):t[n][M]=r[n],r[n]=null),a&&a[n]&&(t[n]=t[n]||{},t[n][A]?i.merge(t[n][A],a[n]):t[n][A]=a[n],a[n]=null)})}var i=t(Ae),n=["areaStyle","lineStyle","nodeStyle","linkStyle","chordStyle","label","labelLine"];return function(t){if(t){e(t),e(t.markPoint),e(t.markLine);var n=t.data;if(n){for(var r=0;r<n[oe];r++)e(n[r]);var a=t.markPoint;if(a&&a.data)for(var o=a.data,r=0;r<o[oe];r++)e(o[r]);var s=t.markLine;if(s&&s.data)for(var l=s.data,r=0;r<l[oe];r++)i[j](l[r])?(e(l[r][0]),e(l[r][1])):e(l[r])}}}}),e("echarts/component/helper/listComponent",[Ce,"../../util/layout","../../util/format",a],function(t){function e(t,e,n){i.positionGroup(t,e.getBoxLayoutParams(),{width:n[me](),height:n[ve]()},e.get("padding"))}var i=t("../../util/layout"),n=t("../../util/format"),r=t(a);return{layout:function(t,n,r){var a=i.getLayoutRect(n.getBoxLayoutParams(),{width:r[me](),height:r[ve]()},n.get("padding"));i.box(n.get("orient"),t,n.get("itemGap"),a.width,a[fe]),e(t,n,r)},addBackground:function(t,e){var i=n.normalizeCssArray(e.get("padding")),a=t[N](),o=e.getItemStyle(["color",O]);o.fill=e.get("backgroundColor");var s=new r.Rect({shape:{x:a.x-i[3],y:a.y-i[0],width:a.width+i[1]+i[3],height:a[fe]+i[0]+i[2]},style:o,silent:!0,z2:-1});r.subPixelOptimizeRect(s),t.add(s)}}}),e("echarts/chart/helper/SymbolDraw",[Ce,a,"./Symbol"],function(t){function e(t){this.group=new n.Group,this._symbolCtor=t||r}function i(t,e,i){var n=t.getItemLayout(e);return!(!n||isNaN(n[0])||isNaN(n[1])||i&&i(e)||"none"===t[C](e,"symbol"))}var n=t(a),r=t("./Symbol"),o=e[be];return o.updateData=function(t,e){var r=this.group,a=t.hostModel,o=this._data,s=this._symbolCtor;t.diff(o).add(function(n){var a=t.getItemLayout(n);if(i(t,n,e)){var o=new s(t,n);o.attr(R,a),t.setItemGraphicEl(n,o),r.add(o)}})[he](function(l,c){var u=o[S](c),h=t.getItemLayout(l);return i(t,l,e)?(u?(u.updateData(t,l),n[g](u,{position:h},a)):(u=new s(t,l),u.attr(R,h)),r.add(u),void t.setItemGraphicEl(l,u)):void r[ce](u)})[ce](function(t){var e=o[S](t);e&&e.fadeOut(function(){r[ce](e)})}).execute(),this._data=t},o.updateLayout=function(){var t=this._data;t&&t.eachItemGraphicEl(function(e,i){e.attr(R,t.getItemLayout(i))})},o[ce]=function(t){var e=this.group,i=this._data;i&&(t?i.eachItemGraphicEl(function(t){t.fadeOut(function(){e[ce](t)})}):e[q]())},e}),e("echarts/component/axis/AngleAxisView",[Ce,Ae,a,"../../model/Model",r],function(t){function e(t,e,i,n){var r=t.coordToPoint([e,n]),a=t.coordToPoint([i,n]);return{x1:r[0],y1:r[1],x2:a[0],y2:a[1]}}var i=t(Ae),n=t(a),o=t("../../model/Model"),s=["axisLine","axisLabel","axisTick","splitLine","splitArea"];t(r).extendComponentView({type:"angleAxis",render:function(t,e){if(this.group[q](),t.get("show")){var n=e[P]("polar",t.get("polarIndex")),r=t.axis,a=n[H],o=a.getRadiusAxis()[k](),l=r.getTicksCoords();r.type!==c&&l.pop(),i.each(s,function(e){t.get(e+".show")&&this["_"+e](t,a,l,o)},this)}},_axisLine:function(t,e,i,r){var a=t[ye]("axisLine.lineStyle"),o=new n.Circle({shape:{cx:e.cx,cy:e.cy,r:r[1]},style:a.getLineStyle(),z2:1,silent:!0});o.style.fill=null,this.group.add(o)},_axisTick:function(t,r,a,o){var s=t[ye]("axisTick"),l=(s.get(m)?-1:1)*s.get(oe),c=i.map(a,function(t){return new n.Line({shape:e(r,o[1],o[1]+l,t)})});this.group.add(n.mergePath(c,{style:s[ye]("lineStyle").getLineStyle()}))},_axisLabel:function(t,e,i,r){for(var a=t.axis,s=t.get("data"),l=t[ye]("axisLabel"),c=l[ye](G),u=t.getFormattedLabels(),h=l.get("margin"),d=a.getLabelsCoords(),f=0;f<i[oe];f++){var p=r[1],g=e.coordToPoint([p+h,d[f]]),v=e.cx,m=e.cy,y=Math.abs(g[0]-v)/p<.3?B:g[0]>v?"left":"right",x=Math.abs(g[1]-m)/p<.3?E:g[1]>m?"top":pe,_=c;s&&s[f]&&s[f][G]&&(_=new o(s[f][G],c)),this.group.add(new n.Text({style:{x:g[0],y:g[1],fill:_.getTextColor(),text:u[f],textAlign:y,textVerticalAlign:x,textFont:_[V]()},silent:!0}))}},_splitLine:function(t,r,a,o){var s=t[ye]("splitLine"),l=s[ye]("lineStyle"),c=l.get("color"),u=0;c=c instanceof Array?c:[c];for(var h=[],d=0;d<a[oe];d++){var f=u++%c[oe];h[f]=h[f]||[],h[f].push(new n.Line({shape:e(r,o[0],o[1],a[d])}))}for(var d=0;d<h[oe];d++)this.group.add(n.mergePath(h[d],{style:i[se]({stroke:c[d%c[oe]]},l.getLineStyle()),silent:!0,z:t.get("z")}))},_splitArea:function(t,e,r,a){var o=t[ye]("splitArea"),s=o[ye]("areaStyle"),l=s.get("color"),c=0;l=l instanceof Array?l:[l];for(var u=[],h=Math.PI/180,d=-r[0]*h,f=Math.min(a[0],a[1]),p=Math.max(a[0],a[1]),g=t.get("clockwise"),v=1;v<r[oe];v++){var m=c++%l[oe];u[m]=u[m]||[],u[m].push(new n[w]({shape:{cx:e.cx,cy:e.cy,r0:f,r:p,startAngle:d,endAngle:-r[v]*h,clockwise:g},silent:!0})),d=-r[v]*h}for(var v=0;v<u[oe];v++)this.group.add(n.mergePath(u[v],{style:i[se]({fill:l[v%l[oe]]},s.getAreaStyle()),silent:!0}))}})}),e("echarts/component/tooltip/TooltipContent",[Ce,Ae,"zrender/tool/color","zrender/core/event","../../util/format","zrender/core/env"],function(t){function e(t){var e="cubic-bezier(0.23, 1, 0.32, 1)",i="left "+t+"s "+e+",top "+t+"s "+e;return s.map(g,function(t){return t+"transition:"+i}).join(";")}function i(t){var e=[],i=t.get("fontSize"),n=t.getTextColor();return n&&e.push("color:"+n),e.push("font:"+t[V]()),i&&e.push("line-height:"+Math.round(3*i/2)+"px"),h(["decoration","align"],function(i){var n=t.get(i);n&&e.push("text-"+i+":"+n)}),e.join(";")}function r(t){t=t;var r=[],a=t.get("transitionDuration"),o=t.get("backgroundColor"),s=t[ye](G),c=t.get("padding");return a&&r.push(e(a)),o&&(p.canvasSupported?r.push("background-Color:"+o):(r.push("background-Color:#"+l.toHex(o)),r.push("filter:alpha(opacity=70)"))),h(["width","color",n],function(e){var i="border-"+e,n=d(i),a=t.get(n);null!=a&&r.push(i+":"+a+("color"===e?"":"px"))}),r.push(i(s)),null!=c&&r.push("padding:"+u.normalizeCssArray(c).join("px ")+"px"),r.join(";")+";"}function a(t,e){var i=document[f]("div"),n=e.getZr();this.el=i,this._x=e[me]()/2,this._y=e[ve]()/2,t.appendChild(i),this._container=t,this._show=!1,this._hideTimeout;var r=this;i.onmouseenter=function(){r.enterable&&(clearTimeout(r._hideTimeout),r._show=!0),r._inContent=!0},i.onmousemove=function(e){if(!r.enterable){var i=n.handler;c.normalizeEvent(t,e),i.dispatch("mousemove",e)}},i.onmouseleave=function(){r.enterable&&r._show&&r.hideLater(r._hideDelay),r._inContent=!1},o(i,t)}function o(t,e){function i(t){n(t[J])&&t.preventDefault()}function n(i){for(;i&&i!==e;){if(i===t)return!0;i=i.parentNode}}c.addEventListener(e,"touchstart",i),c.addEventListener(e,"touchmove",i),c.addEventListener(e,"touchend",i)}var s=t(Ae),l=t("zrender/tool/color"),c=t("zrender/core/event"),u=t("../../util/format"),h=s.each,d=u.toCamelCase,p=t("zrender/core/env"),g=["","-webkit-","-moz-","-o-"],v="position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;";return a[be]={constructor:a,enterable:!0,update:function(){var t=this._container,e=t.currentStyle||document.defaultView.getComputedStyle(t),i=t.style;"absolute"!==i[R]&&"absolute"!==e[R]&&(i[R]="relative")},show:function(t){clearTimeout(this._hideTimeout),this.el.style.cssText=v+r(t)+";left:"+this._x+"px;top:"+this._y+"px;"+(t.get("extraCssText")||""),this._show=!0},setContent:function(t){var e=this.el;e.innerHTML=t,e.style.display=t?"block":"none"},moveTo:function(t,e){var i=this.el.style;i.left=t+"px",i.top=e+"px",this._x=t,this._y=e},hide:function(){this.el.style.display="none",this._show=!1},hideLater:function(t){!this._show||this._inContent&&this.enterable||(t?(this._hideDelay=t,this._show=!1,this._hideTimeout=setTimeout(s.bind(this.hide,this),t)):this.hide())},isShow:function(){return this._show}},a}),e("echarts/component/helper/selectableMixin",[Ce,Ae],function(t){var e=t(Ae);return{updateSelectedMap:function(t){this._selectTargetMap=e.reduce(t||[],function(t,e){return t[e.name]=e,t},{})},select:function(t){var i=this._selectTargetMap,n=i[t],r=this.get("selectedMode");"single"===r&&e.each(i,function(t){t.selected=!1}),n&&(n.selected=!0)},unSelect:function(t){var e=this._selectTargetMap[t];e&&(e.selected=!1)},toggleSelected:function(t){var e=this._selectTargetMap[t];return null!=e?(this[e.selected?"unSelect":"select"](t),e.selected):void 0},isSelected:function(t){var e=this._selectTargetMap[t];return e&&e.selected}}}),e("echarts/chart/line/poly",[Ce,"zrender/graphic/Path","zrender/core/vector"],function(t){function e(t){return isNaN(t[0])||isNaN(t[1])}function n(t,n,r,a,p,g,v,m,y,x,_){for(var b=0,w=r,S=0;a>S;S++){var M=n[w];if(w>=p||0>w)break;if(e(M)){if(_){w+=g;continue}break}if(w===r)t[g>0?i:"lineTo"](M[0],M[1]),u(d,M);else if(y>0){var A=w+g,C=n[A];if(_)for(;C&&e(n[A]);)A+=g,C=n[A];var T=.5,L=n[b],C=n[A];if(!C||e(C))u(f,M);else{e(C)&&!_&&(C=M),o.sub(h,C,L);var P,z;if("x"===x||"y"===x){var k="x"===x?0:1;P=Math.abs(M[k]-L[k]),z=Math.abs(M[k]-C[k])}else P=o.dist(M,L),z=o.dist(M,C);T=z/(z+P),c(f,M,h,-y*(1-T))}s(d,d,m),l(d,d,v),s(f,f,m),l(f,f,v),t.bezierCurveTo(d[0],d[1],f[0],f[1],M[0],M[1]),c(d,M,h,y*T)}else t.lineTo(M[0],M[1]);b=w,w+=g}return S}function r(t,e){var i=[1/0,1/0],n=[-1/0,-1/0];if(e)for(var r=0;r<t[oe];r++){var a=t[r];a[0]<i[0]&&(i[0]=a[0]),a[1]<i[1]&&(i[1]=a[1]),a[0]>n[0]&&(n[0]=a[0]),a[1]>n[1]&&(n[1]=a[1])}return{min:e?i:n,max:e?n:i}}var a=t("zrender/graphic/Path"),o=t("zrender/core/vector"),s=o.min,l=o.max,c=o.scaleAndAdd,u=o.copy,h=[],d=[],f=[];return{Polyline:a[le]({type:"ec-polyline",shape:{points:[],smooth:0,smoothConstraint:!0,smoothMonotone:null,connectNulls:!1},style:{fill:null,stroke:"#000"},buildPath:function(t,i){var a=i.points,o=0,s=a[oe],l=r(a,i.smoothConstraint);if(i.connectNulls){for(;s>0&&e(a[s-1]);s--);for(;s>o&&e(a[o]);o++);}for(;s>o;)o+=n(t,a,o,s,s,1,l.min,l.max,i.smooth,i.smoothMonotone,i.connectNulls)+1}}),Polygon:a[le]({type:"ec-polygon",shape:{points:[],stackedOnPoints:[],smooth:0,stackedOnSmooth:0,smoothConstraint:!0,smoothMonotone:null,connectNulls:!1},buildPath:function(t,i){var a=i.points,o=i.stackedOnPoints,s=0,l=a[oe],c=i.smoothMonotone,u=r(a,i.smoothConstraint),h=r(o,i.smoothConstraint);if(i.connectNulls){for(;l>0&&e(a[l-1]);l--);for(;l>s&&e(a[s]);s++);}for(;l>s;){var d=n(t,a,s,l,l,1,u.min,u.max,i.smooth,c,i.connectNulls);n(t,o,s+d-1,d,l,-1,h.min,h.max,i.stackedOnSmooth,c,i.connectNulls),s+=d+1,t.closePath()}}})}}),e("echarts/chart/line/lineAnimationDiff",[Ce],function(){function t(t){return t>=0?1:-1}function e(e,i,r){for(var a,s=e.getBaseAxis(),l=e.getOtherAxis(s),c=s.onZero?0:l.scale[k]()[0],u=l.dim,h="x"===u||u===n?1:0,d=i.stackedOn,f=i.get(u,r);d&&t(d.get(u,r))===t(f);){a=d;break}var p=[];return p[h]=i.get(s.dim,r),p[1-h]=a?a.get(u,r,!0):c,e[o](p)}function i(t,e){var i=[];return e.diff(t).add(function(t){i.push({cmd:"+",idx:t})})[he](function(t,e){i.push({cmd:"=",idx:e,idx1:t})})[ce](function(t){i.push({cmd:"-",idx:t})}).execute(),i}return function(t,n,r,a,l,c){for(var u=i(t,n),h=[],d=[],f=[],p=[],g=[],v=[],m=[],y=c[s],x=0;x<u[oe];x++){var _=u[x],b=!0;switch(_.cmd){case"=":var w=t.getItemLayout(_.idx),S=n.getItemLayout(_.idx1);(isNaN(w[0])||isNaN(w[1]))&&(w=S.slice()),h.push(w),d.push(S),f.push(r[_.idx]),p.push(a[_.idx1]),m.push(n.getRawIndex(_.idx1));break;case"+":var M=_.idx;h.push(l[o]([n.get(y[0],M,!0),n.get(y[1],M,!0)])),d.push(n.getItemLayout(M).slice()),f.push(e(l,n,M)),p.push(a[M]),m.push(n.getRawIndex(M));break;case"-":var M=_.idx,A=t.getRawIndex(M);A!==M?(h.push(t.getItemLayout(M)),d.push(c[o]([t.get(y[0],M,!0),t.get(y[1],M,!0)])),f.push(r[M]),p.push(e(c,t,M)),m.push(A)):b=!1}b&&(g.push(_),v.push(v[oe]))}v.sort(function(t,e){return m[t]-m[e]});for(var C=[],T=[],L=[],P=[],z=[],x=0;x<v[oe];x++){var M=v[x];C[x]=h[M],T[x]=d[M],L[x]=f[M],P[x]=p[M],z[x]=g[M]}return{current:C,next:T,stackedOnCurrent:L,stackedOnNext:P,status:z}}}),e("echarts/chart/helper/Symbol",[Ce,Ae,"../../util/symbol",a,"../../util/number"],function(t){function e(t){return r[j](t)||(t=[+t,+t]),t}function i(t,e){c.Group.call(this),this.updateData(t,e)}function n(t,e){this.parent.drift(t,e)}var r=t(Ae),o=t("../../util/symbol"),c=t(a),d=t("../../util/number"),f=i[be];f._createSymbol=function(t,i,r){this[q]();var a=i.hostModel,s=i[C](r,"color"),l=o.createSymbol(t,-.5,-.5,1,1,s);l.attr({z2:100,culling:!0,scale:[0,0]}),l.drift=n;var u=e(i[C](r,"symbolSize"));c.initProps(l,{scale:u},a,r),this._symbolType=t,this.add(l)},f.stopSymbolAnimation=function(t){this.childAt(0).stopAnimation(t)},f.getScale=function(){return this.childAt(0).scale},f.highlight=function(){this.childAt(0)[ae](A)},f.downplay=function(){this.childAt(0)[ae](M)},f.setZ=function(t,e){var i=this.childAt(0);i[Y]=t,i.z=e},f.setDraggable=function(t){var e=this.childAt(0);e.draggable=t,e.cursor=t?"move":"pointer"},f.updateData=function(t,i){var n=t[C](i,"symbol")||"circle",r=t.hostModel,a=e(t[C](i,"symbolSize"));if(n!==this._symbolType)this._createSymbol(n,t,i);else{var o=this.childAt(0);c[g](o,{scale:a},r,i)}this._updateCommon(t,i,a),this._seriesModel=r};var p=["itemStyle",M],v=["itemStyle",A],m=["label",M],x=["label",A];return f._updateCommon=function(t,i,n){var a=this.childAt(0),o=t.hostModel,f=t[h](i),g=f[ye](p),_=t[C](i,"color");"image"!==a.type&&a.useStyle({strokeNoScale:!0});var b=a.style,w=f[ye](v).getItemStyle();a.rotation=(f[y]("symbolRotate")||0)*Math.PI/180||0;var S=f[y]("symbolOffset");if(S){var T=a[R];T[0]=d[u](S[0],n[0]),T[1]=d[u](S[1],n[1])}a.setColor(_),r[le](b,g.getItemStyle(["color"]));var L=t[C](i,O);null!=L&&(b[O]=L);for(var P,z,k=f[ye](m),I=f[ye](x),D=t[s].slice();D[oe]&&(P=D.pop(),z=t.getDimensionInfo(P).type,z===l||"time"===z););null!=P&&k.get("show")?(c.setText(b,k,_),b.text=r.retrieve(o.getFormattedLabel(i,M),t.get(P,i))):b.text="",null!=P&&I[y]("show")?(c.setText(w,I,_),w.text=r.retrieve(o.getFormattedLabel(i,A),t.get(P,i))):w.text="";var B=e(t[C](i,"symbolSize"));if(a.off(ee).off(te).off(A).off(M),c.setHoverStyle(a,w),f[y]("hoverAnimation")){var E=function(){var t=B[1]/B[0];this.animateTo({scale:[Math.max(1.1*B[0],B[0]+3),Math.max(1.1*B[1],B[1]+3*t)]},400,"elasticOut")},N=function(){this.animateTo({scale:B},400,"elasticOut")};a.on(ee,E).on(te,N).on(A,E).on(M,N)}},f.fadeOut=function(t){var e=this.childAt(0);e.off(ee).off(te).off(A).off(M),e.style.text="",c[g](e,{scale:[0,0]},this._seriesModel,this[K],t)},r[W](i,c.Group),i}),e("echarts/util/symbol",[Ce,"./graphic","zrender/core/BoundingRect"],function(t){var e=t("./graphic"),n=t("zrender/core/BoundingRect"),r=e.extendShape({type:"triangle",shape:{cx:0,cy:0,width:0,height:0},buildPath:function(t,e){var n=e.cx,r=e.cy,a=e.width/2,o=e[fe]/2;t[i](n,r-o),t.lineTo(n+a,r+o),t.lineTo(n-a,r+o),t.closePath()}}),a=e.extendShape({type:"diamond",shape:{cx:0,cy:0,width:0,height:0},buildPath:function(t,e){var n=e.cx,r=e.cy,a=e.width/2,o=e[fe]/2;t[i](n,r-o),t.lineTo(n+a,r),t.lineTo(n,r+o),t.lineTo(n-a,r),t.closePath()}}),o=e.extendShape({type:"pin",shape:{x:0,y:0,width:0,height:0},buildPath:function(t,e){var i=e.x,n=e.y,r=e.width/5*3,a=Math.max(r,e[fe]),o=r/2,s=o*o/(a-o),l=n-a+o+s,c=Math.asin(s/o),u=Math.cos(c)*o,h=Math.sin(c),d=Math.cos(c);t.arc(i,l,o,Math.PI-c,2*Math.PI+c);var f=.6*o,p=.7*o;t.bezierCurveTo(i+u-h*f,l+s+d*f,i,n-p,i,n),t.bezierCurveTo(i,n-p,i-u+h*f,l+s+d*f,i-u,l+s),t.closePath()}}),s=e.extendShape({type:"arrow",shape:{x:0,y:0,width:0,height:0},buildPath:function(t,e){var n=e[fe],r=e.width,a=e.x,o=e.y,s=r/3*2;t[i](a,o),t.lineTo(a+s,o+n),t.lineTo(a,o+n/4*3),t.lineTo(a-s,o+n),t.lineTo(a,o),t.closePath()}}),l={line:e.Line,rect:e.Rect,roundRect:e.Rect,square:e.Rect,circle:e.Circle,diamond:a,pin:o,arrow:s,triangle:r},c={line:function(t,e,i,n,r){r.x1=t,r.y1=e+n/2,r.x2=t+i,r.y2=e+n/2},rect:function(t,e,i,n,r){r.x=t,r.y=e,r.width=i,r[fe]=n},roundRect:function(t,e,i,n,r){r.x=t,r.y=e,r.width=i,r[fe]=n,r.r=Math.min(i,n)/4},square:function(t,e,i,n,r){var a=Math.min(i,n);r.x=t,r.y=e,r.width=a,r[fe]=a},circle:function(t,e,i,n,r){r.cx=t+i/2,r.cy=e+n/2,r.r=Math.min(i,n)/2},diamond:function(t,e,i,n,r){r.cx=t+i/2,r.cy=e+n/2,r.width=i,r[fe]=n},pin:function(t,e,i,n,r){r.x=t+i/2,r.y=e+n/2,r.width=i,r[fe]=n},arrow:function(t,e,i,n,r){r.x=t+i/2,r.y=e+n/2,r.width=i,r[fe]=n},triangle:function(t,e,i,n,r){r.cx=t+i/2,r.cy=e+n/2,r.width=i,r[fe]=n}},u={};for(var h in l)u[h]=new l[h];var d=e.extendShape({type:"symbol",shape:{symbolType:"",x:0,y:0,width:0,height:0},beforeBrush:function(){var t=this.style,e=this.shape;"pin"===e.symbolType&&t.textPosition===m&&(t.textPosition=["50%","40%"],t[F]=B,t.textVerticalAlign=E)},buildPath:function(t,e){var i=e.symbolType,n=u[i];"none"!==e.symbolType&&(n||(i="rect",n=u[i]),c[i](e.x,e.y,e.width,e[fe],n.shape),n.buildPath(t,n.shape))}}),f=function(t){if("image"!==this.type){var e=this.style,i=this.shape;i&&"line"===i.symbolType?e[x]=t:this.__isEmptyBrush?(e[x]=t,e.fill="#fff"):(e.fill&&(e.fill=t),e[x]&&(e[x]=t)),this.dirty()}},p={createSymbol:function(t,i,r,a,o,s){var l=0===t[X]("empty");l&&(t=t.substr(5,1)[we]()+t.substr(6));var c;return c=0===t[X]("image://")?new e.Image({style:{image:t.slice(8),x:i,y:r,width:a,height:o}}):0===t[X]("path://")?e.makePath(t.slice(7),{},new n(i,r,a,o)):new d({shape:{symbolType:t,x:i,y:r,width:a,height:o}}),c.__isEmptyBrush=l,c.setColor=f,c.setColor(s),c}};return p}),e("echarts/component/axis/RadiusAxisView",[Ce,Ae,a,"./AxisBuilder",r],function(t){function e(t,e,i){return{position:[t.cx,t.cy],rotation:i/180*Math.PI,labelDirection:-1,tickDirection:-1,nameDirection:1,labelRotation:e[ye]("axisLabel").get("rotate"),z2:1}}var i=t(Ae),n=t(a),o=t("./AxisBuilder"),s=["axisLine","axisLabel","axisTick","axisName"],l=["splitLine","splitArea"];t(r).extendComponentView({type:"radiusAxis",render:function(t,n){if(this.group[q](),t.get("show")){var r=n[P]("polar",t.get("polarIndex")),a=r[H].getAngleAxis(),c=t.axis,u=r[H],h=c.getTicksCoords(),d=a[k]()[0],f=c[k](),p=e(u,t,d),g=new o(t,p);i.each(s,g.add,g),this.group.add(g.getGroup()),i.each(l,function(e){t.get(e+".show")&&this["_"+e](t,u,d,f,h)},this)}},_splitLine:function(t,e,r,a,o){var s=t[ye]("splitLine"),l=s[ye]("lineStyle"),c=l.get("color"),u=0;c=c instanceof Array?c:[c];for(var h=[],d=0;d<o[oe];d++){var f=u++%c[oe];h[f]=h[f]||[],h[f].push(new n.Circle({shape:{cx:e.cx,cy:e.cy,r:o[d]},silent:!0}))}for(var d=0;d<h[oe];d++)this.group.add(n.mergePath(h[d],{style:i[se]({stroke:c[d%c[oe]],fill:null},l.getLineStyle()),silent:!0}))},_splitArea:function(t,e,r,a,o){var s=t[ye]("splitArea"),l=s[ye]("areaStyle"),c=l.get("color"),u=0;c=c instanceof Array?c:[c];for(var h=[],d=o[0],f=1;f<o[oe];f++){var p=u++%c[oe];h[p]=h[p]||[],h[p].push(new n[w]({shape:{cx:e.cx,cy:e.cy,r0:d,r:o[f],startAngle:0,endAngle:2*Math.PI},silent:!0})),d=o[f]}for(var f=0;f<h[oe];f++)this.group.add(n.mergePath(h[f],{style:i[se]({fill:c[f%c[oe]]},l.getAreaStyle()),silent:!0}))}})}),e("echarts/chart/pie/labelLayout",[Ce,"zrender/contain/text"],function(t){function e(t,e,i,n,r,a,o){function s(e,i,n){for(var r=e;i>r;r++)if(t[r].y+=n,r>e&&i>r+1&&t[r+1].y>t[r].y+t[r][fe])return void l(r,n/2);l(i-1,n/2)}function l(e,i){for(var n=e;n>=0&&(t[n].y-=i,!(n>0&&t[n].y>t[n-1].y+t[n-1][fe]));n--);}function c(t,e,i,n,r,a){for(var o=a>0?e?Number.MAX_VALUE:0:e?Number.MAX_VALUE:0,s=0,l=t[oe];l>s;s++)if(t[s][R]!==B){var c=Math.abs(t[s].y-n),u=t[s].len,h=t[s].len2,d=r+u>c?Math.sqrt((r+u+h)*(r+u+h)-c*c):Math.abs(t[s].x-i);e&&d>=o&&(d=o-10),!e&&o>=d&&(d=o+10),t[s].x=i+d*a,o=d}}t.sort(function(t,e){return t.y-e.y});for(var u,h=0,d=t[oe],f=[],p=[],g=0;d>g;g++)u=t[g].y-h,0>u&&s(g,d,-u,r),h=t[g].y+t[g][fe];0>o-h&&l(d-1,h-o);for(var g=0;d>g;g++)t[g].y>=i?p.push(t[g]):f.push(t[g]);c(f,!1,e,i,n,r),c(p,!0,e,i,n,r)}function i(t,i,n,r,a,o){for(var s=[],l=[],c=0;c<t[oe];c++)t[c].x<i?s.push(t[c]):l.push(t[c]);e(l,i,n,r,1,a,o),e(s,i,n,r,-1,a,o);for(var c=0;c<t[oe];c++){var u=t[c].linePoints;if(u){var h=u[1][0]-u[2][0];u[2][0]=t[c].x<i?t[c].x+3:t[c].x-3,u[1][1]=u[2][1]=t[c].y,u[1][0]=u[2][0]+h}}}var n=t("zrender/contain/text");return function(t,e,r,a){var o,s,l=t[ie](),c=[],u=!1;l.each(function(i){var r,a,d,f,p=l.getItemLayout(i),g=l[h](i),v=g[ye]("label.normal"),y=v.get(R)||g.get("label.emphasis.position"),x=g[ye]("labelLine.normal"),_=x.get(oe),b=x.get("length2"),w=(p.startAngle+p.endAngle)/2,S=Math.cos(w),A=Math.sin(w);
+o=p.cx,s=p.cy;var C=y===m||"inner"===y;if(y===B)r=p.cx,a=p.cy,f=B;else{var L=(C?(p.r+p.r0)/2*S:p.r*S)+o,P=(C?(p.r+p.r0)/2*A:p.r*A)+s;if(r=L+3*S,a=P+3*A,!C){var z=L+S*(_+e-p.r),k=P+A*(_+e-p.r),I=z+(0>S?-1:1)*b,D=k;r=I+(0>S?-5:5),a=D,d=[[L,P],[z,k],[I,D]]}f=C?B:S>0?"left":"right"}var O=v[ye](G)[V](),E=v.get("rotate")?0>S?-w+Math.PI:-w:0,F=t.getFormattedLabel(i,M)||l[T](i),H=n[N](F,O,f,"top");u=!!E,p.label={x:r,y:a,position:y,height:H[fe],len:_,len2:b,linePoints:d,textAlign:f,verticalAlign:"middle",font:O,rotation:E},C||c.push(p.label)}),!u&&t.get("avoidLabelOverlap")&&i(c,o,s,e,r,a)}}),e("zrender",["zrender/zrender"],function(t){return t}),e("echarts",["echarts/echarts"],function(t){return t});var Te=t("echarts");return Te.graphic=t("echarts/util/graphic"),Te.number=t("echarts/util/number"),Te.format=t("echarts/util/format"),t("echarts/chart/bar"),t("echarts/chart/line"),t("echarts/chart/pie"),t("echarts/component/grid"),t("echarts/component/polar"),t("echarts/component/title"),t("echarts/component/legend"),t("echarts/component/tooltip"),t("zrender/vml/vml"),Te});
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/crypto-js.js b/ap/app/zte_webui/js/3rd/crypto-js.js
new file mode 100755
index 0000000..be5c2ea
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/crypto-js.js
@@ -0,0 +1,6059 @@
+;(function (root, factory) {
+	if (typeof exports === "object") {
+		// CommonJS
+		module.exports = exports = factory();
+	}
+	else if (typeof define === "function" && define.amd) {
+		// AMD
+		define([], factory);
+	}
+	else {
+		// Global (browser)
+		root.CryptoJS = factory();
+	}
+}(this, function () {
+
+	/*globals window, global, require*/
+
+	/**
+	 * CryptoJS core components.
+	 */
+	var CryptoJS = CryptoJS || (function (Math, undefined) {
+
+	    var crypto;
+
+	    // Native crypto from window (Browser)
+	    if (typeof window !== 'undefined' && window.crypto) {
+	        crypto = window.crypto;
+	    }
+
+	    // Native (experimental IE 11) crypto from window (Browser)
+	    if (!crypto && typeof window !== 'undefined' && window.msCrypto) {
+	        crypto = window.msCrypto;
+	    }
+
+	    // Native crypto from global (NodeJS)
+	    if (!crypto && typeof global !== 'undefined' && global.crypto) {
+	        crypto = global.crypto;
+	    }
+
+	    // Native crypto import via require (NodeJS)
+	    if (!crypto && typeof require === 'function') {
+	        try {
+	            crypto = require('crypto');
+	        } catch (err) {}
+	    }
+
+	    /*
+	     * Cryptographically secure pseudorandom number generator
+	     *
+	     * As Math.random() is cryptographically not safe to use
+	     */
+	    var cryptoSecureRandomInt = function () {
+	        if (crypto) {
+	            // Use getRandomValues method (Browser)
+	            if (typeof crypto.getRandomValues === 'function') {
+	                try {
+	                    return crypto.getRandomValues(new Uint32Array(1))[0];
+	                } catch (err) {}
+	            }
+
+	            // Use randomBytes method (NodeJS)
+	            if (typeof crypto.randomBytes === 'function') {
+	                try {
+	                    return crypto.randomBytes(4).readInt32LE();
+	                } catch (err) {}
+	            }
+	        }
+
+	        throw new Error('Native crypto module could not be used to get secure random number.');
+	    };
+
+	    /*
+	     * Local polyfill of Object.create
+
+	     */
+	    var create = Object.create || (function () {
+	        function F() {}
+
+	        return function (obj) {
+	            var subtype;
+
+	            F.prototype = obj;
+
+	            subtype = new F();
+
+	            F.prototype = null;
+
+	            return subtype;
+	        };
+	    }())
+
+	    /**
+	     * CryptoJS namespace.
+	     */
+	    var C = {};
+
+	    /**
+	     * Library namespace.
+	     */
+	    var C_lib = C.lib = {};
+
+	    /**
+	     * Base object for prototypal inheritance.
+	     */
+	    var Base = C_lib.Base = (function () {
+
+
+	        return {
+	            /**
+	             * Creates a new object that inherits from this object.
+	             *
+	             * @param {Object} overrides Properties to copy into the new object.
+	             *
+	             * @return {Object} The new object.
+	             *
+	             * @static
+	             *
+	             * @example
+	             *
+	             *     var MyType = CryptoJS.lib.Base.extend({
+	             *         field: 'value',
+	             *
+	             *         method: function () {
+	             *         }
+	             *     });
+	             */
+	            extend: function (overrides) {
+	                // Spawn
+	                var subtype = create(this);
+
+	                // Augment
+	                if (overrides) {
+	                    subtype.mixIn(overrides);
+	                }
+
+	                // Create default initializer
+	                if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
+	                    subtype.init = function () {
+	                        subtype.$super.init.apply(this, arguments);
+	                    };
+	                }
+
+	                // Initializer's prototype is the subtype object
+	                subtype.init.prototype = subtype;
+
+	                // Reference supertype
+	                subtype.$super = this;
+
+	                return subtype;
+	            },
+
+	            /**
+	             * Extends this object and runs the init method.
+	             * Arguments to create() will be passed to init().
+	             *
+	             * @return {Object} The new object.
+	             *
+	             * @static
+	             *
+	             * @example
+	             *
+	             *     var instance = MyType.create();
+	             */
+	            create: function () {
+	                var instance = this.extend();
+	                instance.init.apply(instance, arguments);
+
+	                return instance;
+	            },
+
+	            /**
+	             * Initializes a newly created object.
+	             * Override this method to add some logic when your objects are created.
+	             *
+	             * @example
+	             *
+	             *     var MyType = CryptoJS.lib.Base.extend({
+	             *         init: function () {
+	             *             // ...
+	             *         }
+	             *     });
+	             */
+	            init: function () {
+	            },
+
+	            /**
+	             * Copies properties into this object.
+	             *
+	             * @param {Object} properties The properties to mix in.
+	             *
+	             * @example
+	             *
+	             *     MyType.mixIn({
+	             *         field: 'value'
+	             *     });
+	             */
+	            mixIn: function (properties) {
+	                for (var propertyName in properties) {
+	                    if (properties.hasOwnProperty(propertyName)) {
+	                        this[propertyName] = properties[propertyName];
+	                    }
+	                }
+
+	                // IE won't copy toString using the loop above
+	                if (properties.hasOwnProperty('toString')) {
+	                    this.toString = properties.toString;
+	                }
+	            },
+
+	            /**
+	             * Creates a copy of this object.
+	             *
+	             * @return {Object} The clone.
+	             *
+	             * @example
+	             *
+	             *     var clone = instance.clone();
+	             */
+	            clone: function () {
+	                return this.init.prototype.extend(this);
+	            }
+	        };
+	    }());
+
+	    /**
+	     * An array of 32-bit words.
+	     *
+	     * @property {Array} words The array of 32-bit words.
+	     * @property {number} sigBytes The number of significant bytes in this word array.
+	     */
+	    var WordArray = C_lib.WordArray = Base.extend({
+	        /**
+	         * Initializes a newly created word array.
+	         *
+	         * @param {Array} words (Optional) An array of 32-bit words.
+	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.lib.WordArray.create();
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
+	         */
+	        init: function (words, sigBytes) {
+	            words = this.words = words || [];
+
+	            if (sigBytes != undefined) {
+	                this.sigBytes = sigBytes;
+	            } else {
+	                this.sigBytes = words.length * 4;
+	            }
+	        },
+
+	        /**
+	         * Converts this word array to a string.
+	         *
+	         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
+	         *
+	         * @return {string} The stringified word array.
+	         *
+	         * @example
+	         *
+	         *     var string = wordArray + '';
+	         *     var string = wordArray.toString();
+	         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
+	         */
+	        toString: function (encoder) {
+	            return (encoder || Hex).stringify(this);
+	        },
+
+	        /**
+	         * Concatenates a word array to this word array.
+	         *
+	         * @param {WordArray} wordArray The word array to append.
+	         *
+	         * @return {WordArray} This word array.
+	         *
+	         * @example
+	         *
+	         *     wordArray1.concat(wordArray2);
+	         */
+	        concat: function (wordArray) {
+	            // Shortcuts
+	            var thisWords = this.words;
+	            var thatWords = wordArray.words;
+	            var thisSigBytes = this.sigBytes;
+	            var thatSigBytes = wordArray.sigBytes;
+
+	            // Clamp excess bits
+	            this.clamp();
+
+	            // Concat
+	            if (thisSigBytes % 4) {
+	                // Copy one byte at a time
+	                for (var i = 0; i < thatSigBytes; i++) {
+	                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
+	                }
+	            } else {
+	                // Copy one word at a time
+	                for (var i = 0; i < thatSigBytes; i += 4) {
+	                    thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
+	                }
+	            }
+	            this.sigBytes += thatSigBytes;
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Removes insignificant bits.
+	         *
+	         * @example
+	         *
+	         *     wordArray.clamp();
+	         */
+	        clamp: function () {
+	            // Shortcuts
+	            var words = this.words;
+	            var sigBytes = this.sigBytes;
+
+	            // Clamp
+	            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
+	            words.length = Math.ceil(sigBytes / 4);
+	        },
+
+	        /**
+	         * Creates a copy of this word array.
+	         *
+	         * @return {WordArray} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = wordArray.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+	            clone.words = this.words.slice(0);
+
+	            return clone;
+	        },
+
+	        /**
+	         * Creates a word array filled with random bytes.
+	         *
+	         * @param {number} nBytes The number of random bytes to generate.
+	         *
+	         * @return {WordArray} The random word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.lib.WordArray.random(16);
+	         */
+	        random: function (nBytes) {
+	            var words = [];
+
+	            for (var i = 0; i < nBytes; i += 4) {
+	                words.push(cryptoSecureRandomInt());
+	            }
+
+	            return new WordArray.init(words, nBytes);
+	        }
+	    });
+
+	    /**
+	     * Encoder namespace.
+	     */
+	    var C_enc = C.enc = {};
+
+	    /**
+	     * Hex encoding strategy.
+	     */
+	    var Hex = C_enc.Hex = {
+	        /**
+	         * Converts a word array to a hex string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The hex string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var hexChars = [];
+	            for (var i = 0; i < sigBytes; i++) {
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                hexChars.push((bite >>> 4).toString(16));
+	                hexChars.push((bite & 0x0f).toString(16));
+	            }
+
+	            return hexChars.join('');
+	        },
+
+	        /**
+	         * Converts a hex string to a word array.
+	         *
+	         * @param {string} hexStr The hex string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
+	         */
+	        parse: function (hexStr) {
+	            // Shortcut
+	            var hexStrLength = hexStr.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < hexStrLength; i += 2) {
+	                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
+	            }
+
+	            return new WordArray.init(words, hexStrLength / 2);
+	        }
+	    };
+
+	    /**
+	     * Latin1 encoding strategy.
+	     */
+	    var Latin1 = C_enc.Latin1 = {
+	        /**
+	         * Converts a word array to a Latin1 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The Latin1 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var latin1Chars = [];
+	            for (var i = 0; i < sigBytes; i++) {
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
+	                latin1Chars.push(String.fromCharCode(bite));
+	            }
+
+	            return latin1Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Latin1 string to a word array.
+	         *
+	         * @param {string} latin1Str The Latin1 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
+	         */
+	        parse: function (latin1Str) {
+	            // Shortcut
+	            var latin1StrLength = latin1Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < latin1StrLength; i++) {
+	                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
+	            }
+
+	            return new WordArray.init(words, latin1StrLength);
+	        }
+	    };
+
+	    /**
+	     * UTF-8 encoding strategy.
+	     */
+	    var Utf8 = C_enc.Utf8 = {
+	        /**
+	         * Converts a word array to a UTF-8 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-8 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            try {
+	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
+	            } catch (e) {
+	                throw new Error('Malformed UTF-8 data');
+	            }
+	        },
+
+	        /**
+	         * Converts a UTF-8 string to a word array.
+	         *
+	         * @param {string} utf8Str The UTF-8 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
+	         */
+	        parse: function (utf8Str) {
+	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
+	        }
+	    };
+
+	    /**
+	     * Abstract buffered block algorithm template.
+	     *
+	     * The property blockSize must be implemented in a concrete subtype.
+	     *
+	     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
+	     */
+	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
+	        /**
+	         * Resets this block algorithm's data buffer to its initial state.
+	         *
+	         * @example
+	         *
+	         *     bufferedBlockAlgorithm.reset();
+	         */
+	        reset: function () {
+	            // Initial values
+	            this._data = new WordArray.init();
+	            this._nDataBytes = 0;
+	        },
+
+	        /**
+	         * Adds new data to this block algorithm's buffer.
+	         *
+	         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
+	         *
+	         * @example
+	         *
+	         *     bufferedBlockAlgorithm._append('data');
+	         *     bufferedBlockAlgorithm._append(wordArray);
+	         */
+	        _append: function (data) {
+	            // Convert string to WordArray, else assume WordArray already
+	            if (typeof data == 'string') {
+	                data = Utf8.parse(data);
+	            }
+
+	            // Append
+	            this._data.concat(data);
+	            this._nDataBytes += data.sigBytes;
+	        },
+
+	        /**
+	         * Processes available data blocks.
+	         *
+	         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
+	         *
+	         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
+	         *
+	         * @return {WordArray} The processed data.
+	         *
+	         * @example
+	         *
+	         *     var processedData = bufferedBlockAlgorithm._process();
+	         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
+	         */
+	        _process: function (doFlush) {
+	            var processedWords;
+
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+	            var dataSigBytes = data.sigBytes;
+	            var blockSize = this.blockSize;
+	            var blockSizeBytes = blockSize * 4;
+
+	            // Count blocks ready
+	            var nBlocksReady = dataSigBytes / blockSizeBytes;
+	            if (doFlush) {
+	                // Round up to include partial blocks
+	                nBlocksReady = Math.ceil(nBlocksReady);
+	            } else {
+	                // Round down to include only full blocks,
+	                // less the number of blocks that must remain in the buffer
+	                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
+	            }
+
+	            // Count words ready
+	            var nWordsReady = nBlocksReady * blockSize;
+
+	            // Count bytes ready
+	            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
+
+	            // Process blocks
+	            if (nWordsReady) {
+	                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
+	                    // Perform concrete-algorithm logic
+	                    this._doProcessBlock(dataWords, offset);
+	                }
+
+	                // Remove processed words
+	                processedWords = dataWords.splice(0, nWordsReady);
+	                data.sigBytes -= nBytesReady;
+	            }
+
+	            // Return processed words
+	            return new WordArray.init(processedWords, nBytesReady);
+	        },
+
+	        /**
+	         * Creates a copy of this object.
+	         *
+	         * @return {Object} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = bufferedBlockAlgorithm.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+	            clone._data = this._data.clone();
+
+	            return clone;
+	        },
+
+	        _minBufferSize: 0
+	    });
+
+	    /**
+	     * Abstract hasher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
+	     */
+	    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
+	        /**
+	         * Configuration options.
+	         */
+	        cfg: Base.extend(),
+
+	        /**
+	         * Initializes a newly created hasher.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
+	         *
+	         * @example
+	         *
+	         *     var hasher = CryptoJS.algo.SHA256.create();
+	         */
+	        init: function (cfg) {
+	            // Apply config defaults
+	            this.cfg = this.cfg.extend(cfg);
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this hasher to its initial state.
+	         *
+	         * @example
+	         *
+	         *     hasher.reset();
+	         */
+	        reset: function () {
+	            // Reset data buffer
+	            BufferedBlockAlgorithm.reset.call(this);
+
+	            // Perform concrete-hasher logic
+	            this._doReset();
+	        },
+
+	        /**
+	         * Updates this hasher with a message.
+	         *
+	         * @param {WordArray|string} messageUpdate The message to append.
+	         *
+	         * @return {Hasher} This hasher.
+	         *
+	         * @example
+	         *
+	         *     hasher.update('message');
+	         *     hasher.update(wordArray);
+	         */
+	        update: function (messageUpdate) {
+	            // Append
+	            this._append(messageUpdate);
+
+	            // Update the hash
+	            this._process();
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Finalizes the hash computation.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
+	         *
+	         * @return {WordArray} The hash.
+	         *
+	         * @example
+	         *
+	         *     var hash = hasher.finalize();
+	         *     var hash = hasher.finalize('message');
+	         *     var hash = hasher.finalize(wordArray);
+	         */
+	        finalize: function (messageUpdate) {
+	            // Final message update
+	            if (messageUpdate) {
+	                this._append(messageUpdate);
+	            }
+
+	            // Perform concrete-hasher logic
+	            var hash = this._doFinalize();
+
+	            return hash;
+	        },
+
+	        blockSize: 512/32,
+
+	        /**
+	         * Creates a shortcut function to a hasher's object interface.
+	         *
+	         * @param {Hasher} hasher The hasher to create a helper for.
+	         *
+	         * @return {Function} The shortcut function.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
+	         */
+	        _createHelper: function (hasher) {
+	            return function (message, cfg) {
+	                return new hasher.init(cfg).finalize(message);
+	            };
+	        },
+
+	        /**
+	         * Creates a shortcut function to the HMAC's object interface.
+	         *
+	         * @param {Hasher} hasher The hasher to use in this HMAC helper.
+	         *
+	         * @return {Function} The shortcut function.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
+	         */
+	        _createHmacHelper: function (hasher) {
+	            return function (message, key) {
+	                return new C_algo.HMAC.init(hasher, key).finalize(message);
+	            };
+	        }
+	    });
+
+	    /**
+	     * Algorithm namespace.
+	     */
+	    var C_algo = C.algo = {};
+
+	    return C;
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * Base64 encoding strategy.
+	     */
+	    var Base64 = C_enc.Base64 = {
+	        /**
+	         * Converts a word array to a Base64 string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The Base64 string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var base64String = CryptoJS.enc.Base64.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+	            var map = this._map;
+
+	            // Clamp excess bits
+	            wordArray.clamp();
+
+	            // Convert
+	            var base64Chars = [];
+	            for (var i = 0; i < sigBytes; i += 3) {
+	                var byte1 = (words[i >>> 2]       >>> (24 - (i % 4) * 8))       & 0xff;
+	                var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;
+	                var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;
+
+	                var triplet = (byte1 << 16) | (byte2 << 8) | byte3;
+
+	                for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {
+	                    base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));
+	                }
+	            }
+
+	            // Add padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                while (base64Chars.length % 4) {
+	                    base64Chars.push(paddingChar);
+	                }
+	            }
+
+	            return base64Chars.join('');
+	        },
+
+	        /**
+	         * Converts a Base64 string to a word array.
+	         *
+	         * @param {string} base64Str The Base64 string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Base64.parse(base64String);
+	         */
+	        parse: function (base64Str) {
+	            // Shortcuts
+	            var base64StrLength = base64Str.length;
+	            var map = this._map;
+	            var reverseMap = this._reverseMap;
+
+	            if (!reverseMap) {
+	                    reverseMap = this._reverseMap = [];
+	                    for (var j = 0; j < map.length; j++) {
+	                        reverseMap[map.charCodeAt(j)] = j;
+	                    }
+	            }
+
+	            // Ignore padding
+	            var paddingChar = map.charAt(64);
+	            if (paddingChar) {
+	                var paddingIndex = base64Str.indexOf(paddingChar);
+	                if (paddingIndex !== -1) {
+	                    base64StrLength = paddingIndex;
+	                }
+	            }
+
+	            // Convert
+	            return parseLoop(base64Str, base64StrLength, reverseMap);
+
+	        },
+
+	        _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
+	    };
+
+	    function parseLoop(base64Str, base64StrLength, reverseMap) {
+	      var words = [];
+	      var nBytes = 0;
+	      for (var i = 0; i < base64StrLength; i++) {
+	          if (i % 4) {
+	              var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
+	              var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
+	              var bitsCombined = bits1 | bits2;
+	              words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8);
+	              nBytes++;
+	          }
+	      }
+	      return WordArray.create(words, nBytes);
+	    }
+	}());
+
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Constants table
+	    var T = [];
+
+	    // Compute constants
+	    (function () {
+	        for (var i = 0; i < 64; i++) {
+	            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
+	        }
+	    }());
+
+	    /**
+	     * MD5 hash algorithm.
+	     */
+	    var MD5 = C_algo.MD5 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0x67452301, 0xefcdab89,
+	                0x98badcfe, 0x10325476
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Swap endian
+	            for (var i = 0; i < 16; i++) {
+	                // Shortcuts
+	                var offset_i = offset + i;
+	                var M_offset_i = M[offset_i];
+
+	                M[offset_i] = (
+	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
+	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
+	                );
+	            }
+
+	            // Shortcuts
+	            var H = this._hash.words;
+
+	            var M_offset_0  = M[offset + 0];
+	            var M_offset_1  = M[offset + 1];
+	            var M_offset_2  = M[offset + 2];
+	            var M_offset_3  = M[offset + 3];
+	            var M_offset_4  = M[offset + 4];
+	            var M_offset_5  = M[offset + 5];
+	            var M_offset_6  = M[offset + 6];
+	            var M_offset_7  = M[offset + 7];
+	            var M_offset_8  = M[offset + 8];
+	            var M_offset_9  = M[offset + 9];
+	            var M_offset_10 = M[offset + 10];
+	            var M_offset_11 = M[offset + 11];
+	            var M_offset_12 = M[offset + 12];
+	            var M_offset_13 = M[offset + 13];
+	            var M_offset_14 = M[offset + 14];
+	            var M_offset_15 = M[offset + 15];
+
+	            // Working varialbes
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+
+	            // Computation
+	            a = FF(a, b, c, d, M_offset_0,  7,  T[0]);
+	            d = FF(d, a, b, c, M_offset_1,  12, T[1]);
+	            c = FF(c, d, a, b, M_offset_2,  17, T[2]);
+	            b = FF(b, c, d, a, M_offset_3,  22, T[3]);
+	            a = FF(a, b, c, d, M_offset_4,  7,  T[4]);
+	            d = FF(d, a, b, c, M_offset_5,  12, T[5]);
+	            c = FF(c, d, a, b, M_offset_6,  17, T[6]);
+	            b = FF(b, c, d, a, M_offset_7,  22, T[7]);
+	            a = FF(a, b, c, d, M_offset_8,  7,  T[8]);
+	            d = FF(d, a, b, c, M_offset_9,  12, T[9]);
+	            c = FF(c, d, a, b, M_offset_10, 17, T[10]);
+	            b = FF(b, c, d, a, M_offset_11, 22, T[11]);
+	            a = FF(a, b, c, d, M_offset_12, 7,  T[12]);
+	            d = FF(d, a, b, c, M_offset_13, 12, T[13]);
+	            c = FF(c, d, a, b, M_offset_14, 17, T[14]);
+	            b = FF(b, c, d, a, M_offset_15, 22, T[15]);
+
+	            a = GG(a, b, c, d, M_offset_1,  5,  T[16]);
+	            d = GG(d, a, b, c, M_offset_6,  9,  T[17]);
+	            c = GG(c, d, a, b, M_offset_11, 14, T[18]);
+	            b = GG(b, c, d, a, M_offset_0,  20, T[19]);
+	            a = GG(a, b, c, d, M_offset_5,  5,  T[20]);
+	            d = GG(d, a, b, c, M_offset_10, 9,  T[21]);
+	            c = GG(c, d, a, b, M_offset_15, 14, T[22]);
+	            b = GG(b, c, d, a, M_offset_4,  20, T[23]);
+	            a = GG(a, b, c, d, M_offset_9,  5,  T[24]);
+	            d = GG(d, a, b, c, M_offset_14, 9,  T[25]);
+	            c = GG(c, d, a, b, M_offset_3,  14, T[26]);
+	            b = GG(b, c, d, a, M_offset_8,  20, T[27]);
+	            a = GG(a, b, c, d, M_offset_13, 5,  T[28]);
+	            d = GG(d, a, b, c, M_offset_2,  9,  T[29]);
+	            c = GG(c, d, a, b, M_offset_7,  14, T[30]);
+	            b = GG(b, c, d, a, M_offset_12, 20, T[31]);
+
+	            a = HH(a, b, c, d, M_offset_5,  4,  T[32]);
+	            d = HH(d, a, b, c, M_offset_8,  11, T[33]);
+	            c = HH(c, d, a, b, M_offset_11, 16, T[34]);
+	            b = HH(b, c, d, a, M_offset_14, 23, T[35]);
+	            a = HH(a, b, c, d, M_offset_1,  4,  T[36]);
+	            d = HH(d, a, b, c, M_offset_4,  11, T[37]);
+	            c = HH(c, d, a, b, M_offset_7,  16, T[38]);
+	            b = HH(b, c, d, a, M_offset_10, 23, T[39]);
+	            a = HH(a, b, c, d, M_offset_13, 4,  T[40]);
+	            d = HH(d, a, b, c, M_offset_0,  11, T[41]);
+	            c = HH(c, d, a, b, M_offset_3,  16, T[42]);
+	            b = HH(b, c, d, a, M_offset_6,  23, T[43]);
+	            a = HH(a, b, c, d, M_offset_9,  4,  T[44]);
+	            d = HH(d, a, b, c, M_offset_12, 11, T[45]);
+	            c = HH(c, d, a, b, M_offset_15, 16, T[46]);
+	            b = HH(b, c, d, a, M_offset_2,  23, T[47]);
+
+	            a = II(a, b, c, d, M_offset_0,  6,  T[48]);
+	            d = II(d, a, b, c, M_offset_7,  10, T[49]);
+	            c = II(c, d, a, b, M_offset_14, 15, T[50]);
+	            b = II(b, c, d, a, M_offset_5,  21, T[51]);
+	            a = II(a, b, c, d, M_offset_12, 6,  T[52]);
+	            d = II(d, a, b, c, M_offset_3,  10, T[53]);
+	            c = II(c, d, a, b, M_offset_10, 15, T[54]);
+	            b = II(b, c, d, a, M_offset_1,  21, T[55]);
+	            a = II(a, b, c, d, M_offset_8,  6,  T[56]);
+	            d = II(d, a, b, c, M_offset_15, 10, T[57]);
+	            c = II(c, d, a, b, M_offset_6,  15, T[58]);
+	            b = II(b, c, d, a, M_offset_13, 21, T[59]);
+	            a = II(a, b, c, d, M_offset_4,  6,  T[60]);
+	            d = II(d, a, b, c, M_offset_11, 10, T[61]);
+	            c = II(c, d, a, b, M_offset_2,  15, T[62]);
+	            b = II(b, c, d, a, M_offset_9,  21, T[63]);
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+
+	            var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
+	            var nBitsTotalL = nBitsTotal;
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
+	                (((nBitsTotalH << 8)  | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotalH << 24) | (nBitsTotalH >>> 8))  & 0xff00ff00)
+	            );
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
+	                (((nBitsTotalL << 8)  | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotalL << 24) | (nBitsTotalL >>> 8))  & 0xff00ff00)
+	            );
+
+	            data.sigBytes = (dataWords.length + 1) * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var hash = this._hash;
+	            var H = hash.words;
+
+	            // Swap endian
+	            for (var i = 0; i < 4; i++) {
+	                // Shortcut
+	                var H_i = H[i];
+
+	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
+	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    function FF(a, b, c, d, x, s, t) {
+	        var n = a + ((b & c) | (~b & d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function GG(a, b, c, d, x, s, t) {
+	        var n = a + ((b & d) | (c & ~d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function HH(a, b, c, d, x, s, t) {
+	        var n = a + (b ^ c ^ d) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    function II(a, b, c, d, x, s, t) {
+	        var n = a + (c ^ (b | ~d)) + x + t;
+	        return ((n << s) | (n >>> (32 - s))) + b;
+	    }
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.MD5('message');
+	     *     var hash = CryptoJS.MD5(wordArray);
+	     */
+	    C.MD5 = Hasher._createHelper(MD5);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacMD5(message, key);
+	     */
+	    C.HmacMD5 = Hasher._createHmacHelper(MD5);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Reusable object
+	    var W = [];
+
+	    /**
+	     * SHA-1 hash algorithm.
+	     */
+	    var SHA1 = C_algo.SHA1 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0x67452301, 0xefcdab89,
+	                0x98badcfe, 0x10325476,
+	                0xc3d2e1f0
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var H = this._hash.words;
+
+	            // Working variables
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+	            var e = H[4];
+
+	            // Computation
+	            for (var i = 0; i < 80; i++) {
+	                if (i < 16) {
+	                    W[i] = M[offset + i] | 0;
+	                } else {
+	                    var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
+	                    W[i] = (n << 1) | (n >>> 31);
+	                }
+
+	                var t = ((a << 5) | (a >>> 27)) + e + W[i];
+	                if (i < 20) {
+	                    t += ((b & c) | (~b & d)) + 0x5a827999;
+	                } else if (i < 40) {
+	                    t += (b ^ c ^ d) + 0x6ed9eba1;
+	                } else if (i < 60) {
+	                    t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;
+	                } else /* if (i < 80) */ {
+	                    t += (b ^ c ^ d) - 0x359d3e2a;
+	                }
+
+	                e = d;
+	                d = c;
+	                c = (b << 30) | (b >>> 2);
+	                b = a;
+	                a = t;
+	            }
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	            H[4] = (H[4] + e) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Return final computed hash
+	            return this._hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA1('message');
+	     *     var hash = CryptoJS.SHA1(wordArray);
+	     */
+	    C.SHA1 = Hasher._createHelper(SHA1);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA1(message, key);
+	     */
+	    C.HmacSHA1 = Hasher._createHmacHelper(SHA1);
+	}());
+
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Initialization and round constants tables
+	    var H = [];
+	    var K = [];
+
+	    // Compute constants
+	    (function () {
+	        function isPrime(n) {
+	            var sqrtN = Math.sqrt(n);
+	            for (var factor = 2; factor <= sqrtN; factor++) {
+	                if (!(n % factor)) {
+	                    return false;
+	                }
+	            }
+
+	            return true;
+	        }
+
+	        function getFractionalBits(n) {
+	            return ((n - (n | 0)) * 0x100000000) | 0;
+	        }
+
+	        var n = 2;
+	        var nPrime = 0;
+	        while (nPrime < 64) {
+	            if (isPrime(n)) {
+	                if (nPrime < 8) {
+	                    H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
+	                }
+	                K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));
+
+	                nPrime++;
+	            }
+
+	            n++;
+	        }
+	    }());
+
+	    // Reusable object
+	    var W = [];
+
+	    /**
+	     * SHA-256 hash algorithm.
+	     */
+	    var SHA256 = C_algo.SHA256 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init(H.slice(0));
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var H = this._hash.words;
+
+	            // Working variables
+	            var a = H[0];
+	            var b = H[1];
+	            var c = H[2];
+	            var d = H[3];
+	            var e = H[4];
+	            var f = H[5];
+	            var g = H[6];
+	            var h = H[7];
+
+	            // Computation
+	            for (var i = 0; i < 64; i++) {
+	                if (i < 16) {
+	                    W[i] = M[offset + i] | 0;
+	                } else {
+	                    var gamma0x = W[i - 15];
+	                    var gamma0  = ((gamma0x << 25) | (gamma0x >>> 7))  ^
+	                                  ((gamma0x << 14) | (gamma0x >>> 18)) ^
+	                                   (gamma0x >>> 3);
+
+	                    var gamma1x = W[i - 2];
+	                    var gamma1  = ((gamma1x << 15) | (gamma1x >>> 17)) ^
+	                                  ((gamma1x << 13) | (gamma1x >>> 19)) ^
+	                                   (gamma1x >>> 10);
+
+	                    W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
+	                }
+
+	                var ch  = (e & f) ^ (~e & g);
+	                var maj = (a & b) ^ (a & c) ^ (b & c);
+
+	                var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
+	                var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7)  | (e >>> 25));
+
+	                var t1 = h + sigma1 + ch + K[i] + W[i];
+	                var t2 = sigma0 + maj;
+
+	                h = g;
+	                g = f;
+	                f = e;
+	                e = (d + t1) | 0;
+	                d = c;
+	                c = b;
+	                b = a;
+	                a = (t1 + t2) | 0;
+	            }
+
+	            // Intermediate hash value
+	            H[0] = (H[0] + a) | 0;
+	            H[1] = (H[1] + b) | 0;
+	            H[2] = (H[2] + c) | 0;
+	            H[3] = (H[3] + d) | 0;
+	            H[4] = (H[4] + e) | 0;
+	            H[5] = (H[5] + f) | 0;
+	            H[6] = (H[6] + g) | 0;
+	            H[7] = (H[7] + h) | 0;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Return final computed hash
+	            return this._hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA256('message');
+	     *     var hash = CryptoJS.SHA256(wordArray);
+	     */
+	    C.SHA256 = Hasher._createHelper(SHA256);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA256(message, key);
+	     */
+	    C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_enc = C.enc;
+
+	    /**
+	     * UTF-16 BE encoding strategy.
+	     */
+	    var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = {
+	        /**
+	         * Converts a word array to a UTF-16 BE string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-16 BE string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf16String = CryptoJS.enc.Utf16.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var utf16Chars = [];
+	            for (var i = 0; i < sigBytes; i += 2) {
+	                var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff;
+	                utf16Chars.push(String.fromCharCode(codePoint));
+	            }
+
+	            return utf16Chars.join('');
+	        },
+
+	        /**
+	         * Converts a UTF-16 BE string to a word array.
+	         *
+	         * @param {string} utf16Str The UTF-16 BE string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf16.parse(utf16String);
+	         */
+	        parse: function (utf16Str) {
+	            // Shortcut
+	            var utf16StrLength = utf16Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < utf16StrLength; i++) {
+	                words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16);
+	            }
+
+	            return WordArray.create(words, utf16StrLength * 2);
+	        }
+	    };
+
+	    /**
+	     * UTF-16 LE encoding strategy.
+	     */
+	    C_enc.Utf16LE = {
+	        /**
+	         * Converts a word array to a UTF-16 LE string.
+	         *
+	         * @param {WordArray} wordArray The word array.
+	         *
+	         * @return {string} The UTF-16 LE string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray);
+	         */
+	        stringify: function (wordArray) {
+	            // Shortcuts
+	            var words = wordArray.words;
+	            var sigBytes = wordArray.sigBytes;
+
+	            // Convert
+	            var utf16Chars = [];
+	            for (var i = 0; i < sigBytes; i += 2) {
+	                var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff);
+	                utf16Chars.push(String.fromCharCode(codePoint));
+	            }
+
+	            return utf16Chars.join('');
+	        },
+
+	        /**
+	         * Converts a UTF-16 LE string to a word array.
+	         *
+	         * @param {string} utf16Str The UTF-16 LE string.
+	         *
+	         * @return {WordArray} The word array.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str);
+	         */
+	        parse: function (utf16Str) {
+	            // Shortcut
+	            var utf16StrLength = utf16Str.length;
+
+	            // Convert
+	            var words = [];
+	            for (var i = 0; i < utf16StrLength; i++) {
+	                words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16));
+	            }
+
+	            return WordArray.create(words, utf16StrLength * 2);
+	        }
+	    };
+
+	    function swapEndian(word) {
+	        return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff);
+	    }
+	}());
+
+
+	(function () {
+	    // Check if typed arrays are supported
+	    if (typeof ArrayBuffer != 'function') {
+	        return;
+	    }
+
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+
+	    // Reference original init
+	    var superInit = WordArray.init;
+
+	    // Augment WordArray.init to handle typed arrays
+	    var subInit = WordArray.init = function (typedArray) {
+	        // Convert buffers to uint8
+	        if (typedArray instanceof ArrayBuffer) {
+	            typedArray = new Uint8Array(typedArray);
+	        }
+
+	        // Convert other array views to uint8
+	        if (
+	            typedArray instanceof Int8Array ||
+	            (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) ||
+	            typedArray instanceof Int16Array ||
+	            typedArray instanceof Uint16Array ||
+	            typedArray instanceof Int32Array ||
+	            typedArray instanceof Uint32Array ||
+	            typedArray instanceof Float32Array ||
+	            typedArray instanceof Float64Array
+	        ) {
+	            typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);
+	        }
+
+	        // Handle Uint8Array
+	        if (typedArray instanceof Uint8Array) {
+	            // Shortcut
+	            var typedArrayByteLength = typedArray.byteLength;
+
+	            // Extract bytes
+	            var words = [];
+	            for (var i = 0; i < typedArrayByteLength; i++) {
+	                words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8);
+	            }
+
+	            // Initialize this word array
+	            superInit.call(this, words, typedArrayByteLength);
+	        } else {
+	            // Else call normal init
+	            superInit.apply(this, arguments);
+	        }
+	    };
+
+	    subInit.prototype = WordArray;
+	}());
+
+
+	/** @preserve
+	(c) 2012 by Cédric Mesnil. All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+	    - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+	    - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+	*/
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_algo = C.algo;
+
+	    // Constants table
+	    var _zl = WordArray.create([
+	        0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	        7,  4, 13,  1, 10,  6, 15,  3, 12,  0,  9,  5,  2, 14, 11,  8,
+	        3, 10, 14,  4,  9, 15,  8,  1,  2,  7,  0,  6, 13, 11,  5, 12,
+	        1,  9, 11, 10,  0,  8, 12,  4, 13,  3,  7, 15, 14,  5,  6,  2,
+	        4,  0,  5,  9,  7, 12,  2, 10, 14,  1,  3,  8, 11,  6, 15, 13]);
+	    var _zr = WordArray.create([
+	        5, 14,  7,  0,  9,  2, 11,  4, 13,  6, 15,  8,  1, 10,  3, 12,
+	        6, 11,  3,  7,  0, 13,  5, 10, 14, 15,  8, 12,  4,  9,  1,  2,
+	        15,  5,  1,  3,  7, 14,  6,  9, 11,  8, 12,  2, 10,  0,  4, 13,
+	        8,  6,  4,  1,  3, 11, 15,  0,  5, 12,  2, 13,  9,  7, 10, 14,
+	        12, 15, 10,  4,  1,  5,  8,  7,  6,  2, 13, 14,  0,  3,  9, 11]);
+	    var _sl = WordArray.create([
+	         11, 14, 15, 12,  5,  8,  7,  9, 11, 13, 14, 15,  6,  7,  9,  8,
+	        7, 6,   8, 13, 11,  9,  7, 15,  7, 12, 15,  9, 11,  7, 13, 12,
+	        11, 13,  6,  7, 14,  9, 13, 15, 14,  8, 13,  6,  5, 12,  7,  5,
+	          11, 12, 14, 15, 14, 15,  9,  8,  9, 14,  5,  6,  8,  6,  5, 12,
+	        9, 15,  5, 11,  6,  8, 13, 12,  5, 12, 13, 14, 11,  8,  5,  6 ]);
+	    var _sr = WordArray.create([
+	        8,  9,  9, 11, 13, 15, 15,  5,  7,  7,  8, 11, 14, 14, 12,  6,
+	        9, 13, 15,  7, 12,  8,  9, 11,  7,  7, 12,  7,  6, 15, 13, 11,
+	        9,  7, 15, 11,  8,  6,  6, 14, 12, 13,  5, 14, 13, 13,  7,  5,
+	        15,  5,  8, 11, 14, 14,  6, 14,  6,  9, 12,  9, 12,  5, 15,  8,
+	        8,  5, 12,  9, 12,  5, 14,  6,  8, 13,  6,  5, 15, 13, 11, 11 ]);
+
+	    var _hl =  WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]);
+	    var _hr =  WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]);
+
+	    /**
+	     * RIPEMD160 hash algorithm.
+	     */
+	    var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash  = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+
+	            // Swap endian
+	            for (var i = 0; i < 16; i++) {
+	                // Shortcuts
+	                var offset_i = offset + i;
+	                var M_offset_i = M[offset_i];
+
+	                // Swap
+	                M[offset_i] = (
+	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
+	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
+	                );
+	            }
+	            // Shortcut
+	            var H  = this._hash.words;
+	            var hl = _hl.words;
+	            var hr = _hr.words;
+	            var zl = _zl.words;
+	            var zr = _zr.words;
+	            var sl = _sl.words;
+	            var sr = _sr.words;
+
+	            // Working variables
+	            var al, bl, cl, dl, el;
+	            var ar, br, cr, dr, er;
+
+	            ar = al = H[0];
+	            br = bl = H[1];
+	            cr = cl = H[2];
+	            dr = dl = H[3];
+	            er = el = H[4];
+	            // Computation
+	            var t;
+	            for (var i = 0; i < 80; i += 1) {
+	                t = (al +  M[offset+zl[i]])|0;
+	                if (i<16){
+		            t +=  f1(bl,cl,dl) + hl[0];
+	                } else if (i<32) {
+		            t +=  f2(bl,cl,dl) + hl[1];
+	                } else if (i<48) {
+		            t +=  f3(bl,cl,dl) + hl[2];
+	                } else if (i<64) {
+		            t +=  f4(bl,cl,dl) + hl[3];
+	                } else {// if (i<80) {
+		            t +=  f5(bl,cl,dl) + hl[4];
+	                }
+	                t = t|0;
+	                t =  rotl(t,sl[i]);
+	                t = (t+el)|0;
+	                al = el;
+	                el = dl;
+	                dl = rotl(cl, 10);
+	                cl = bl;
+	                bl = t;
+
+	                t = (ar + M[offset+zr[i]])|0;
+	                if (i<16){
+		            t +=  f5(br,cr,dr) + hr[0];
+	                } else if (i<32) {
+		            t +=  f4(br,cr,dr) + hr[1];
+	                } else if (i<48) {
+		            t +=  f3(br,cr,dr) + hr[2];
+	                } else if (i<64) {
+		            t +=  f2(br,cr,dr) + hr[3];
+	                } else {// if (i<80) {
+		            t +=  f1(br,cr,dr) + hr[4];
+	                }
+	                t = t|0;
+	                t =  rotl(t,sr[i]) ;
+	                t = (t+er)|0;
+	                ar = er;
+	                er = dr;
+	                dr = rotl(cr, 10);
+	                cr = br;
+	                br = t;
+	            }
+	            // Intermediate hash value
+	            t    = (H[1] + cl + dr)|0;
+	            H[1] = (H[2] + dl + er)|0;
+	            H[2] = (H[3] + el + ar)|0;
+	            H[3] = (H[4] + al + br)|0;
+	            H[4] = (H[0] + bl + cr)|0;
+	            H[0] =  t;
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
+	                (((nBitsTotal << 8)  | (nBitsTotal >>> 24)) & 0x00ff00ff) |
+	                (((nBitsTotal << 24) | (nBitsTotal >>> 8))  & 0xff00ff00)
+	            );
+	            data.sigBytes = (dataWords.length + 1) * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var hash = this._hash;
+	            var H = hash.words;
+
+	            // Swap endian
+	            for (var i = 0; i < 5; i++) {
+	                // Shortcut
+	                var H_i = H[i];
+
+	                // Swap
+	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
+	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        }
+	    });
+
+
+	    function f1(x, y, z) {
+	        return ((x) ^ (y) ^ (z));
+
+	    }
+
+	    function f2(x, y, z) {
+	        return (((x)&(y)) | ((~x)&(z)));
+	    }
+
+	    function f3(x, y, z) {
+	        return (((x) | (~(y))) ^ (z));
+	    }
+
+	    function f4(x, y, z) {
+	        return (((x) & (z)) | ((y)&(~(z))));
+	    }
+
+	    function f5(x, y, z) {
+	        return ((x) ^ ((y) |(~(z))));
+
+	    }
+
+	    function rotl(x,n) {
+	        return (x<<n) | (x>>>(32-n));
+	    }
+
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.RIPEMD160('message');
+	     *     var hash = CryptoJS.RIPEMD160(wordArray);
+	     */
+	    C.RIPEMD160 = Hasher._createHelper(RIPEMD160);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacRIPEMD160(message, key);
+	     */
+	    C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var C_enc = C.enc;
+	    var Utf8 = C_enc.Utf8;
+	    var C_algo = C.algo;
+
+	    /**
+	     * HMAC algorithm.
+	     */
+	    var HMAC = C_algo.HMAC = Base.extend({
+	        /**
+	         * Initializes a newly created HMAC.
+	         *
+	         * @param {Hasher} hasher The hash algorithm to use.
+	         * @param {WordArray|string} key The secret key.
+	         *
+	         * @example
+	         *
+	         *     var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);
+	         */
+	        init: function (hasher, key) {
+	            // Init hasher
+	            hasher = this._hasher = new hasher.init();
+
+	            // Convert string to WordArray, else assume WordArray already
+	            if (typeof key == 'string') {
+	                key = Utf8.parse(key);
+	            }
+
+	            // Shortcuts
+	            var hasherBlockSize = hasher.blockSize;
+	            var hasherBlockSizeBytes = hasherBlockSize * 4;
+
+	            // Allow arbitrary length keys
+	            if (key.sigBytes > hasherBlockSizeBytes) {
+	                key = hasher.finalize(key);
+	            }
+
+	            // Clamp excess bits
+	            key.clamp();
+
+	            // Clone key for inner and outer pads
+	            var oKey = this._oKey = key.clone();
+	            var iKey = this._iKey = key.clone();
+
+	            // Shortcuts
+	            var oKeyWords = oKey.words;
+	            var iKeyWords = iKey.words;
+
+	            // XOR keys with pad constants
+	            for (var i = 0; i < hasherBlockSize; i++) {
+	                oKeyWords[i] ^= 0x5c5c5c5c;
+	                iKeyWords[i] ^= 0x36363636;
+	            }
+	            oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this HMAC to its initial state.
+	         *
+	         * @example
+	         *
+	         *     hmacHasher.reset();
+	         */
+	        reset: function () {
+	            // Shortcut
+	            var hasher = this._hasher;
+
+	            // Reset
+	            hasher.reset();
+	            hasher.update(this._iKey);
+	        },
+
+	        /**
+	         * Updates this HMAC with a message.
+	         *
+	         * @param {WordArray|string} messageUpdate The message to append.
+	         *
+	         * @return {HMAC} This HMAC instance.
+	         *
+	         * @example
+	         *
+	         *     hmacHasher.update('message');
+	         *     hmacHasher.update(wordArray);
+	         */
+	        update: function (messageUpdate) {
+	            this._hasher.update(messageUpdate);
+
+	            // Chainable
+	            return this;
+	        },
+
+	        /**
+	         * Finalizes the HMAC computation.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
+	         *
+	         * @return {WordArray} The HMAC.
+	         *
+	         * @example
+	         *
+	         *     var hmac = hmacHasher.finalize();
+	         *     var hmac = hmacHasher.finalize('message');
+	         *     var hmac = hmacHasher.finalize(wordArray);
+	         */
+	        finalize: function (messageUpdate) {
+	            // Shortcut
+	            var hasher = this._hasher;
+
+	            // Compute HMAC
+	            var innerHash = hasher.finalize(messageUpdate);
+	            hasher.reset();
+	            var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));
+
+	            return hmac;
+	        }
+	    });
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var SHA1 = C_algo.SHA1;
+	    var HMAC = C_algo.HMAC;
+
+	    /**
+	     * Password-Based Key Derivation Function 2 algorithm.
+	     */
+	    var PBKDF2 = C_algo.PBKDF2 = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
+	         * @property {Hasher} hasher The hasher to use. Default: SHA1
+	         * @property {number} iterations The number of iterations to perform. Default: 1
+	         */
+	        cfg: Base.extend({
+	            keySize: 128/32,
+	            hasher: SHA1,
+	            iterations: 1
+	        }),
+
+	        /**
+	         * Initializes a newly created key derivation function.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
+	         *
+	         * @example
+	         *
+	         *     var kdf = CryptoJS.algo.PBKDF2.create();
+	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 });
+	         *     var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 });
+	         */
+	        init: function (cfg) {
+	            this.cfg = this.cfg.extend(cfg);
+	        },
+
+	        /**
+	         * Computes the Password-Based Key Derivation Function 2.
+	         *
+	         * @param {WordArray|string} password The password.
+	         * @param {WordArray|string} salt A salt.
+	         *
+	         * @return {WordArray} The derived key.
+	         *
+	         * @example
+	         *
+	         *     var key = kdf.compute(password, salt);
+	         */
+	        compute: function (password, salt) {
+	            // Shortcut
+	            var cfg = this.cfg;
+
+	            // Init HMAC
+	            var hmac = HMAC.create(cfg.hasher, password);
+
+	            // Initial values
+	            var derivedKey = WordArray.create();
+	            var blockIndex = WordArray.create([0x00000001]);
+
+	            // Shortcuts
+	            var derivedKeyWords = derivedKey.words;
+	            var blockIndexWords = blockIndex.words;
+	            var keySize = cfg.keySize;
+	            var iterations = cfg.iterations;
+
+	            // Generate key
+	            while (derivedKeyWords.length < keySize) {
+	                var block = hmac.update(salt).finalize(blockIndex);
+	                hmac.reset();
+
+	                // Shortcuts
+	                var blockWords = block.words;
+	                var blockWordsLength = blockWords.length;
+
+	                // Iterations
+	                var intermediate = block;
+	                for (var i = 1; i < iterations; i++) {
+	                    intermediate = hmac.finalize(intermediate);
+	                    hmac.reset();
+
+	                    // Shortcut
+	                    var intermediateWords = intermediate.words;
+
+	                    // XOR intermediate with block
+	                    for (var j = 0; j < blockWordsLength; j++) {
+	                        blockWords[j] ^= intermediateWords[j];
+	                    }
+	                }
+
+	                derivedKey.concat(block);
+	                blockIndexWords[0]++;
+	            }
+	            derivedKey.sigBytes = keySize * 4;
+
+	            return derivedKey;
+	        }
+	    });
+
+	    /**
+	     * Computes the Password-Based Key Derivation Function 2.
+	     *
+	     * @param {WordArray|string} password The password.
+	     * @param {WordArray|string} salt A salt.
+	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
+	     *
+	     * @return {WordArray} The derived key.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var key = CryptoJS.PBKDF2(password, salt);
+	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 });
+	     *     var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 });
+	     */
+	    C.PBKDF2 = function (password, salt, cfg) {
+	        return PBKDF2.create(cfg).compute(password, salt);
+	    };
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var MD5 = C_algo.MD5;
+
+	    /**
+	     * This key derivation function is meant to conform with EVP_BytesToKey.
+	     * www.openssl.org/docs/crypto/EVP_BytesToKey.html
+	     */
+	    var EvpKDF = C_algo.EvpKDF = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)
+	         * @property {Hasher} hasher The hash algorithm to use. Default: MD5
+	         * @property {number} iterations The number of iterations to perform. Default: 1
+	         */
+	        cfg: Base.extend({
+	            keySize: 128/32,
+	            hasher: MD5,
+	            iterations: 1
+	        }),
+
+	        /**
+	         * Initializes a newly created key derivation function.
+	         *
+	         * @param {Object} cfg (Optional) The configuration options to use for the derivation.
+	         *
+	         * @example
+	         *
+	         *     var kdf = CryptoJS.algo.EvpKDF.create();
+	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 });
+	         *     var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 });
+	         */
+	        init: function (cfg) {
+	            this.cfg = this.cfg.extend(cfg);
+	        },
+
+	        /**
+	         * Derives a key from a password.
+	         *
+	         * @param {WordArray|string} password The password.
+	         * @param {WordArray|string} salt A salt.
+	         *
+	         * @return {WordArray} The derived key.
+	         *
+	         * @example
+	         *
+	         *     var key = kdf.compute(password, salt);
+	         */
+	        compute: function (password, salt) {
+	            var block;
+
+	            // Shortcut
+	            var cfg = this.cfg;
+
+	            // Init hasher
+	            var hasher = cfg.hasher.create();
+
+	            // Initial values
+	            var derivedKey = WordArray.create();
+
+	            // Shortcuts
+	            var derivedKeyWords = derivedKey.words;
+	            var keySize = cfg.keySize;
+	            var iterations = cfg.iterations;
+
+	            // Generate key
+	            while (derivedKeyWords.length < keySize) {
+	                if (block) {
+	                    hasher.update(block);
+	                }
+	                block = hasher.update(password).finalize(salt);
+	                hasher.reset();
+
+	                // Iterations
+	                for (var i = 1; i < iterations; i++) {
+	                    block = hasher.finalize(block);
+	                    hasher.reset();
+	                }
+
+	                derivedKey.concat(block);
+	            }
+	            derivedKey.sigBytes = keySize * 4;
+
+	            return derivedKey;
+	        }
+	    });
+
+	    /**
+	     * Derives a key from a password.
+	     *
+	     * @param {WordArray|string} password The password.
+	     * @param {WordArray|string} salt A salt.
+	     * @param {Object} cfg (Optional) The configuration options to use for this computation.
+	     *
+	     * @return {WordArray} The derived key.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var key = CryptoJS.EvpKDF(password, salt);
+	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 });
+	     *     var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 });
+	     */
+	    C.EvpKDF = function (password, salt, cfg) {
+	        return EvpKDF.create(cfg).compute(password, salt);
+	    };
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var C_algo = C.algo;
+	    var SHA256 = C_algo.SHA256;
+
+	    /**
+	     * SHA-224 hash algorithm.
+	     */
+	    var SHA224 = C_algo.SHA224 = SHA256.extend({
+	        _doReset: function () {
+	            this._hash = new WordArray.init([
+	                0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+	                0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
+	            ]);
+	        },
+
+	        _doFinalize: function () {
+	            var hash = SHA256._doFinalize.call(this);
+
+	            hash.sigBytes -= 4;
+
+	            return hash;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA224('message');
+	     *     var hash = CryptoJS.SHA224(wordArray);
+	     */
+	    C.SHA224 = SHA256._createHelper(SHA224);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA224(message, key);
+	     */
+	    C.HmacSHA224 = SHA256._createHmacHelper(SHA224);
+	}());
+
+
+	(function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var X32WordArray = C_lib.WordArray;
+
+	    /**
+	     * x64 namespace.
+	     */
+	    var C_x64 = C.x64 = {};
+
+	    /**
+	     * A 64-bit word.
+	     */
+	    var X64Word = C_x64.Word = Base.extend({
+	        /**
+	         * Initializes a newly created 64-bit word.
+	         *
+	         * @param {number} high The high 32 bits.
+	         * @param {number} low The low 32 bits.
+	         *
+	         * @example
+	         *
+	         *     var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607);
+	         */
+	        init: function (high, low) {
+	            this.high = high;
+	            this.low = low;
+	        }
+
+	        /**
+	         * Bitwise NOTs this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after negating.
+	         *
+	         * @example
+	         *
+	         *     var negated = x64Word.not();
+	         */
+	        // not: function () {
+	            // var high = ~this.high;
+	            // var low = ~this.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise ANDs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to AND with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after ANDing.
+	         *
+	         * @example
+	         *
+	         *     var anded = x64Word.and(anotherX64Word);
+	         */
+	        // and: function (word) {
+	            // var high = this.high & word.high;
+	            // var low = this.low & word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise ORs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to OR with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after ORing.
+	         *
+	         * @example
+	         *
+	         *     var ored = x64Word.or(anotherX64Word);
+	         */
+	        // or: function (word) {
+	            // var high = this.high | word.high;
+	            // var low = this.low | word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Bitwise XORs this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to XOR with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after XORing.
+	         *
+	         * @example
+	         *
+	         *     var xored = x64Word.xor(anotherX64Word);
+	         */
+	        // xor: function (word) {
+	            // var high = this.high ^ word.high;
+	            // var low = this.low ^ word.low;
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Shifts this word n bits to the left.
+	         *
+	         * @param {number} n The number of bits to shift.
+	         *
+	         * @return {X64Word} A new x64-Word object after shifting.
+	         *
+	         * @example
+	         *
+	         *     var shifted = x64Word.shiftL(25);
+	         */
+	        // shiftL: function (n) {
+	            // if (n < 32) {
+	                // var high = (this.high << n) | (this.low >>> (32 - n));
+	                // var low = this.low << n;
+	            // } else {
+	                // var high = this.low << (n - 32);
+	                // var low = 0;
+	            // }
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Shifts this word n bits to the right.
+	         *
+	         * @param {number} n The number of bits to shift.
+	         *
+	         * @return {X64Word} A new x64-Word object after shifting.
+	         *
+	         * @example
+	         *
+	         *     var shifted = x64Word.shiftR(7);
+	         */
+	        // shiftR: function (n) {
+	            // if (n < 32) {
+	                // var low = (this.low >>> n) | (this.high << (32 - n));
+	                // var high = this.high >>> n;
+	            // } else {
+	                // var low = this.high >>> (n - 32);
+	                // var high = 0;
+	            // }
+
+	            // return X64Word.create(high, low);
+	        // },
+
+	        /**
+	         * Rotates this word n bits to the left.
+	         *
+	         * @param {number} n The number of bits to rotate.
+	         *
+	         * @return {X64Word} A new x64-Word object after rotating.
+	         *
+	         * @example
+	         *
+	         *     var rotated = x64Word.rotL(25);
+	         */
+	        // rotL: function (n) {
+	            // return this.shiftL(n).or(this.shiftR(64 - n));
+	        // },
+
+	        /**
+	         * Rotates this word n bits to the right.
+	         *
+	         * @param {number} n The number of bits to rotate.
+	         *
+	         * @return {X64Word} A new x64-Word object after rotating.
+	         *
+	         * @example
+	         *
+	         *     var rotated = x64Word.rotR(7);
+	         */
+	        // rotR: function (n) {
+	            // return this.shiftR(n).or(this.shiftL(64 - n));
+	        // },
+
+	        /**
+	         * Adds this word with the passed word.
+	         *
+	         * @param {X64Word} word The x64-Word to add with this word.
+	         *
+	         * @return {X64Word} A new x64-Word object after adding.
+	         *
+	         * @example
+	         *
+	         *     var added = x64Word.add(anotherX64Word);
+	         */
+	        // add: function (word) {
+	            // var low = (this.low + word.low) | 0;
+	            // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0;
+	            // var high = (this.high + word.high + carry) | 0;
+
+	            // return X64Word.create(high, low);
+	        // }
+	    });
+
+	    /**
+	     * An array of 64-bit words.
+	     *
+	     * @property {Array} words The array of CryptoJS.x64.Word objects.
+	     * @property {number} sigBytes The number of significant bytes in this word array.
+	     */
+	    var X64WordArray = C_x64.WordArray = Base.extend({
+	        /**
+	         * Initializes a newly created word array.
+	         *
+	         * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects.
+	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
+	         *
+	         * @example
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create();
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create([
+	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
+	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
+	         *     ]);
+	         *
+	         *     var wordArray = CryptoJS.x64.WordArray.create([
+	         *         CryptoJS.x64.Word.create(0x00010203, 0x04050607),
+	         *         CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)
+	         *     ], 10);
+	         */
+	        init: function (words, sigBytes) {
+	            words = this.words = words || [];
+
+	            if (sigBytes != undefined) {
+	                this.sigBytes = sigBytes;
+	            } else {
+	                this.sigBytes = words.length * 8;
+	            }
+	        },
+
+	        /**
+	         * Converts this 64-bit word array to a 32-bit word array.
+	         *
+	         * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array.
+	         *
+	         * @example
+	         *
+	         *     var x32WordArray = x64WordArray.toX32();
+	         */
+	        toX32: function () {
+	            // Shortcuts
+	            var x64Words = this.words;
+	            var x64WordsLength = x64Words.length;
+
+	            // Convert
+	            var x32Words = [];
+	            for (var i = 0; i < x64WordsLength; i++) {
+	                var x64Word = x64Words[i];
+	                x32Words.push(x64Word.high);
+	                x32Words.push(x64Word.low);
+	            }
+
+	            return X32WordArray.create(x32Words, this.sigBytes);
+	        },
+
+	        /**
+	         * Creates a copy of this word array.
+	         *
+	         * @return {X64WordArray} The clone.
+	         *
+	         * @example
+	         *
+	         *     var clone = x64WordArray.clone();
+	         */
+	        clone: function () {
+	            var clone = Base.clone.call(this);
+
+	            // Clone "words" array
+	            var words = clone.words = this.words.slice(0);
+
+	            // Clone each X64Word object
+	            var wordsLength = words.length;
+	            for (var i = 0; i < wordsLength; i++) {
+	                words[i] = words[i].clone();
+	            }
+
+	            return clone;
+	        }
+	    });
+	}());
+
+
+	(function (Math) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var Hasher = C_lib.Hasher;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var C_algo = C.algo;
+
+	    // Constants tables
+	    var RHO_OFFSETS = [];
+	    var PI_INDEXES  = [];
+	    var ROUND_CONSTANTS = [];
+
+	    // Compute Constants
+	    (function () {
+	        // Compute rho offset constants
+	        var x = 1, y = 0;
+	        for (var t = 0; t < 24; t++) {
+	            RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64;
+
+	            var newX = y % 5;
+	            var newY = (2 * x + 3 * y) % 5;
+	            x = newX;
+	            y = newY;
+	        }
+
+	        // Compute pi index constants
+	        for (var x = 0; x < 5; x++) {
+	            for (var y = 0; y < 5; y++) {
+	                PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;
+	            }
+	        }
+
+	        // Compute round constants
+	        var LFSR = 0x01;
+	        for (var i = 0; i < 24; i++) {
+	            var roundConstantMsw = 0;
+	            var roundConstantLsw = 0;
+
+	            for (var j = 0; j < 7; j++) {
+	                if (LFSR & 0x01) {
+	                    var bitPosition = (1 << j) - 1;
+	                    if (bitPosition < 32) {
+	                        roundConstantLsw ^= 1 << bitPosition;
+	                    } else /* if (bitPosition >= 32) */ {
+	                        roundConstantMsw ^= 1 << (bitPosition - 32);
+	                    }
+	                }
+
+	                // Compute next LFSR
+	                if (LFSR & 0x80) {
+	                    // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1
+	                    LFSR = (LFSR << 1) ^ 0x71;
+	                } else {
+	                    LFSR <<= 1;
+	                }
+	            }
+
+	            ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);
+	        }
+	    }());
+
+	    // Reusable objects for temporary values
+	    var T = [];
+	    (function () {
+	        for (var i = 0; i < 25; i++) {
+	            T[i] = X64Word.create();
+	        }
+	    }());
+
+	    /**
+	     * SHA-3 hash algorithm.
+	     */
+	    var SHA3 = C_algo.SHA3 = Hasher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} outputLength
+	         *   The desired number of bits in the output hash.
+	         *   Only values permitted are: 224, 256, 384, 512.
+	         *   Default: 512
+	         */
+	        cfg: Hasher.cfg.extend({
+	            outputLength: 512
+	        }),
+
+	        _doReset: function () {
+	            var state = this._state = []
+	            for (var i = 0; i < 25; i++) {
+	                state[i] = new X64Word.init();
+	            }
+
+	            this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcuts
+	            var state = this._state;
+	            var nBlockSizeLanes = this.blockSize / 2;
+
+	            // Absorb
+	            for (var i = 0; i < nBlockSizeLanes; i++) {
+	                // Shortcuts
+	                var M2i  = M[offset + 2 * i];
+	                var M2i1 = M[offset + 2 * i + 1];
+
+	                // Swap endian
+	                M2i = (
+	                    (((M2i << 8)  | (M2i >>> 24)) & 0x00ff00ff) |
+	                    (((M2i << 24) | (M2i >>> 8))  & 0xff00ff00)
+	                );
+	                M2i1 = (
+	                    (((M2i1 << 8)  | (M2i1 >>> 24)) & 0x00ff00ff) |
+	                    (((M2i1 << 24) | (M2i1 >>> 8))  & 0xff00ff00)
+	                );
+
+	                // Absorb message into state
+	                var lane = state[i];
+	                lane.high ^= M2i1;
+	                lane.low  ^= M2i;
+	            }
+
+	            // Rounds
+	            for (var round = 0; round < 24; round++) {
+	                // Theta
+	                for (var x = 0; x < 5; x++) {
+	                    // Mix column lanes
+	                    var tMsw = 0, tLsw = 0;
+	                    for (var y = 0; y < 5; y++) {
+	                        var lane = state[x + 5 * y];
+	                        tMsw ^= lane.high;
+	                        tLsw ^= lane.low;
+	                    }
+
+	                    // Temporary values
+	                    var Tx = T[x];
+	                    Tx.high = tMsw;
+	                    Tx.low  = tLsw;
+	                }
+	                for (var x = 0; x < 5; x++) {
+	                    // Shortcuts
+	                    var Tx4 = T[(x + 4) % 5];
+	                    var Tx1 = T[(x + 1) % 5];
+	                    var Tx1Msw = Tx1.high;
+	                    var Tx1Lsw = Tx1.low;
+
+	                    // Mix surrounding columns
+	                    var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));
+	                    var tLsw = Tx4.low  ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));
+	                    for (var y = 0; y < 5; y++) {
+	                        var lane = state[x + 5 * y];
+	                        lane.high ^= tMsw;
+	                        lane.low  ^= tLsw;
+	                    }
+	                }
+
+	                // Rho Pi
+	                for (var laneIndex = 1; laneIndex < 25; laneIndex++) {
+	                    var tMsw;
+	                    var tLsw;
+
+	                    // Shortcuts
+	                    var lane = state[laneIndex];
+	                    var laneMsw = lane.high;
+	                    var laneLsw = lane.low;
+	                    var rhoOffset = RHO_OFFSETS[laneIndex];
+
+	                    // Rotate lanes
+	                    if (rhoOffset < 32) {
+	                        tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));
+	                        tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));
+	                    } else /* if (rhoOffset >= 32) */ {
+	                        tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));
+	                        tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));
+	                    }
+
+	                    // Transpose lanes
+	                    var TPiLane = T[PI_INDEXES[laneIndex]];
+	                    TPiLane.high = tMsw;
+	                    TPiLane.low  = tLsw;
+	                }
+
+	                // Rho pi at x = y = 0
+	                var T0 = T[0];
+	                var state0 = state[0];
+	                T0.high = state0.high;
+	                T0.low  = state0.low;
+
+	                // Chi
+	                for (var x = 0; x < 5; x++) {
+	                    for (var y = 0; y < 5; y++) {
+	                        // Shortcuts
+	                        var laneIndex = x + 5 * y;
+	                        var lane = state[laneIndex];
+	                        var TLane = T[laneIndex];
+	                        var Tx1Lane = T[((x + 1) % 5) + 5 * y];
+	                        var Tx2Lane = T[((x + 2) % 5) + 5 * y];
+
+	                        // Mix rows
+	                        lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);
+	                        lane.low  = TLane.low  ^ (~Tx1Lane.low  & Tx2Lane.low);
+	                    }
+	                }
+
+	                // Iota
+	                var lane = state[0];
+	                var roundConstant = ROUND_CONSTANTS[round];
+	                lane.high ^= roundConstant.high;
+	                lane.low  ^= roundConstant.low;
+	            }
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+	            var blockSizeBits = this.blockSize * 32;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32);
+	            dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Shortcuts
+	            var state = this._state;
+	            var outputLengthBytes = this.cfg.outputLength / 8;
+	            var outputLengthLanes = outputLengthBytes / 8;
+
+	            // Squeeze
+	            var hashWords = [];
+	            for (var i = 0; i < outputLengthLanes; i++) {
+	                // Shortcuts
+	                var lane = state[i];
+	                var laneMsw = lane.high;
+	                var laneLsw = lane.low;
+
+	                // Swap endian
+	                laneMsw = (
+	                    (((laneMsw << 8)  | (laneMsw >>> 24)) & 0x00ff00ff) |
+	                    (((laneMsw << 24) | (laneMsw >>> 8))  & 0xff00ff00)
+	                );
+	                laneLsw = (
+	                    (((laneLsw << 8)  | (laneLsw >>> 24)) & 0x00ff00ff) |
+	                    (((laneLsw << 24) | (laneLsw >>> 8))  & 0xff00ff00)
+	                );
+
+	                // Squeeze state to retrieve hash
+	                hashWords.push(laneLsw);
+	                hashWords.push(laneMsw);
+	            }
+
+	            // Return final computed hash
+	            return new WordArray.init(hashWords, outputLengthBytes);
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+
+	            var state = clone._state = this._state.slice(0);
+	            for (var i = 0; i < 25; i++) {
+	                state[i] = state[i].clone();
+	            }
+
+	            return clone;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA3('message');
+	     *     var hash = CryptoJS.SHA3(wordArray);
+	     */
+	    C.SHA3 = Hasher._createHelper(SHA3);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA3(message, key);
+	     */
+	    C.HmacSHA3 = Hasher._createHmacHelper(SHA3);
+	}(Math));
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Hasher = C_lib.Hasher;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var X64WordArray = C_x64.WordArray;
+	    var C_algo = C.algo;
+
+	    function X64Word_create() {
+	        return X64Word.create.apply(X64Word, arguments);
+	    }
+
+	    // Constants
+	    var K = [
+	        X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd),
+	        X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc),
+	        X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019),
+	        X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118),
+	        X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe),
+	        X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2),
+	        X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1),
+	        X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694),
+	        X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3),
+	        X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65),
+	        X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483),
+	        X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5),
+	        X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210),
+	        X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4),
+	        X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725),
+	        X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70),
+	        X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926),
+	        X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df),
+	        X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8),
+	        X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b),
+	        X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001),
+	        X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30),
+	        X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910),
+	        X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8),
+	        X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53),
+	        X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8),
+	        X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb),
+	        X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3),
+	        X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60),
+	        X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec),
+	        X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9),
+	        X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b),
+	        X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207),
+	        X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178),
+	        X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6),
+	        X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b),
+	        X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493),
+	        X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c),
+	        X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a),
+	        X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817)
+	    ];
+
+	    // Reusable objects
+	    var W = [];
+	    (function () {
+	        for (var i = 0; i < 80; i++) {
+	            W[i] = X64Word_create();
+	        }
+	    }());
+
+	    /**
+	     * SHA-512 hash algorithm.
+	     */
+	    var SHA512 = C_algo.SHA512 = Hasher.extend({
+	        _doReset: function () {
+	            this._hash = new X64WordArray.init([
+	                new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b),
+	                new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1),
+	                new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f),
+	                new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179)
+	            ]);
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcuts
+	            var H = this._hash.words;
+
+	            var H0 = H[0];
+	            var H1 = H[1];
+	            var H2 = H[2];
+	            var H3 = H[3];
+	            var H4 = H[4];
+	            var H5 = H[5];
+	            var H6 = H[6];
+	            var H7 = H[7];
+
+	            var H0h = H0.high;
+	            var H0l = H0.low;
+	            var H1h = H1.high;
+	            var H1l = H1.low;
+	            var H2h = H2.high;
+	            var H2l = H2.low;
+	            var H3h = H3.high;
+	            var H3l = H3.low;
+	            var H4h = H4.high;
+	            var H4l = H4.low;
+	            var H5h = H5.high;
+	            var H5l = H5.low;
+	            var H6h = H6.high;
+	            var H6l = H6.low;
+	            var H7h = H7.high;
+	            var H7l = H7.low;
+
+	            // Working variables
+	            var ah = H0h;
+	            var al = H0l;
+	            var bh = H1h;
+	            var bl = H1l;
+	            var ch = H2h;
+	            var cl = H2l;
+	            var dh = H3h;
+	            var dl = H3l;
+	            var eh = H4h;
+	            var el = H4l;
+	            var fh = H5h;
+	            var fl = H5l;
+	            var gh = H6h;
+	            var gl = H6l;
+	            var hh = H7h;
+	            var hl = H7l;
+
+	            // Rounds
+	            for (var i = 0; i < 80; i++) {
+	                var Wil;
+	                var Wih;
+
+	                // Shortcut
+	                var Wi = W[i];
+
+	                // Extend message
+	                if (i < 16) {
+	                    Wih = Wi.high = M[offset + i * 2]     | 0;
+	                    Wil = Wi.low  = M[offset + i * 2 + 1] | 0;
+	                } else {
+	                    // Gamma0
+	                    var gamma0x  = W[i - 15];
+	                    var gamma0xh = gamma0x.high;
+	                    var gamma0xl = gamma0x.low;
+	                    var gamma0h  = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7);
+	                    var gamma0l  = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25));
+
+	                    // Gamma1
+	                    var gamma1x  = W[i - 2];
+	                    var gamma1xh = gamma1x.high;
+	                    var gamma1xl = gamma1x.low;
+	                    var gamma1h  = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6);
+	                    var gamma1l  = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26));
+
+	                    // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]
+	                    var Wi7  = W[i - 7];
+	                    var Wi7h = Wi7.high;
+	                    var Wi7l = Wi7.low;
+
+	                    var Wi16  = W[i - 16];
+	                    var Wi16h = Wi16.high;
+	                    var Wi16l = Wi16.low;
+
+	                    Wil = gamma0l + Wi7l;
+	                    Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0);
+	                    Wil = Wil + gamma1l;
+	                    Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0);
+	                    Wil = Wil + Wi16l;
+	                    Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0);
+
+	                    Wi.high = Wih;
+	                    Wi.low  = Wil;
+	                }
+
+	                var chh  = (eh & fh) ^ (~eh & gh);
+	                var chl  = (el & fl) ^ (~el & gl);
+	                var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
+	                var majl = (al & bl) ^ (al & cl) ^ (bl & cl);
+
+	                var sigma0h = ((ah >>> 28) | (al << 4))  ^ ((ah << 30)  | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
+	                var sigma0l = ((al >>> 28) | (ah << 4))  ^ ((al << 30)  | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
+	                var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9));
+	                var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9));
+
+	                // t1 = h + sigma1 + ch + K[i] + W[i]
+	                var Ki  = K[i];
+	                var Kih = Ki.high;
+	                var Kil = Ki.low;
+
+	                var t1l = hl + sigma1l;
+	                var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
+	                var t1l = t1l + chl;
+	                var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
+	                var t1l = t1l + Kil;
+	                var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0);
+	                var t1l = t1l + Wil;
+	                var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0);
+
+	                // t2 = sigma0 + maj
+	                var t2l = sigma0l + majl;
+	                var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);
+
+	                // Update working variables
+	                hh = gh;
+	                hl = gl;
+	                gh = fh;
+	                gl = fl;
+	                fh = eh;
+	                fl = el;
+	                el = (dl + t1l) | 0;
+	                eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+	                dh = ch;
+	                dl = cl;
+	                ch = bh;
+	                cl = bl;
+	                bh = ah;
+	                bl = al;
+	                al = (t1l + t2l) | 0;
+	                ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
+	            }
+
+	            // Intermediate hash value
+	            H0l = H0.low  = (H0l + al);
+	            H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0));
+	            H1l = H1.low  = (H1l + bl);
+	            H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0));
+	            H2l = H2.low  = (H2l + cl);
+	            H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0));
+	            H3l = H3.low  = (H3l + dl);
+	            H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0));
+	            H4l = H4.low  = (H4l + el);
+	            H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0));
+	            H5l = H5.low  = (H5l + fl);
+	            H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0));
+	            H6l = H6.low  = (H6l + gl);
+	            H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0));
+	            H7l = H7.low  = (H7l + hl);
+	            H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0));
+	        },
+
+	        _doFinalize: function () {
+	            // Shortcuts
+	            var data = this._data;
+	            var dataWords = data.words;
+
+	            var nBitsTotal = this._nDataBytes * 8;
+	            var nBitsLeft = data.sigBytes * 8;
+
+	            // Add padding
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
+	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000);
+	            dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal;
+	            data.sigBytes = dataWords.length * 4;
+
+	            // Hash final blocks
+	            this._process();
+
+	            // Convert hash to 32-bit word array before returning
+	            var hash = this._hash.toX32();
+
+	            // Return final computed hash
+	            return hash;
+	        },
+
+	        clone: function () {
+	            var clone = Hasher.clone.call(this);
+	            clone._hash = this._hash.clone();
+
+	            return clone;
+	        },
+
+	        blockSize: 1024/32
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA512('message');
+	     *     var hash = CryptoJS.SHA512(wordArray);
+	     */
+	    C.SHA512 = Hasher._createHelper(SHA512);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA512(message, key);
+	     */
+	    C.HmacSHA512 = Hasher._createHmacHelper(SHA512);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_x64 = C.x64;
+	    var X64Word = C_x64.Word;
+	    var X64WordArray = C_x64.WordArray;
+	    var C_algo = C.algo;
+	    var SHA512 = C_algo.SHA512;
+
+	    /**
+	     * SHA-384 hash algorithm.
+	     */
+	    var SHA384 = C_algo.SHA384 = SHA512.extend({
+	        _doReset: function () {
+	            this._hash = new X64WordArray.init([
+	                new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507),
+	                new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939),
+	                new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511),
+	                new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4)
+	            ]);
+	        },
+
+	        _doFinalize: function () {
+	            var hash = SHA512._doFinalize.call(this);
+
+	            hash.sigBytes -= 16;
+
+	            return hash;
+	        }
+	    });
+
+	    /**
+	     * Shortcut function to the hasher's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     *
+	     * @return {WordArray} The hash.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hash = CryptoJS.SHA384('message');
+	     *     var hash = CryptoJS.SHA384(wordArray);
+	     */
+	    C.SHA384 = SHA512._createHelper(SHA384);
+
+	    /**
+	     * Shortcut function to the HMAC's object interface.
+	     *
+	     * @param {WordArray|string} message The message to hash.
+	     * @param {WordArray|string} key The secret key.
+	     *
+	     * @return {WordArray} The HMAC.
+	     *
+	     * @static
+	     *
+	     * @example
+	     *
+	     *     var hmac = CryptoJS.HmacSHA384(message, key);
+	     */
+	    C.HmacSHA384 = SHA512._createHmacHelper(SHA384);
+	}());
+
+
+	/**
+	 * Cipher core components.
+	 */
+	CryptoJS.lib.Cipher || (function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var Base = C_lib.Base;
+	    var WordArray = C_lib.WordArray;
+	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm;
+	    var C_enc = C.enc;
+	    var Utf8 = C_enc.Utf8;
+	    var Base64 = C_enc.Base64;
+	    var C_algo = C.algo;
+	    var EvpKDF = C_algo.EvpKDF;
+
+	    /**
+	     * Abstract base cipher template.
+	     *
+	     * @property {number} keySize This cipher's key size. Default: 4 (128 bits)
+	     * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)
+	     * @property {number} _ENC_XFORM_MODE A constant representing encryption mode.
+	     * @property {number} _DEC_XFORM_MODE A constant representing decryption mode.
+	     */
+	    var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {WordArray} iv The IV to use for this operation.
+	         */
+	        cfg: Base.extend(),
+
+	        /**
+	         * Creates this cipher in encryption mode.
+	         *
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {Cipher} A cipher instance.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });
+	         */
+	        createEncryptor: function (key, cfg) {
+	            return this.create(this._ENC_XFORM_MODE, key, cfg);
+	        },
+
+	        /**
+	         * Creates this cipher in decryption mode.
+	         *
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {Cipher} A cipher instance.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });
+	         */
+	        createDecryptor: function (key, cfg) {
+	            return this.create(this._DEC_XFORM_MODE, key, cfg);
+	        },
+
+	        /**
+	         * Initializes a newly created cipher.
+	         *
+	         * @param {number} xformMode Either the encryption or decryption transormation mode constant.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @example
+	         *
+	         *     var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });
+	         */
+	        init: function (xformMode, key, cfg) {
+	            // Apply config defaults
+	            this.cfg = this.cfg.extend(cfg);
+
+	            // Store transform mode and key
+	            this._xformMode = xformMode;
+	            this._key = key;
+
+	            // Set initial values
+	            this.reset();
+	        },
+
+	        /**
+	         * Resets this cipher to its initial state.
+	         *
+	         * @example
+	         *
+	         *     cipher.reset();
+	         */
+	        reset: function () {
+	            // Reset data buffer
+	            BufferedBlockAlgorithm.reset.call(this);
+
+	            // Perform concrete-cipher logic
+	            this._doReset();
+	        },
+
+	        /**
+	         * Adds data to be encrypted or decrypted.
+	         *
+	         * @param {WordArray|string} dataUpdate The data to encrypt or decrypt.
+	         *
+	         * @return {WordArray} The data after processing.
+	         *
+	         * @example
+	         *
+	         *     var encrypted = cipher.process('data');
+	         *     var encrypted = cipher.process(wordArray);
+	         */
+	        process: function (dataUpdate) {
+	            // Append
+	            this._append(dataUpdate);
+
+	            // Process available blocks
+	            return this._process();
+	        },
+
+	        /**
+	         * Finalizes the encryption or decryption process.
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
+	         *
+	         * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.
+	         *
+	         * @return {WordArray} The data after final processing.
+	         *
+	         * @example
+	         *
+	         *     var encrypted = cipher.finalize();
+	         *     var encrypted = cipher.finalize('data');
+	         *     var encrypted = cipher.finalize(wordArray);
+	         */
+	        finalize: function (dataUpdate) {
+	            // Final data update
+	            if (dataUpdate) {
+	                this._append(dataUpdate);
+	            }
+
+	            // Perform concrete-cipher logic
+	            var finalProcessedData = this._doFinalize();
+
+	            return finalProcessedData;
+	        },
+
+	        keySize: 128/32,
+
+	        ivSize: 128/32,
+
+	        _ENC_XFORM_MODE: 1,
+
+	        _DEC_XFORM_MODE: 2,
+
+	        /**
+	         * Creates shortcut functions to a cipher's object interface.
+	         *
+	         * @param {Cipher} cipher The cipher to create a helper for.
+	         *
+	         * @return {Object} An object with encrypt and decrypt shortcut functions.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);
+	         */
+	        _createHelper: (function () {
+	            function selectCipherStrategy(key) {
+	                if (typeof key == 'string') {
+	                    return PasswordBasedCipher;
+	                } else {
+	                    return SerializableCipher;
+	                }
+	            }
+
+	            return function (cipher) {
+	                return {
+	                    encrypt: function (message, key, cfg) {
+	                        return selectCipherStrategy(key).encrypt(cipher, message, key, cfg);
+	                    },
+
+	                    decrypt: function (ciphertext, key, cfg) {
+	                        return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg);
+	                    }
+	                };
+	            };
+	        }())
+	    });
+
+	    /**
+	     * Abstract base stream cipher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits)
+	     */
+	    var StreamCipher = C_lib.StreamCipher = Cipher.extend({
+	        _doFinalize: function () {
+	            // Process partial blocks
+	            var finalProcessedBlocks = this._process(!!'flush');
+
+	            return finalProcessedBlocks;
+	        },
+
+	        blockSize: 1
+	    });
+
+	    /**
+	     * Mode namespace.
+	     */
+	    var C_mode = C.mode = {};
+
+	    /**
+	     * Abstract base block cipher mode template.
+	     */
+	    var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({
+	        /**
+	         * Creates this mode for encryption.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
+	         */
+	        createEncryptor: function (cipher, iv) {
+	            return this.Encryptor.create(cipher, iv);
+	        },
+
+	        /**
+	         * Creates this mode for decryption.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);
+	         */
+	        createDecryptor: function (cipher, iv) {
+	            return this.Decryptor.create(cipher, iv);
+	        },
+
+	        /**
+	         * Initializes a newly created mode.
+	         *
+	         * @param {Cipher} cipher A block cipher instance.
+	         * @param {Array} iv The IV words.
+	         *
+	         * @example
+	         *
+	         *     var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);
+	         */
+	        init: function (cipher, iv) {
+	            this._cipher = cipher;
+	            this._iv = iv;
+	        }
+	    });
+
+	    /**
+	     * Cipher Block Chaining mode.
+	     */
+	    var CBC = C_mode.CBC = (function () {
+	        /**
+	         * Abstract base CBC mode.
+	         */
+	        var CBC = BlockCipherMode.extend();
+
+	        /**
+	         * CBC encryptor.
+	         */
+	        CBC.Encryptor = CBC.extend({
+	            /**
+	             * Processes the data block at offset.
+	             *
+	             * @param {Array} words The data words to operate on.
+	             * @param {number} offset The offset where the block starts.
+	             *
+	             * @example
+	             *
+	             *     mode.processBlock(data.words, offset);
+	             */
+	            processBlock: function (words, offset) {
+	                // Shortcuts
+	                var cipher = this._cipher;
+	                var blockSize = cipher.blockSize;
+
+	                // XOR and encrypt
+	                xorBlock.call(this, words, offset, blockSize);
+	                cipher.encryptBlock(words, offset);
+
+	                // Remember this block to use with next block
+	                this._prevBlock = words.slice(offset, offset + blockSize);
+	            }
+	        });
+
+	        /**
+	         * CBC decryptor.
+	         */
+	        CBC.Decryptor = CBC.extend({
+	            /**
+	             * Processes the data block at offset.
+	             *
+	             * @param {Array} words The data words to operate on.
+	             * @param {number} offset The offset where the block starts.
+	             *
+	             * @example
+	             *
+	             *     mode.processBlock(data.words, offset);
+	             */
+	            processBlock: function (words, offset) {
+	                // Shortcuts
+	                var cipher = this._cipher;
+	                var blockSize = cipher.blockSize;
+
+	                // Remember this block to use with next block
+	                var thisBlock = words.slice(offset, offset + blockSize);
+
+	                // Decrypt and XOR
+	                cipher.decryptBlock(words, offset);
+	                xorBlock.call(this, words, offset, blockSize);
+
+	                // This block becomes the previous block
+	                this._prevBlock = thisBlock;
+	            }
+	        });
+
+	        function xorBlock(words, offset, blockSize) {
+	            var block;
+
+	            // Shortcut
+	            var iv = this._iv;
+
+	            // Choose mixing block
+	            if (iv) {
+	                block = iv;
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            } else {
+	                block = this._prevBlock;
+	            }
+
+	            // XOR blocks
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= block[i];
+	            }
+	        }
+
+	        return CBC;
+	    }());
+
+	    /**
+	     * Padding namespace.
+	     */
+	    var C_pad = C.pad = {};
+
+	    /**
+	     * PKCS #5/7 padding strategy.
+	     */
+	    var Pkcs7 = C_pad.Pkcs7 = {
+	        /**
+	         * Pads data using the algorithm defined in PKCS #5/7.
+	         *
+	         * @param {WordArray} data The data to pad.
+	         * @param {number} blockSize The multiple that the data should be padded to.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     CryptoJS.pad.Pkcs7.pad(wordArray, 4);
+	         */
+	        pad: function (data, blockSize) {
+	            // Shortcut
+	            var blockSizeBytes = blockSize * 4;
+
+	            // Count padding bytes
+	            var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
+
+	            // Create padding word
+	            var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes;
+
+	            // Create padding
+	            var paddingWords = [];
+	            for (var i = 0; i < nPaddingBytes; i += 4) {
+	                paddingWords.push(paddingWord);
+	            }
+	            var padding = WordArray.create(paddingWords, nPaddingBytes);
+
+	            // Add padding
+	            data.concat(padding);
+	        },
+
+	        /**
+	         * Unpads data that had been padded using the algorithm defined in PKCS #5/7.
+	         *
+	         * @param {WordArray} data The data to unpad.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     CryptoJS.pad.Pkcs7.unpad(wordArray);
+	         */
+	        unpad: function (data) {
+	            // Get number of padding bytes from last byte
+	            var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	            // Remove padding
+	            data.sigBytes -= nPaddingBytes;
+	        }
+	    };
+
+	    /**
+	     * Abstract base block cipher template.
+	     *
+	     * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits)
+	     */
+	    var BlockCipher = C_lib.BlockCipher = Cipher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {Mode} mode The block mode to use. Default: CBC
+	         * @property {Padding} padding The padding strategy to use. Default: Pkcs7
+	         */
+	        cfg: Cipher.cfg.extend({
+	            mode: CBC,
+	            padding: Pkcs7
+	        }),
+
+	        reset: function () {
+	            var modeCreator;
+
+	            // Reset cipher
+	            Cipher.reset.call(this);
+
+	            // Shortcuts
+	            var cfg = this.cfg;
+	            var iv = cfg.iv;
+	            var mode = cfg.mode;
+
+	            // Reset block mode
+	            if (this._xformMode == this._ENC_XFORM_MODE) {
+	                modeCreator = mode.createEncryptor;
+	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
+	                modeCreator = mode.createDecryptor;
+	                // Keep at least one block in the buffer for unpadding
+	                this._minBufferSize = 1;
+	            }
+
+	            if (this._mode && this._mode.__creator == modeCreator) {
+	                this._mode.init(this, iv && iv.words);
+	            } else {
+	                this._mode = modeCreator.call(mode, this, iv && iv.words);
+	                this._mode.__creator = modeCreator;
+	            }
+	        },
+
+	        _doProcessBlock: function (words, offset) {
+	            this._mode.processBlock(words, offset);
+	        },
+
+	        _doFinalize: function () {
+	            var finalProcessedBlocks;
+
+	            // Shortcut
+	            var padding = this.cfg.padding;
+
+	            // Finalize
+	            if (this._xformMode == this._ENC_XFORM_MODE) {
+	                // Pad data
+	                padding.pad(this._data, this.blockSize);
+
+	                // Process final blocks
+	                finalProcessedBlocks = this._process(!!'flush');
+	            } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
+	                // Process final blocks
+	                finalProcessedBlocks = this._process(!!'flush');
+
+	                // Unpad data
+	                padding.unpad(finalProcessedBlocks);
+	            }
+
+	            return finalProcessedBlocks;
+	        },
+
+	        blockSize: 128/32
+	    });
+
+	    /**
+	     * A collection of cipher parameters.
+	     *
+	     * @property {WordArray} ciphertext The raw ciphertext.
+	     * @property {WordArray} key The key to this ciphertext.
+	     * @property {WordArray} iv The IV used in the ciphering operation.
+	     * @property {WordArray} salt The salt used with a key derivation function.
+	     * @property {Cipher} algorithm The cipher algorithm.
+	     * @property {Mode} mode The block mode used in the ciphering operation.
+	     * @property {Padding} padding The padding scheme used in the ciphering operation.
+	     * @property {number} blockSize The block size of the cipher.
+	     * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string.
+	     */
+	    var CipherParams = C_lib.CipherParams = Base.extend({
+	        /**
+	         * Initializes a newly created cipher params object.
+	         *
+	         * @param {Object} cipherParams An object with any of the possible cipher parameters.
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.lib.CipherParams.create({
+	         *         ciphertext: ciphertextWordArray,
+	         *         key: keyWordArray,
+	         *         iv: ivWordArray,
+	         *         salt: saltWordArray,
+	         *         algorithm: CryptoJS.algo.AES,
+	         *         mode: CryptoJS.mode.CBC,
+	         *         padding: CryptoJS.pad.PKCS7,
+	         *         blockSize: 4,
+	         *         formatter: CryptoJS.format.OpenSSL
+	         *     });
+	         */
+	        init: function (cipherParams) {
+	            this.mixIn(cipherParams);
+	        },
+
+	        /**
+	         * Converts this cipher params object to a string.
+	         *
+	         * @param {Format} formatter (Optional) The formatting strategy to use.
+	         *
+	         * @return {string} The stringified cipher params.
+	         *
+	         * @throws Error If neither the formatter nor the default formatter is set.
+	         *
+	         * @example
+	         *
+	         *     var string = cipherParams + '';
+	         *     var string = cipherParams.toString();
+	         *     var string = cipherParams.toString(CryptoJS.format.OpenSSL);
+	         */
+	        toString: function (formatter) {
+	            return (formatter || this.formatter).stringify(this);
+	        }
+	    });
+
+	    /**
+	     * Format namespace.
+	     */
+	    var C_format = C.format = {};
+
+	    /**
+	     * OpenSSL formatting strategy.
+	     */
+	    var OpenSSLFormatter = C_format.OpenSSL = {
+	        /**
+	         * Converts a cipher params object to an OpenSSL-compatible string.
+	         *
+	         * @param {CipherParams} cipherParams The cipher params object.
+	         *
+	         * @return {string} The OpenSSL-compatible string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);
+	         */
+	        stringify: function (cipherParams) {
+	            var wordArray;
+
+	            // Shortcuts
+	            var ciphertext = cipherParams.ciphertext;
+	            var salt = cipherParams.salt;
+
+	            // Format
+	            if (salt) {
+	                wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
+	            } else {
+	                wordArray = ciphertext;
+	            }
+
+	            return wordArray.toString(Base64);
+	        },
+
+	        /**
+	         * Converts an OpenSSL-compatible string to a cipher params object.
+	         *
+	         * @param {string} openSSLStr The OpenSSL-compatible string.
+	         *
+	         * @return {CipherParams} The cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);
+	         */
+	        parse: function (openSSLStr) {
+	            var salt;
+
+	            // Parse base64
+	            var ciphertext = Base64.parse(openSSLStr);
+
+	            // Shortcut
+	            var ciphertextWords = ciphertext.words;
+
+	            // Test for salt
+	            if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) {
+	                // Extract salt
+	                salt = WordArray.create(ciphertextWords.slice(2, 4));
+
+	                // Remove salt from ciphertext
+	                ciphertextWords.splice(0, 4);
+	                ciphertext.sigBytes -= 16;
+	            }
+
+	            return CipherParams.create({ ciphertext: ciphertext, salt: salt });
+	        }
+	    };
+
+	    /**
+	     * A cipher wrapper that returns ciphertext as a serializable cipher params object.
+	     */
+	    var SerializableCipher = C_lib.SerializableCipher = Base.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL
+	         */
+	        cfg: Base.extend({
+	            format: OpenSSLFormatter
+	        }),
+
+	        /**
+	         * Encrypts a message.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {WordArray|string} message The message to encrypt.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {CipherParams} A cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         */
+	        encrypt: function (cipher, message, key, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Encrypt
+	            var encryptor = cipher.createEncryptor(key, cfg);
+	            var ciphertext = encryptor.finalize(message);
+
+	            // Shortcut
+	            var cipherCfg = encryptor.cfg;
+
+	            // Create and return serializable cipher params
+	            return CipherParams.create({
+	                ciphertext: ciphertext,
+	                key: key,
+	                iv: cipherCfg.iv,
+	                algorithm: cipher,
+	                mode: cipherCfg.mode,
+	                padding: cipherCfg.padding,
+	                blockSize: cipher.blockSize,
+	                formatter: cfg.format
+	            });
+	        },
+
+	        /**
+	         * Decrypts serialized ciphertext.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
+	         * @param {WordArray} key The key.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {WordArray} The plaintext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         *     var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL });
+	         */
+	        decrypt: function (cipher, ciphertext, key, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Convert string to CipherParams
+	            ciphertext = this._parse(ciphertext, cfg.format);
+
+	            // Decrypt
+	            var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);
+
+	            return plaintext;
+	        },
+
+	        /**
+	         * Converts serialized ciphertext to CipherParams,
+	         * else assumed CipherParams already and returns ciphertext unchanged.
+	         *
+	         * @param {CipherParams|string} ciphertext The ciphertext.
+	         * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.
+	         *
+	         * @return {CipherParams} The unserialized ciphertext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
+	         */
+	        _parse: function (ciphertext, format) {
+	            if (typeof ciphertext == 'string') {
+	                return format.parse(ciphertext, this);
+	            } else {
+	                return ciphertext;
+	            }
+	        }
+	    });
+
+	    /**
+	     * Key derivation function namespace.
+	     */
+	    var C_kdf = C.kdf = {};
+
+	    /**
+	     * OpenSSL key derivation function.
+	     */
+	    var OpenSSLKdf = C_kdf.OpenSSL = {
+	        /**
+	         * Derives a key and IV from a password.
+	         *
+	         * @param {string} password The password to derive from.
+	         * @param {number} keySize The size in words of the key to generate.
+	         * @param {number} ivSize The size in words of the IV to generate.
+	         * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
+	         *
+	         * @return {CipherParams} A cipher params object with the key, IV, and salt.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
+	         *     var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
+	         */
+	        execute: function (password, keySize, ivSize, salt) {
+	            // Generate random salt
+	            if (!salt) {
+	                salt = WordArray.random(64/8);
+	            }
+
+	            // Derive key and IV
+	            var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
+
+	            // Separate key and IV
+	            var iv = WordArray.create(key.words.slice(keySize), ivSize * 4);
+	            key.sigBytes = keySize * 4;
+
+	            // Return params
+	            return CipherParams.create({ key: key, iv: iv, salt: salt });
+	        }
+	    };
+
+	    /**
+	     * A serializable cipher wrapper that derives the key from a password,
+	     * and returns ciphertext as a serializable cipher params object.
+	     */
+	    var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL
+	         */
+	        cfg: SerializableCipher.cfg.extend({
+	            kdf: OpenSSLKdf
+	        }),
+
+	        /**
+	         * Encrypts a message using a password.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {WordArray|string} message The message to encrypt.
+	         * @param {string} password The password.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {CipherParams} A cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password');
+	         *     var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });
+	         */
+	        encrypt: function (cipher, message, password, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Derive key and other params
+	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize);
+
+	            // Add IV to config
+	            cfg.iv = derivedParams.iv;
+
+	            // Encrypt
+	            var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg);
+
+	            // Mix in derived params
+	            ciphertext.mixIn(derivedParams);
+
+	            return ciphertext;
+	        },
+
+	        /**
+	         * Decrypts serialized ciphertext using a password.
+	         *
+	         * @param {Cipher} cipher The cipher algorithm to use.
+	         * @param {CipherParams|string} ciphertext The ciphertext to decrypt.
+	         * @param {string} password The password.
+	         * @param {Object} cfg (Optional) The configuration options to use for this operation.
+	         *
+	         * @return {WordArray} The plaintext.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL });
+	         *     var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL });
+	         */
+	        decrypt: function (cipher, ciphertext, password, cfg) {
+	            // Apply config defaults
+	            cfg = this.cfg.extend(cfg);
+
+	            // Convert string to CipherParams
+	            ciphertext = this._parse(ciphertext, cfg.format);
+
+	            // Derive key and other params
+	            var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt);
+
+	            // Add IV to config
+	            cfg.iv = derivedParams.iv;
+
+	            // Decrypt
+	            var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg);
+
+	            return plaintext;
+	        }
+	    });
+	}());
+
+
+	/**
+	 * Cipher Feedback block mode.
+	 */
+	CryptoJS.mode.CFB = (function () {
+	    var CFB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    CFB.Encryptor = CFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher;
+	            var blockSize = cipher.blockSize;
+
+	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);
+
+	            // Remember this block to use with next block
+	            this._prevBlock = words.slice(offset, offset + blockSize);
+	        }
+	    });
+
+	    CFB.Decryptor = CFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher;
+	            var blockSize = cipher.blockSize;
+
+	            // Remember this block to use with next block
+	            var thisBlock = words.slice(offset, offset + blockSize);
+
+	            generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher);
+
+	            // This block becomes the previous block
+	            this._prevBlock = thisBlock;
+	        }
+	    });
+
+	    function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) {
+	        var keystream;
+
+	        // Shortcut
+	        var iv = this._iv;
+
+	        // Generate keystream
+	        if (iv) {
+	            keystream = iv.slice(0);
+
+	            // Remove IV for subsequent blocks
+	            this._iv = undefined;
+	        } else {
+	            keystream = this._prevBlock;
+	        }
+	        cipher.encryptBlock(keystream, 0);
+
+	        // Encrypt
+	        for (var i = 0; i < blockSize; i++) {
+	            words[offset + i] ^= keystream[i];
+	        }
+	    }
+
+	    return CFB;
+	}());
+
+
+	/**
+	 * Electronic Codebook block mode.
+	 */
+	CryptoJS.mode.ECB = (function () {
+	    var ECB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    ECB.Encryptor = ECB.extend({
+	        processBlock: function (words, offset) {
+	            this._cipher.encryptBlock(words, offset);
+	        }
+	    });
+
+	    ECB.Decryptor = ECB.extend({
+	        processBlock: function (words, offset) {
+	            this._cipher.decryptBlock(words, offset);
+	        }
+	    });
+
+	    return ECB;
+	}());
+
+
+	/**
+	 * ANSI X.923 padding strategy.
+	 */
+	CryptoJS.pad.AnsiX923 = {
+	    pad: function (data, blockSize) {
+	        // Shortcuts
+	        var dataSigBytes = data.sigBytes;
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Count padding bytes
+	        var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes;
+
+	        // Compute last byte position
+	        var lastBytePos = dataSigBytes + nPaddingBytes - 1;
+
+	        // Pad
+	        data.clamp();
+	        data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8);
+	        data.sigBytes += nPaddingBytes;
+	    },
+
+	    unpad: function (data) {
+	        // Get number of padding bytes from last byte
+	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	        // Remove padding
+	        data.sigBytes -= nPaddingBytes;
+	    }
+	};
+
+
+	/**
+	 * ISO 10126 padding strategy.
+	 */
+	CryptoJS.pad.Iso10126 = {
+	    pad: function (data, blockSize) {
+	        // Shortcut
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Count padding bytes
+	        var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
+
+	        // Pad
+	        data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)).
+	             concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1));
+	    },
+
+	    unpad: function (data) {
+	        // Get number of padding bytes from last byte
+	        var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
+
+	        // Remove padding
+	        data.sigBytes -= nPaddingBytes;
+	    }
+	};
+
+
+	/**
+	 * ISO/IEC 9797-1 Padding Method 2.
+	 */
+	CryptoJS.pad.Iso97971 = {
+	    pad: function (data, blockSize) {
+	        // Add 0x80 byte
+	        data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1));
+
+	        // Zero pad the rest
+	        CryptoJS.pad.ZeroPadding.pad(data, blockSize);
+	    },
+
+	    unpad: function (data) {
+	        // Remove zero padding
+	        CryptoJS.pad.ZeroPadding.unpad(data);
+
+	        // Remove one more byte -- the 0x80 byte
+	        data.sigBytes--;
+	    }
+	};
+
+
+	/**
+	 * Output Feedback block mode.
+	 */
+	CryptoJS.mode.OFB = (function () {
+	    var OFB = CryptoJS.lib.BlockCipherMode.extend();
+
+	    var Encryptor = OFB.Encryptor = OFB.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var keystream = this._keystream;
+
+	            // Generate keystream
+	            if (iv) {
+	                keystream = this._keystream = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    OFB.Decryptor = Encryptor;
+
+	    return OFB;
+	}());
+
+
+	/**
+	 * A noop padding strategy.
+	 */
+	CryptoJS.pad.NoPadding = {
+	    pad: function () {
+	    },
+
+	    unpad: function () {
+	    }
+	};
+
+
+	(function (undefined) {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var CipherParams = C_lib.CipherParams;
+	    var C_enc = C.enc;
+	    var Hex = C_enc.Hex;
+	    var C_format = C.format;
+
+	    var HexFormatter = C_format.Hex = {
+	        /**
+	         * Converts the ciphertext of a cipher params object to a hexadecimally encoded string.
+	         *
+	         * @param {CipherParams} cipherParams The cipher params object.
+	         *
+	         * @return {string} The hexadecimally encoded string.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var hexString = CryptoJS.format.Hex.stringify(cipherParams);
+	         */
+	        stringify: function (cipherParams) {
+	            return cipherParams.ciphertext.toString(Hex);
+	        },
+
+	        /**
+	         * Converts a hexadecimally encoded ciphertext string to a cipher params object.
+	         *
+	         * @param {string} input The hexadecimally encoded string.
+	         *
+	         * @return {CipherParams} The cipher params object.
+	         *
+	         * @static
+	         *
+	         * @example
+	         *
+	         *     var cipherParams = CryptoJS.format.Hex.parse(hexString);
+	         */
+	        parse: function (input) {
+	            var ciphertext = Hex.parse(input);
+	            return CipherParams.create({ ciphertext: ciphertext });
+	        }
+	    };
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var BlockCipher = C_lib.BlockCipher;
+	    var C_algo = C.algo;
+
+	    // Lookup tables
+	    var SBOX = [];
+	    var INV_SBOX = [];
+	    var SUB_MIX_0 = [];
+	    var SUB_MIX_1 = [];
+	    var SUB_MIX_2 = [];
+	    var SUB_MIX_3 = [];
+	    var INV_SUB_MIX_0 = [];
+	    var INV_SUB_MIX_1 = [];
+	    var INV_SUB_MIX_2 = [];
+	    var INV_SUB_MIX_3 = [];
+
+	    // Compute lookup tables
+	    (function () {
+	        // Compute double table
+	        var d = [];
+	        for (var i = 0; i < 256; i++) {
+	            if (i < 128) {
+	                d[i] = i << 1;
+	            } else {
+	                d[i] = (i << 1) ^ 0x11b;
+	            }
+	        }
+
+	        // Walk GF(2^8)
+	        var x = 0;
+	        var xi = 0;
+	        for (var i = 0; i < 256; i++) {
+	            // Compute sbox
+	            var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4);
+	            sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63;
+	            SBOX[x] = sx;
+	            INV_SBOX[sx] = x;
+
+	            // Compute multiplication
+	            var x2 = d[x];
+	            var x4 = d[x2];
+	            var x8 = d[x4];
+
+	            // Compute sub bytes, mix columns tables
+	            var t = (d[sx] * 0x101) ^ (sx * 0x1010100);
+	            SUB_MIX_0[x] = (t << 24) | (t >>> 8);
+	            SUB_MIX_1[x] = (t << 16) | (t >>> 16);
+	            SUB_MIX_2[x] = (t << 8)  | (t >>> 24);
+	            SUB_MIX_3[x] = t;
+
+	            // Compute inv sub bytes, inv mix columns tables
+	            var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100);
+	            INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8);
+	            INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16);
+	            INV_SUB_MIX_2[sx] = (t << 8)  | (t >>> 24);
+	            INV_SUB_MIX_3[sx] = t;
+
+	            // Compute next counter
+	            if (!x) {
+	                x = xi = 1;
+	            } else {
+	                x = x2 ^ d[d[d[x8 ^ x2]]];
+	                xi ^= d[d[xi]];
+	            }
+	        }
+	    }());
+
+	    // Precomputed Rcon lookup
+	    var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
+
+	    /**
+	     * AES block cipher algorithm.
+	     */
+	    var AES = C_algo.AES = BlockCipher.extend({
+	        _doReset: function () {
+	            var t;
+
+	            // Skip reset of nRounds has been set before and key did not change
+	            if (this._nRounds && this._keyPriorReset === this._key) {
+	                return;
+	            }
+
+	            // Shortcuts
+	            var key = this._keyPriorReset = this._key;
+	            var keyWords = key.words;
+	            var keySize = key.sigBytes / 4;
+
+	            // Compute number of rounds
+	            var nRounds = this._nRounds = keySize + 6;
+
+	            // Compute number of key schedule rows
+	            var ksRows = (nRounds + 1) * 4;
+
+	            // Compute key schedule
+	            var keySchedule = this._keySchedule = [];
+	            for (var ksRow = 0; ksRow < ksRows; ksRow++) {
+	                if (ksRow < keySize) {
+	                    keySchedule[ksRow] = keyWords[ksRow];
+	                } else {
+	                    t = keySchedule[ksRow - 1];
+
+	                    if (!(ksRow % keySize)) {
+	                        // Rot word
+	                        t = (t << 8) | (t >>> 24);
+
+	                        // Sub word
+	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
+
+	                        // Mix Rcon
+	                        t ^= RCON[(ksRow / keySize) | 0] << 24;
+	                    } else if (keySize > 6 && ksRow % keySize == 4) {
+	                        // Sub word
+	                        t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
+	                    }
+
+	                    keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t;
+	                }
+	            }
+
+	            // Compute inv key schedule
+	            var invKeySchedule = this._invKeySchedule = [];
+	            for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) {
+	                var ksRow = ksRows - invKsRow;
+
+	                if (invKsRow % 4) {
+	                    var t = keySchedule[ksRow];
+	                } else {
+	                    var t = keySchedule[ksRow - 4];
+	                }
+
+	                if (invKsRow < 4 || ksRow <= 4) {
+	                    invKeySchedule[invKsRow] = t;
+	                } else {
+	                    invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^
+	                                               INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]];
+	                }
+	            }
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            // Swap 2nd and 4th rows
+	            var t = M[offset + 1];
+	            M[offset + 1] = M[offset + 3];
+	            M[offset + 3] = t;
+
+	            this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX);
+
+	            // Inv swap 2nd and 4th rows
+	            var t = M[offset + 1];
+	            M[offset + 1] = M[offset + 3];
+	            M[offset + 3] = t;
+	        },
+
+	        _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) {
+	            // Shortcut
+	            var nRounds = this._nRounds;
+
+	            // Get input, add round key
+	            var s0 = M[offset]     ^ keySchedule[0];
+	            var s1 = M[offset + 1] ^ keySchedule[1];
+	            var s2 = M[offset + 2] ^ keySchedule[2];
+	            var s3 = M[offset + 3] ^ keySchedule[3];
+
+	            // Key schedule row counter
+	            var ksRow = 4;
+
+	            // Rounds
+	            for (var round = 1; round < nRounds; round++) {
+	                // Shift rows, sub bytes, mix columns, add round key
+	                var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++];
+	                var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++];
+	                var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++];
+	                var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++];
+
+	                // Update state
+	                s0 = t0;
+	                s1 = t1;
+	                s2 = t2;
+	                s3 = t3;
+	            }
+
+	            // Shift rows, sub bytes, add round key
+	            var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++];
+	            var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++];
+	            var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++];
+	            var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++];
+
+	            // Set output
+	            M[offset]     = t0;
+	            M[offset + 1] = t1;
+	            M[offset + 2] = t2;
+	            M[offset + 3] = t3;
+	        },
+
+	        keySize: 256/32
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.AES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.AES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.AES = BlockCipher._createHelper(AES);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var WordArray = C_lib.WordArray;
+	    var BlockCipher = C_lib.BlockCipher;
+	    var C_algo = C.algo;
+
+	    // Permuted Choice 1 constants
+	    var PC1 = [
+	        57, 49, 41, 33, 25, 17, 9,  1,
+	        58, 50, 42, 34, 26, 18, 10, 2,
+	        59, 51, 43, 35, 27, 19, 11, 3,
+	        60, 52, 44, 36, 63, 55, 47, 39,
+	        31, 23, 15, 7,  62, 54, 46, 38,
+	        30, 22, 14, 6,  61, 53, 45, 37,
+	        29, 21, 13, 5,  28, 20, 12, 4
+	    ];
+
+	    // Permuted Choice 2 constants
+	    var PC2 = [
+	        14, 17, 11, 24, 1,  5,
+	        3,  28, 15, 6,  21, 10,
+	        23, 19, 12, 4,  26, 8,
+	        16, 7,  27, 20, 13, 2,
+	        41, 52, 31, 37, 47, 55,
+	        30, 40, 51, 45, 33, 48,
+	        44, 49, 39, 56, 34, 53,
+	        46, 42, 50, 36, 29, 32
+	    ];
+
+	    // Cumulative bit shift constants
+	    var BIT_SHIFTS = [1,  2,  4,  6,  8,  10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28];
+
+	    // SBOXes and round permutation constants
+	    var SBOX_P = [
+	        {
+	            0x0: 0x808200,
+	            0x10000000: 0x8000,
+	            0x20000000: 0x808002,
+	            0x30000000: 0x2,
+	            0x40000000: 0x200,
+	            0x50000000: 0x808202,
+	            0x60000000: 0x800202,
+	            0x70000000: 0x800000,
+	            0x80000000: 0x202,
+	            0x90000000: 0x800200,
+	            0xa0000000: 0x8200,
+	            0xb0000000: 0x808000,
+	            0xc0000000: 0x8002,
+	            0xd0000000: 0x800002,
+	            0xe0000000: 0x0,
+	            0xf0000000: 0x8202,
+	            0x8000000: 0x0,
+	            0x18000000: 0x808202,
+	            0x28000000: 0x8202,
+	            0x38000000: 0x8000,
+	            0x48000000: 0x808200,
+	            0x58000000: 0x200,
+	            0x68000000: 0x808002,
+	            0x78000000: 0x2,
+	            0x88000000: 0x800200,
+	            0x98000000: 0x8200,
+	            0xa8000000: 0x808000,
+	            0xb8000000: 0x800202,
+	            0xc8000000: 0x800002,
+	            0xd8000000: 0x8002,
+	            0xe8000000: 0x202,
+	            0xf8000000: 0x800000,
+	            0x1: 0x8000,
+	            0x10000001: 0x2,
+	            0x20000001: 0x808200,
+	            0x30000001: 0x800000,
+	            0x40000001: 0x808002,
+	            0x50000001: 0x8200,
+	            0x60000001: 0x200,
+	            0x70000001: 0x800202,
+	            0x80000001: 0x808202,
+	            0x90000001: 0x808000,
+	            0xa0000001: 0x800002,
+	            0xb0000001: 0x8202,
+	            0xc0000001: 0x202,
+	            0xd0000001: 0x800200,
+	            0xe0000001: 0x8002,
+	            0xf0000001: 0x0,
+	            0x8000001: 0x808202,
+	            0x18000001: 0x808000,
+	            0x28000001: 0x800000,
+	            0x38000001: 0x200,
+	            0x48000001: 0x8000,
+	            0x58000001: 0x800002,
+	            0x68000001: 0x2,
+	            0x78000001: 0x8202,
+	            0x88000001: 0x8002,
+	            0x98000001: 0x800202,
+	            0xa8000001: 0x202,
+	            0xb8000001: 0x808200,
+	            0xc8000001: 0x800200,
+	            0xd8000001: 0x0,
+	            0xe8000001: 0x8200,
+	            0xf8000001: 0x808002
+	        },
+	        {
+	            0x0: 0x40084010,
+	            0x1000000: 0x4000,
+	            0x2000000: 0x80000,
+	            0x3000000: 0x40080010,
+	            0x4000000: 0x40000010,
+	            0x5000000: 0x40084000,
+	            0x6000000: 0x40004000,
+	            0x7000000: 0x10,
+	            0x8000000: 0x84000,
+	            0x9000000: 0x40004010,
+	            0xa000000: 0x40000000,
+	            0xb000000: 0x84010,
+	            0xc000000: 0x80010,
+	            0xd000000: 0x0,
+	            0xe000000: 0x4010,
+	            0xf000000: 0x40080000,
+	            0x800000: 0x40004000,
+	            0x1800000: 0x84010,
+	            0x2800000: 0x10,
+	            0x3800000: 0x40004010,
+	            0x4800000: 0x40084010,
+	            0x5800000: 0x40000000,
+	            0x6800000: 0x80000,
+	            0x7800000: 0x40080010,
+	            0x8800000: 0x80010,
+	            0x9800000: 0x0,
+	            0xa800000: 0x4000,
+	            0xb800000: 0x40080000,
+	            0xc800000: 0x40000010,
+	            0xd800000: 0x84000,
+	            0xe800000: 0x40084000,
+	            0xf800000: 0x4010,
+	            0x10000000: 0x0,
+	            0x11000000: 0x40080010,
+	            0x12000000: 0x40004010,
+	            0x13000000: 0x40084000,
+	            0x14000000: 0x40080000,
+	            0x15000000: 0x10,
+	            0x16000000: 0x84010,
+	            0x17000000: 0x4000,
+	            0x18000000: 0x4010,
+	            0x19000000: 0x80000,
+	            0x1a000000: 0x80010,
+	            0x1b000000: 0x40000010,
+	            0x1c000000: 0x84000,
+	            0x1d000000: 0x40004000,
+	            0x1e000000: 0x40000000,
+	            0x1f000000: 0x40084010,
+	            0x10800000: 0x84010,
+	            0x11800000: 0x80000,
+	            0x12800000: 0x40080000,
+	            0x13800000: 0x4000,
+	            0x14800000: 0x40004000,
+	            0x15800000: 0x40084010,
+	            0x16800000: 0x10,
+	            0x17800000: 0x40000000,
+	            0x18800000: 0x40084000,
+	            0x19800000: 0x40000010,
+	            0x1a800000: 0x40004010,
+	            0x1b800000: 0x80010,
+	            0x1c800000: 0x0,
+	            0x1d800000: 0x4010,
+	            0x1e800000: 0x40080010,
+	            0x1f800000: 0x84000
+	        },
+	        {
+	            0x0: 0x104,
+	            0x100000: 0x0,
+	            0x200000: 0x4000100,
+	            0x300000: 0x10104,
+	            0x400000: 0x10004,
+	            0x500000: 0x4000004,
+	            0x600000: 0x4010104,
+	            0x700000: 0x4010000,
+	            0x800000: 0x4000000,
+	            0x900000: 0x4010100,
+	            0xa00000: 0x10100,
+	            0xb00000: 0x4010004,
+	            0xc00000: 0x4000104,
+	            0xd00000: 0x10000,
+	            0xe00000: 0x4,
+	            0xf00000: 0x100,
+	            0x80000: 0x4010100,
+	            0x180000: 0x4010004,
+	            0x280000: 0x0,
+	            0x380000: 0x4000100,
+	            0x480000: 0x4000004,
+	            0x580000: 0x10000,
+	            0x680000: 0x10004,
+	            0x780000: 0x104,
+	            0x880000: 0x4,
+	            0x980000: 0x100,
+	            0xa80000: 0x4010000,
+	            0xb80000: 0x10104,
+	            0xc80000: 0x10100,
+	            0xd80000: 0x4000104,
+	            0xe80000: 0x4010104,
+	            0xf80000: 0x4000000,
+	            0x1000000: 0x4010100,
+	            0x1100000: 0x10004,
+	            0x1200000: 0x10000,
+	            0x1300000: 0x4000100,
+	            0x1400000: 0x100,
+	            0x1500000: 0x4010104,
+	            0x1600000: 0x4000004,
+	            0x1700000: 0x0,
+	            0x1800000: 0x4000104,
+	            0x1900000: 0x4000000,
+	            0x1a00000: 0x4,
+	            0x1b00000: 0x10100,
+	            0x1c00000: 0x4010000,
+	            0x1d00000: 0x104,
+	            0x1e00000: 0x10104,
+	            0x1f00000: 0x4010004,
+	            0x1080000: 0x4000000,
+	            0x1180000: 0x104,
+	            0x1280000: 0x4010100,
+	            0x1380000: 0x0,
+	            0x1480000: 0x10004,
+	            0x1580000: 0x4000100,
+	            0x1680000: 0x100,
+	            0x1780000: 0x4010004,
+	            0x1880000: 0x10000,
+	            0x1980000: 0x4010104,
+	            0x1a80000: 0x10104,
+	            0x1b80000: 0x4000004,
+	            0x1c80000: 0x4000104,
+	            0x1d80000: 0x4010000,
+	            0x1e80000: 0x4,
+	            0x1f80000: 0x10100
+	        },
+	        {
+	            0x0: 0x80401000,
+	            0x10000: 0x80001040,
+	            0x20000: 0x401040,
+	            0x30000: 0x80400000,
+	            0x40000: 0x0,
+	            0x50000: 0x401000,
+	            0x60000: 0x80000040,
+	            0x70000: 0x400040,
+	            0x80000: 0x80000000,
+	            0x90000: 0x400000,
+	            0xa0000: 0x40,
+	            0xb0000: 0x80001000,
+	            0xc0000: 0x80400040,
+	            0xd0000: 0x1040,
+	            0xe0000: 0x1000,
+	            0xf0000: 0x80401040,
+	            0x8000: 0x80001040,
+	            0x18000: 0x40,
+	            0x28000: 0x80400040,
+	            0x38000: 0x80001000,
+	            0x48000: 0x401000,
+	            0x58000: 0x80401040,
+	            0x68000: 0x0,
+	            0x78000: 0x80400000,
+	            0x88000: 0x1000,
+	            0x98000: 0x80401000,
+	            0xa8000: 0x400000,
+	            0xb8000: 0x1040,
+	            0xc8000: 0x80000000,
+	            0xd8000: 0x400040,
+	            0xe8000: 0x401040,
+	            0xf8000: 0x80000040,
+	            0x100000: 0x400040,
+	            0x110000: 0x401000,
+	            0x120000: 0x80000040,
+	            0x130000: 0x0,
+	            0x140000: 0x1040,
+	            0x150000: 0x80400040,
+	            0x160000: 0x80401000,
+	            0x170000: 0x80001040,
+	            0x180000: 0x80401040,
+	            0x190000: 0x80000000,
+	            0x1a0000: 0x80400000,
+	            0x1b0000: 0x401040,
+	            0x1c0000: 0x80001000,
+	            0x1d0000: 0x400000,
+	            0x1e0000: 0x40,
+	            0x1f0000: 0x1000,
+	            0x108000: 0x80400000,
+	            0x118000: 0x80401040,
+	            0x128000: 0x0,
+	            0x138000: 0x401000,
+	            0x148000: 0x400040,
+	            0x158000: 0x80000000,
+	            0x168000: 0x80001040,
+	            0x178000: 0x40,
+	            0x188000: 0x80000040,
+	            0x198000: 0x1000,
+	            0x1a8000: 0x80001000,
+	            0x1b8000: 0x80400040,
+	            0x1c8000: 0x1040,
+	            0x1d8000: 0x80401000,
+	            0x1e8000: 0x400000,
+	            0x1f8000: 0x401040
+	        },
+	        {
+	            0x0: 0x80,
+	            0x1000: 0x1040000,
+	            0x2000: 0x40000,
+	            0x3000: 0x20000000,
+	            0x4000: 0x20040080,
+	            0x5000: 0x1000080,
+	            0x6000: 0x21000080,
+	            0x7000: 0x40080,
+	            0x8000: 0x1000000,
+	            0x9000: 0x20040000,
+	            0xa000: 0x20000080,
+	            0xb000: 0x21040080,
+	            0xc000: 0x21040000,
+	            0xd000: 0x0,
+	            0xe000: 0x1040080,
+	            0xf000: 0x21000000,
+	            0x800: 0x1040080,
+	            0x1800: 0x21000080,
+	            0x2800: 0x80,
+	            0x3800: 0x1040000,
+	            0x4800: 0x40000,
+	            0x5800: 0x20040080,
+	            0x6800: 0x21040000,
+	            0x7800: 0x20000000,
+	            0x8800: 0x20040000,
+	            0x9800: 0x0,
+	            0xa800: 0x21040080,
+	            0xb800: 0x1000080,
+	            0xc800: 0x20000080,
+	            0xd800: 0x21000000,
+	            0xe800: 0x1000000,
+	            0xf800: 0x40080,
+	            0x10000: 0x40000,
+	            0x11000: 0x80,
+	            0x12000: 0x20000000,
+	            0x13000: 0x21000080,
+	            0x14000: 0x1000080,
+	            0x15000: 0x21040000,
+	            0x16000: 0x20040080,
+	            0x17000: 0x1000000,
+	            0x18000: 0x21040080,
+	            0x19000: 0x21000000,
+	            0x1a000: 0x1040000,
+	            0x1b000: 0x20040000,
+	            0x1c000: 0x40080,
+	            0x1d000: 0x20000080,
+	            0x1e000: 0x0,
+	            0x1f000: 0x1040080,
+	            0x10800: 0x21000080,
+	            0x11800: 0x1000000,
+	            0x12800: 0x1040000,
+	            0x13800: 0x20040080,
+	            0x14800: 0x20000000,
+	            0x15800: 0x1040080,
+	            0x16800: 0x80,
+	            0x17800: 0x21040000,
+	            0x18800: 0x40080,
+	            0x19800: 0x21040080,
+	            0x1a800: 0x0,
+	            0x1b800: 0x21000000,
+	            0x1c800: 0x1000080,
+	            0x1d800: 0x40000,
+	            0x1e800: 0x20040000,
+	            0x1f800: 0x20000080
+	        },
+	        {
+	            0x0: 0x10000008,
+	            0x100: 0x2000,
+	            0x200: 0x10200000,
+	            0x300: 0x10202008,
+	            0x400: 0x10002000,
+	            0x500: 0x200000,
+	            0x600: 0x200008,
+	            0x700: 0x10000000,
+	            0x800: 0x0,
+	            0x900: 0x10002008,
+	            0xa00: 0x202000,
+	            0xb00: 0x8,
+	            0xc00: 0x10200008,
+	            0xd00: 0x202008,
+	            0xe00: 0x2008,
+	            0xf00: 0x10202000,
+	            0x80: 0x10200000,
+	            0x180: 0x10202008,
+	            0x280: 0x8,
+	            0x380: 0x200000,
+	            0x480: 0x202008,
+	            0x580: 0x10000008,
+	            0x680: 0x10002000,
+	            0x780: 0x2008,
+	            0x880: 0x200008,
+	            0x980: 0x2000,
+	            0xa80: 0x10002008,
+	            0xb80: 0x10200008,
+	            0xc80: 0x0,
+	            0xd80: 0x10202000,
+	            0xe80: 0x202000,
+	            0xf80: 0x10000000,
+	            0x1000: 0x10002000,
+	            0x1100: 0x10200008,
+	            0x1200: 0x10202008,
+	            0x1300: 0x2008,
+	            0x1400: 0x200000,
+	            0x1500: 0x10000000,
+	            0x1600: 0x10000008,
+	            0x1700: 0x202000,
+	            0x1800: 0x202008,
+	            0x1900: 0x0,
+	            0x1a00: 0x8,
+	            0x1b00: 0x10200000,
+	            0x1c00: 0x2000,
+	            0x1d00: 0x10002008,
+	            0x1e00: 0x10202000,
+	            0x1f00: 0x200008,
+	            0x1080: 0x8,
+	            0x1180: 0x202000,
+	            0x1280: 0x200000,
+	            0x1380: 0x10000008,
+	            0x1480: 0x10002000,
+	            0x1580: 0x2008,
+	            0x1680: 0x10202008,
+	            0x1780: 0x10200000,
+	            0x1880: 0x10202000,
+	            0x1980: 0x10200008,
+	            0x1a80: 0x2000,
+	            0x1b80: 0x202008,
+	            0x1c80: 0x200008,
+	            0x1d80: 0x0,
+	            0x1e80: 0x10000000,
+	            0x1f80: 0x10002008
+	        },
+	        {
+	            0x0: 0x100000,
+	            0x10: 0x2000401,
+	            0x20: 0x400,
+	            0x30: 0x100401,
+	            0x40: 0x2100401,
+	            0x50: 0x0,
+	            0x60: 0x1,
+	            0x70: 0x2100001,
+	            0x80: 0x2000400,
+	            0x90: 0x100001,
+	            0xa0: 0x2000001,
+	            0xb0: 0x2100400,
+	            0xc0: 0x2100000,
+	            0xd0: 0x401,
+	            0xe0: 0x100400,
+	            0xf0: 0x2000000,
+	            0x8: 0x2100001,
+	            0x18: 0x0,
+	            0x28: 0x2000401,
+	            0x38: 0x2100400,
+	            0x48: 0x100000,
+	            0x58: 0x2000001,
+	            0x68: 0x2000000,
+	            0x78: 0x401,
+	            0x88: 0x100401,
+	            0x98: 0x2000400,
+	            0xa8: 0x2100000,
+	            0xb8: 0x100001,
+	            0xc8: 0x400,
+	            0xd8: 0x2100401,
+	            0xe8: 0x1,
+	            0xf8: 0x100400,
+	            0x100: 0x2000000,
+	            0x110: 0x100000,
+	            0x120: 0x2000401,
+	            0x130: 0x2100001,
+	            0x140: 0x100001,
+	            0x150: 0x2000400,
+	            0x160: 0x2100400,
+	            0x170: 0x100401,
+	            0x180: 0x401,
+	            0x190: 0x2100401,
+	            0x1a0: 0x100400,
+	            0x1b0: 0x1,
+	            0x1c0: 0x0,
+	            0x1d0: 0x2100000,
+	            0x1e0: 0x2000001,
+	            0x1f0: 0x400,
+	            0x108: 0x100400,
+	            0x118: 0x2000401,
+	            0x128: 0x2100001,
+	            0x138: 0x1,
+	            0x148: 0x2000000,
+	            0x158: 0x100000,
+	            0x168: 0x401,
+	            0x178: 0x2100400,
+	            0x188: 0x2000001,
+	            0x198: 0x2100000,
+	            0x1a8: 0x0,
+	            0x1b8: 0x2100401,
+	            0x1c8: 0x100401,
+	            0x1d8: 0x400,
+	            0x1e8: 0x2000400,
+	            0x1f8: 0x100001
+	        },
+	        {
+	            0x0: 0x8000820,
+	            0x1: 0x20000,
+	            0x2: 0x8000000,
+	            0x3: 0x20,
+	            0x4: 0x20020,
+	            0x5: 0x8020820,
+	            0x6: 0x8020800,
+	            0x7: 0x800,
+	            0x8: 0x8020000,
+	            0x9: 0x8000800,
+	            0xa: 0x20800,
+	            0xb: 0x8020020,
+	            0xc: 0x820,
+	            0xd: 0x0,
+	            0xe: 0x8000020,
+	            0xf: 0x20820,
+	            0x80000000: 0x800,
+	            0x80000001: 0x8020820,
+	            0x80000002: 0x8000820,
+	            0x80000003: 0x8000000,
+	            0x80000004: 0x8020000,
+	            0x80000005: 0x20800,
+	            0x80000006: 0x20820,
+	            0x80000007: 0x20,
+	            0x80000008: 0x8000020,
+	            0x80000009: 0x820,
+	            0x8000000a: 0x20020,
+	            0x8000000b: 0x8020800,
+	            0x8000000c: 0x0,
+	            0x8000000d: 0x8020020,
+	            0x8000000e: 0x8000800,
+	            0x8000000f: 0x20000,
+	            0x10: 0x20820,
+	            0x11: 0x8020800,
+	            0x12: 0x20,
+	            0x13: 0x800,
+	            0x14: 0x8000800,
+	            0x15: 0x8000020,
+	            0x16: 0x8020020,
+	            0x17: 0x20000,
+	            0x18: 0x0,
+	            0x19: 0x20020,
+	            0x1a: 0x8020000,
+	            0x1b: 0x8000820,
+	            0x1c: 0x8020820,
+	            0x1d: 0x20800,
+	            0x1e: 0x820,
+	            0x1f: 0x8000000,
+	            0x80000010: 0x20000,
+	            0x80000011: 0x800,
+	            0x80000012: 0x8020020,
+	            0x80000013: 0x20820,
+	            0x80000014: 0x20,
+	            0x80000015: 0x8020000,
+	            0x80000016: 0x8000000,
+	            0x80000017: 0x8000820,
+	            0x80000018: 0x8020820,
+	            0x80000019: 0x8000020,
+	            0x8000001a: 0x8000800,
+	            0x8000001b: 0x0,
+	            0x8000001c: 0x20800,
+	            0x8000001d: 0x820,
+	            0x8000001e: 0x20020,
+	            0x8000001f: 0x8020800
+	        }
+	    ];
+
+	    // Masks that select the SBOX input
+	    var SBOX_MASK = [
+	        0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000,
+	        0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f
+	    ];
+
+	    /**
+	     * DES block cipher algorithm.
+	     */
+	    var DES = C_algo.DES = BlockCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+
+	            // Select 56 bits according to PC1
+	            var keyBits = [];
+	            for (var i = 0; i < 56; i++) {
+	                var keyBitPos = PC1[i] - 1;
+	                keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1;
+	            }
+
+	            // Assemble 16 subkeys
+	            var subKeys = this._subKeys = [];
+	            for (var nSubKey = 0; nSubKey < 16; nSubKey++) {
+	                // Create subkey
+	                var subKey = subKeys[nSubKey] = [];
+
+	                // Shortcut
+	                var bitShift = BIT_SHIFTS[nSubKey];
+
+	                // Select 48 bits according to PC2
+	                for (var i = 0; i < 24; i++) {
+	                    // Select from the left 28 key bits
+	                    subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6);
+
+	                    // Select from the right 28 key bits
+	                    subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6);
+	                }
+
+	                // Since each subkey is applied to an expanded 32-bit input,
+	                // the subkey can be broken into 8 values scaled to 32-bits,
+	                // which allows the key to be used without expansion
+	                subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31);
+	                for (var i = 1; i < 7; i++) {
+	                    subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3);
+	                }
+	                subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27);
+	            }
+
+	            // Compute inverse subkeys
+	            var invSubKeys = this._invSubKeys = [];
+	            for (var i = 0; i < 16; i++) {
+	                invSubKeys[i] = subKeys[15 - i];
+	            }
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._subKeys);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            this._doCryptBlock(M, offset, this._invSubKeys);
+	        },
+
+	        _doCryptBlock: function (M, offset, subKeys) {
+	            // Get input
+	            this._lBlock = M[offset];
+	            this._rBlock = M[offset + 1];
+
+	            // Initial permutation
+	            exchangeLR.call(this, 4,  0x0f0f0f0f);
+	            exchangeLR.call(this, 16, 0x0000ffff);
+	            exchangeRL.call(this, 2,  0x33333333);
+	            exchangeRL.call(this, 8,  0x00ff00ff);
+	            exchangeLR.call(this, 1,  0x55555555);
+
+	            // Rounds
+	            for (var round = 0; round < 16; round++) {
+	                // Shortcuts
+	                var subKey = subKeys[round];
+	                var lBlock = this._lBlock;
+	                var rBlock = this._rBlock;
+
+	                // Feistel function
+	                var f = 0;
+	                for (var i = 0; i < 8; i++) {
+	                    f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0];
+	                }
+	                this._lBlock = rBlock;
+	                this._rBlock = lBlock ^ f;
+	            }
+
+	            // Undo swap from last round
+	            var t = this._lBlock;
+	            this._lBlock = this._rBlock;
+	            this._rBlock = t;
+
+	            // Final permutation
+	            exchangeLR.call(this, 1,  0x55555555);
+	            exchangeRL.call(this, 8,  0x00ff00ff);
+	            exchangeRL.call(this, 2,  0x33333333);
+	            exchangeLR.call(this, 16, 0x0000ffff);
+	            exchangeLR.call(this, 4,  0x0f0f0f0f);
+
+	            // Set output
+	            M[offset] = this._lBlock;
+	            M[offset + 1] = this._rBlock;
+	        },
+
+	        keySize: 64/32,
+
+	        ivSize: 64/32,
+
+	        blockSize: 64/32
+	    });
+
+	    // Swap bits across the left and right words
+	    function exchangeLR(offset, mask) {
+	        var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask;
+	        this._rBlock ^= t;
+	        this._lBlock ^= t << offset;
+	    }
+
+	    function exchangeRL(offset, mask) {
+	        var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask;
+	        this._lBlock ^= t;
+	        this._rBlock ^= t << offset;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.DES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.DES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.DES = BlockCipher._createHelper(DES);
+
+	    /**
+	     * Triple-DES block cipher algorithm.
+	     */
+	    var TripleDES = C_algo.TripleDES = BlockCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+	            // Make sure the key length is valid (64, 128 or >= 192 bit)
+	            if (keyWords.length !== 2 && keyWords.length !== 4 && keyWords.length < 6) {
+	                throw new Error('Invalid key length - 3DES requires the key length to be 64, 128, 192 or >192.');
+	            }
+
+	            // Extend the key according to the keying options defined in 3DES standard
+	            var key1 = keyWords.slice(0, 2);
+	            var key2 = keyWords.length < 4 ? keyWords.slice(0, 2) : keyWords.slice(2, 4);
+	            var key3 = keyWords.length < 6 ? keyWords.slice(0, 2) : keyWords.slice(4, 6);
+
+	            // Create DES instances
+	            this._des1 = DES.createEncryptor(WordArray.create(key1));
+	            this._des2 = DES.createEncryptor(WordArray.create(key2));
+	            this._des3 = DES.createEncryptor(WordArray.create(key3));
+	        },
+
+	        encryptBlock: function (M, offset) {
+	            this._des1.encryptBlock(M, offset);
+	            this._des2.decryptBlock(M, offset);
+	            this._des3.encryptBlock(M, offset);
+	        },
+
+	        decryptBlock: function (M, offset) {
+	            this._des3.decryptBlock(M, offset);
+	            this._des2.encryptBlock(M, offset);
+	            this._des1.decryptBlock(M, offset);
+	        },
+
+	        keySize: 192/32,
+
+	        ivSize: 64/32,
+
+	        blockSize: 64/32
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg);
+	     */
+	    C.TripleDES = BlockCipher._createHelper(TripleDES);
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    /**
+	     * RC4 stream cipher algorithm.
+	     */
+	    var RC4 = C_algo.RC4 = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var key = this._key;
+	            var keyWords = key.words;
+	            var keySigBytes = key.sigBytes;
+
+	            // Init sbox
+	            var S = this._S = [];
+	            for (var i = 0; i < 256; i++) {
+	                S[i] = i;
+	            }
+
+	            // Key setup
+	            for (var i = 0, j = 0; i < 256; i++) {
+	                var keyByteIndex = i % keySigBytes;
+	                var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff;
+
+	                j = (j + S[i] + keyByte) % 256;
+
+	                // Swap
+	                var t = S[i];
+	                S[i] = S[j];
+	                S[j] = t;
+	            }
+
+	            // Counters
+	            this._i = this._j = 0;
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            M[offset] ^= generateKeystreamWord.call(this);
+	        },
+
+	        keySize: 256/32,
+
+	        ivSize: 0
+	    });
+
+	    function generateKeystreamWord() {
+	        // Shortcuts
+	        var S = this._S;
+	        var i = this._i;
+	        var j = this._j;
+
+	        // Generate keystream word
+	        var keystreamWord = 0;
+	        for (var n = 0; n < 4; n++) {
+	            i = (i + 1) % 256;
+	            j = (j + S[i]) % 256;
+
+	            // Swap
+	            var t = S[i];
+	            S[i] = S[j];
+	            S[j] = t;
+
+	            keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8);
+	        }
+
+	        // Update counters
+	        this._i = i;
+	        this._j = j;
+
+	        return keystreamWord;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RC4.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RC4 = StreamCipher._createHelper(RC4);
+
+	    /**
+	     * Modified RC4 stream cipher algorithm.
+	     */
+	    var RC4Drop = C_algo.RC4Drop = RC4.extend({
+	        /**
+	         * Configuration options.
+	         *
+	         * @property {number} drop The number of keystream words to drop. Default 192
+	         */
+	        cfg: RC4.cfg.extend({
+	            drop: 192
+	        }),
+
+	        _doReset: function () {
+	            RC4._doReset.call(this);
+
+	            // Drop
+	            for (var i = this.cfg.drop; i > 0; i--) {
+	                generateKeystreamWord.call(this);
+	            }
+	        }
+	    });
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RC4Drop = StreamCipher._createHelper(RC4Drop);
+	}());
+
+
+	/** @preserve
+	 * Counter block mode compatible with  Dr Brian Gladman fileenc.c
+	 * derived from CryptoJS.mode.CTR
+	 * Jan Hruby jhruby.web@gmail.com
+	 */
+	CryptoJS.mode.CTRGladman = (function () {
+	    var CTRGladman = CryptoJS.lib.BlockCipherMode.extend();
+
+		function incWord(word)
+		{
+			if (((word >> 24) & 0xff) === 0xff) { //overflow
+			var b1 = (word >> 16)&0xff;
+			var b2 = (word >> 8)&0xff;
+			var b3 = word & 0xff;
+
+			if (b1 === 0xff) // overflow b1
+			{
+			b1 = 0;
+			if (b2 === 0xff)
+			{
+				b2 = 0;
+				if (b3 === 0xff)
+				{
+					b3 = 0;
+				}
+				else
+				{
+					++b3;
+				}
+			}
+			else
+			{
+				++b2;
+			}
+			}
+			else
+			{
+			++b1;
+			}
+
+			word = 0;
+			word += (b1 << 16);
+			word += (b2 << 8);
+			word += b3;
+			}
+			else
+			{
+			word += (0x01 << 24);
+			}
+			return word;
+		}
+
+		function incCounter(counter)
+		{
+			if ((counter[0] = incWord(counter[0])) === 0)
+			{
+				// encr_data in fileenc.c from  Dr Brian Gladman's counts only with DWORD j < 8
+				counter[1] = incWord(counter[1]);
+			}
+			return counter;
+		}
+
+	    var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var counter = this._counter;
+
+	            // Generate keystream
+	            if (iv) {
+	                counter = this._counter = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+
+				incCounter(counter);
+
+				var keystream = counter.slice(0);
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    CTRGladman.Decryptor = Encryptor;
+
+	    return CTRGladman;
+	}());
+
+
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    // Reusable objects
+	    var S  = [];
+	    var C_ = [];
+	    var G  = [];
+
+	    /**
+	     * Rabbit stream cipher algorithm
+	     */
+	    var Rabbit = C_algo.Rabbit = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var K = this._key.words;
+	            var iv = this.cfg.iv;
+
+	            // Swap endian
+	            for (var i = 0; i < 4; i++) {
+	                K[i] = (((K[i] << 8)  | (K[i] >>> 24)) & 0x00ff00ff) |
+	                       (((K[i] << 24) | (K[i] >>> 8))  & 0xff00ff00);
+	            }
+
+	            // Generate initial state values
+	            var X = this._X = [
+	                K[0], (K[3] << 16) | (K[2] >>> 16),
+	                K[1], (K[0] << 16) | (K[3] >>> 16),
+	                K[2], (K[1] << 16) | (K[0] >>> 16),
+	                K[3], (K[2] << 16) | (K[1] >>> 16)
+	            ];
+
+	            // Generate initial counter values
+	            var C = this._C = [
+	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
+	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
+	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
+	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
+	            ];
+
+	            // Carry bit
+	            this._b = 0;
+
+	            // Iterate the system four times
+	            for (var i = 0; i < 4; i++) {
+	                nextState.call(this);
+	            }
+
+	            // Modify the counters
+	            for (var i = 0; i < 8; i++) {
+	                C[i] ^= X[(i + 4) & 7];
+	            }
+
+	            // IV setup
+	            if (iv) {
+	                // Shortcuts
+	                var IV = iv.words;
+	                var IV_0 = IV[0];
+	                var IV_1 = IV[1];
+
+	                // Generate four subvectors
+	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
+	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
+	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
+	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);
+
+	                // Modify counter values
+	                C[0] ^= i0;
+	                C[1] ^= i1;
+	                C[2] ^= i2;
+	                C[3] ^= i3;
+	                C[4] ^= i0;
+	                C[5] ^= i1;
+	                C[6] ^= i2;
+	                C[7] ^= i3;
+
+	                // Iterate the system four times
+	                for (var i = 0; i < 4; i++) {
+	                    nextState.call(this);
+	                }
+	            }
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var X = this._X;
+
+	            // Iterate the system
+	            nextState.call(this);
+
+	            // Generate four keystream words
+	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
+	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
+	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
+	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);
+
+	            for (var i = 0; i < 4; i++) {
+	                // Swap endian
+	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
+	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);
+
+	                // Encrypt
+	                M[offset + i] ^= S[i];
+	            }
+	        },
+
+	        blockSize: 128/32,
+
+	        ivSize: 64/32
+	    });
+
+	    function nextState() {
+	        // Shortcuts
+	        var X = this._X;
+	        var C = this._C;
+
+	        // Save old counter values
+	        for (var i = 0; i < 8; i++) {
+	            C_[i] = C[i];
+	        }
+
+	        // Calculate new counter values
+	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
+	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
+	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
+	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
+	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
+	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
+	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
+	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
+	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;
+
+	        // Calculate the g-values
+	        for (var i = 0; i < 8; i++) {
+	            var gx = X[i] + C[i];
+
+	            // Construct high and low argument for squaring
+	            var ga = gx & 0xffff;
+	            var gb = gx >>> 16;
+
+	            // Calculate high and low result of squaring
+	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
+	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);
+
+	            // High XOR low
+	            G[i] = gh ^ gl;
+	        }
+
+	        // Calculate new state values
+	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
+	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
+	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
+	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
+	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
+	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
+	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
+	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg);
+	     */
+	    C.Rabbit = StreamCipher._createHelper(Rabbit);
+	}());
+
+
+	/**
+	 * Counter block mode.
+	 */
+	CryptoJS.mode.CTR = (function () {
+	    var CTR = CryptoJS.lib.BlockCipherMode.extend();
+
+	    var Encryptor = CTR.Encryptor = CTR.extend({
+	        processBlock: function (words, offset) {
+	            // Shortcuts
+	            var cipher = this._cipher
+	            var blockSize = cipher.blockSize;
+	            var iv = this._iv;
+	            var counter = this._counter;
+
+	            // Generate keystream
+	            if (iv) {
+	                counter = this._counter = iv.slice(0);
+
+	                // Remove IV for subsequent blocks
+	                this._iv = undefined;
+	            }
+	            var keystream = counter.slice(0);
+	            cipher.encryptBlock(keystream, 0);
+
+	            // Increment counter
+	            counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0
+
+	            // Encrypt
+	            for (var i = 0; i < blockSize; i++) {
+	                words[offset + i] ^= keystream[i];
+	            }
+	        }
+	    });
+
+	    CTR.Decryptor = Encryptor;
+
+	    return CTR;
+	}());
+
+
+	(function () {
+	    // Shortcuts
+	    var C = CryptoJS;
+	    var C_lib = C.lib;
+	    var StreamCipher = C_lib.StreamCipher;
+	    var C_algo = C.algo;
+
+	    // Reusable objects
+	    var S  = [];
+	    var C_ = [];
+	    var G  = [];
+
+	    /**
+	     * Rabbit stream cipher algorithm.
+	     *
+	     * This is a legacy version that neglected to convert the key to little-endian.
+	     * This error doesn't affect the cipher's security,
+	     * but it does affect its compatibility with other implementations.
+	     */
+	    var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({
+	        _doReset: function () {
+	            // Shortcuts
+	            var K = this._key.words;
+	            var iv = this.cfg.iv;
+
+	            // Generate initial state values
+	            var X = this._X = [
+	                K[0], (K[3] << 16) | (K[2] >>> 16),
+	                K[1], (K[0] << 16) | (K[3] >>> 16),
+	                K[2], (K[1] << 16) | (K[0] >>> 16),
+	                K[3], (K[2] << 16) | (K[1] >>> 16)
+	            ];
+
+	            // Generate initial counter values
+	            var C = this._C = [
+	                (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff),
+	                (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff),
+	                (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff),
+	                (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff)
+	            ];
+
+	            // Carry bit
+	            this._b = 0;
+
+	            // Iterate the system four times
+	            for (var i = 0; i < 4; i++) {
+	                nextState.call(this);
+	            }
+
+	            // Modify the counters
+	            for (var i = 0; i < 8; i++) {
+	                C[i] ^= X[(i + 4) & 7];
+	            }
+
+	            // IV setup
+	            if (iv) {
+	                // Shortcuts
+	                var IV = iv.words;
+	                var IV_0 = IV[0];
+	                var IV_1 = IV[1];
+
+	                // Generate four subvectors
+	                var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00);
+	                var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00);
+	                var i1 = (i0 >>> 16) | (i2 & 0xffff0000);
+	                var i3 = (i2 << 16)  | (i0 & 0x0000ffff);
+
+	                // Modify counter values
+	                C[0] ^= i0;
+	                C[1] ^= i1;
+	                C[2] ^= i2;
+	                C[3] ^= i3;
+	                C[4] ^= i0;
+	                C[5] ^= i1;
+	                C[6] ^= i2;
+	                C[7] ^= i3;
+
+	                // Iterate the system four times
+	                for (var i = 0; i < 4; i++) {
+	                    nextState.call(this);
+	                }
+	            }
+	        },
+
+	        _doProcessBlock: function (M, offset) {
+	            // Shortcut
+	            var X = this._X;
+
+	            // Iterate the system
+	            nextState.call(this);
+
+	            // Generate four keystream words
+	            S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16);
+	            S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16);
+	            S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16);
+	            S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16);
+
+	            for (var i = 0; i < 4; i++) {
+	                // Swap endian
+	                S[i] = (((S[i] << 8)  | (S[i] >>> 24)) & 0x00ff00ff) |
+	                       (((S[i] << 24) | (S[i] >>> 8))  & 0xff00ff00);
+
+	                // Encrypt
+	                M[offset + i] ^= S[i];
+	            }
+	        },
+
+	        blockSize: 128/32,
+
+	        ivSize: 64/32
+	    });
+
+	    function nextState() {
+	        // Shortcuts
+	        var X = this._X;
+	        var C = this._C;
+
+	        // Save old counter values
+	        for (var i = 0; i < 8; i++) {
+	            C_[i] = C[i];
+	        }
+
+	        // Calculate new counter values
+	        C[0] = (C[0] + 0x4d34d34d + this._b) | 0;
+	        C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0;
+	        C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0;
+	        C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0;
+	        C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0;
+	        C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0;
+	        C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0;
+	        C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0;
+	        this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0;
+
+	        // Calculate the g-values
+	        for (var i = 0; i < 8; i++) {
+	            var gx = X[i] + C[i];
+
+	            // Construct high and low argument for squaring
+	            var ga = gx & 0xffff;
+	            var gb = gx >>> 16;
+
+	            // Calculate high and low result of squaring
+	            var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb;
+	            var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0);
+
+	            // High XOR low
+	            G[i] = gh ^ gl;
+	        }
+
+	        // Calculate new state values
+	        X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0;
+	        X[1] = (G[1] + ((G[0] << 8)  | (G[0] >>> 24)) + G[7]) | 0;
+	        X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0;
+	        X[3] = (G[3] + ((G[2] << 8)  | (G[2] >>> 24)) + G[1]) | 0;
+	        X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0;
+	        X[5] = (G[5] + ((G[4] << 8)  | (G[4] >>> 24)) + G[3]) | 0;
+	        X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0;
+	        X[7] = (G[7] + ((G[6] << 8)  | (G[6] >>> 24)) + G[5]) | 0;
+	    }
+
+	    /**
+	     * Shortcut functions to the cipher's object interface.
+	     *
+	     * @example
+	     *
+	     *     var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg);
+	     *     var plaintext  = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg);
+	     */
+	    C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy);
+	}());
+
+
+	/**
+	 * Zero padding strategy.
+	 */
+	CryptoJS.pad.ZeroPadding = {
+	    pad: function (data, blockSize) {
+	        // Shortcut
+	        var blockSizeBytes = blockSize * 4;
+
+	        // Pad
+	        data.clamp();
+	        data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes);
+	    },
+
+	    unpad: function (data) {
+	        // Shortcut
+	        var dataWords = data.words;
+
+	        // Unpad
+	        var i = data.sigBytes - 1;
+	        for (var i = data.sigBytes - 1; i >= 0; i--) {
+	            if (((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) {
+	                data.sigBytes = i + 1;
+	                break;
+	            }
+	        }
+	    }
+	};
+
+
+	return CryptoJS;
+
+}));
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/html5shiv.js b/ap/app/zte_webui/js/3rd/html5shiv.js
new file mode 100755
index 0000000..8783215
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/html5shiv.js
@@ -0,0 +1,322 @@
+/**
+* @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+*/
+;(function(window, document) {
+/*jshint evil:true */
+  /** version */
+  var version = '0.0.0';
+
+  /** Preset options */
+  var options = window.html5 || {};
+
+  /** Used to skip problem elements */
+  var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
+
+  /** Not all elements can be cloned in IE **/
+  var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
+
+  /** Detect whether the browser supports default html5 styles */
+  var supportsHtml5Styles;
+
+  /** Name of the expando, to work with multiple documents or to re-shiv one document */
+  var expando = '_html5shiv';
+
+  /** The id for the the documents expando */
+  var expanID = 0;
+
+  /** Cached data for each document */
+  var expandoData = {};
+
+  /** Detect whether the browser supports unknown elements */
+  var supportsUnknownElements;
+
+  (function() {
+    try {
+        var a = document.createElement('a');
+        a.innerHTML = '<xyz></xyz>';
+        //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
+        supportsHtml5Styles = ('hidden' in a);
+
+        supportsUnknownElements = a.childNodes.length == 1 || (function() {
+          // assign a false positive if unable to shiv
+          (document.createElement)('a');
+          var frag = document.createDocumentFragment();
+          return (
+            typeof frag.cloneNode == 'undefined' ||
+            typeof frag.createDocumentFragment == 'undefined' ||
+            typeof frag.createElement == 'undefined'
+          );
+        }());
+    } catch(e) {
+      // assign a false positive if detection fails => unable to shiv
+      supportsHtml5Styles = true;
+      supportsUnknownElements = true;
+    }
+
+  }());
+
+  /*--------------------------------------------------------------------------*/
+
+  /**
+   * Creates a style sheet with the given CSS text and adds it to the document.
+   * @private
+   * @param {Document} ownerDocument The document.
+   * @param {String} cssText The CSS text.
+   * @returns {StyleSheet} The style element.
+   */
+  function addStyleSheet(ownerDocument, cssText) {
+    var p = ownerDocument.createElement('p'),
+        parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
+
+    p.innerHTML = 'x<style>' + cssText + '</style>';
+    return parent.insertBefore(p.lastChild, parent.firstChild);
+  }
+
+  /**
+   * Returns the value of `html5.elements` as an array.
+   * @private
+   * @returns {Array} An array of shived element node names.
+   */
+  function getElements() {
+    var elements = html5.elements;
+    return typeof elements == 'string' ? elements.split(' ') : elements;
+  }
+
+  /**
+   * Extends the built-in list of html5 elements
+   * @memberOf html5
+   * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
+   * @param {Document} ownerDocument The context document.
+   */
+  function addElements(newElements, ownerDocument) {
+    var elements = html5.elements;
+    if(typeof elements != 'string'){
+      elements = elements.join(' ');
+    }
+    if(typeof newElements != 'string'){
+      newElements = newElements.join(' ');
+    }
+    html5.elements = elements +' '+ newElements;
+    shivDocument(ownerDocument);
+  }
+
+   /**
+   * Returns the data associated to the given document
+   * @private
+   * @param {Document} ownerDocument The document.
+   * @returns {Object} An object of data.
+   */
+  function getExpandoData(ownerDocument) {
+    var data = expandoData[ownerDocument[expando]];
+    if (!data) {
+        data = {};
+        expanID++;
+        ownerDocument[expando] = expanID;
+        expandoData[expanID] = data;
+    }
+    return data;
+  }
+
+  /**
+   * returns a shived element for the given nodeName and document
+   * @memberOf html5
+   * @param {String} nodeName name of the element
+   * @param {Document} ownerDocument The context document.
+   * @returns {Object} The shived element.
+   */
+  function createElement(nodeName, ownerDocument, data){
+    if (!ownerDocument) {
+        ownerDocument = document;
+    }
+    if(supportsUnknownElements){
+        return ownerDocument.createElement(nodeName);
+    }
+    if (!data) {
+        data = getExpandoData(ownerDocument);
+    }
+    var node;
+
+    if (data.cache[nodeName]) {
+        node = data.cache[nodeName].cloneNode();
+    } else if (saveClones.test(nodeName)) {
+        node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
+    } else {
+        node = data.createElem(nodeName);
+    }
+
+    // Avoid adding some elements to fragments in IE < 9 because
+    // * Attributes like `name` or `type` cannot be set/changed once an element
+    //   is inserted into a document/fragment
+    // * Link elements with `src` attributes that are inaccessible, as with
+    //   a 403 response, will cause the tab/window to crash
+    // * Script elements appended to fragments will execute when their `src`
+    //   or `text` property is set
+    return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
+  }
+
+  /**
+   * returns a shived DocumentFragment for the given document
+   * @memberOf html5
+   * @param {Document} ownerDocument The context document.
+   * @returns {Object} The shived DocumentFragment.
+   */
+  function createDocumentFragment(ownerDocument, data){
+    if (!ownerDocument) {
+        ownerDocument = document;
+    }
+    if(supportsUnknownElements){
+        return ownerDocument.createDocumentFragment();
+    }
+    data = data || getExpandoData(ownerDocument);
+    var clone = data.frag.cloneNode(),
+        i = 0,
+        elems = getElements(),
+        l = elems.length;
+    for(;i<l;i++){
+        clone.createElement(elems[i]);
+    }
+    return clone;
+  }
+
+  /**
+   * Shivs the `createElement` and `createDocumentFragment` methods of the document.
+   * @private
+   * @param {Document|DocumentFragment} ownerDocument The document.
+   * @param {Object} data of the document.
+   */
+  function shivMethods(ownerDocument, data) {
+    if (!data.cache) {
+        data.cache = {};
+        data.createElem = ownerDocument.createElement;
+        data.createFrag = ownerDocument.createDocumentFragment;
+        data.frag = data.createFrag();
+    }
+
+
+    ownerDocument.createElement = function(nodeName) {
+      //abort shiv
+      if (!html5.shivMethods) {
+          return data.createElem(nodeName);
+      }
+      return createElement(nodeName, ownerDocument, data);
+    };
+
+    ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
+      'var n=f.cloneNode(),c=n.createElement;' +
+      'h.shivMethods&&(' +
+        // unroll the `createElement` calls
+        getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
+          data.createElem(nodeName);
+          data.frag.createElement(nodeName);
+          return 'c("' + nodeName + '")';
+        }) +
+      ');return n}'
+    )(html5, data.frag);
+  }
+
+  /*--------------------------------------------------------------------------*/
+
+  /**
+   * Shivs the given document.
+   * @memberOf html5
+   * @param {Document} ownerDocument The document to shiv.
+   * @returns {Document} The shived document.
+   */
+  function shivDocument(ownerDocument) {
+    if (!ownerDocument) {
+        ownerDocument = document;
+    }
+    var data = getExpandoData(ownerDocument);
+
+    if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
+      data.hasCSS = !!addStyleSheet(ownerDocument,
+        // corrects block display not defined in IE6/7/8/9
+        'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
+        // adds styling not present in IE6/7/8/9
+        'mark{background:#FF0;color:#000}' +
+        // hides non-rendered elements
+        'template{display:none}'
+      );
+    }
+    if (!supportsUnknownElements) {
+      shivMethods(ownerDocument, data);
+    }
+    return ownerDocument;
+  }
+
+  /*--------------------------------------------------------------------------*/
+
+  /**
+   * The `html5` object is exposed so that more elements can be shived and
+   * existing shiving can be detected on iframes.
+   * @type Object
+   * @example
+   *
+   * // options can be changed before the script is included
+   * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
+   */
+  var html5 = {
+
+    /**
+     * An array or space separated string of node names of the elements to shiv.
+     * @memberOf html5
+     * @type Array|String
+     */
+    'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
+
+    /**
+     * current version of html5shiv
+     */
+    'version': version,
+
+    /**
+     * A flag to indicate that the HTML5 style sheet should be inserted.
+     * @memberOf html5
+     * @type Boolean
+     */
+    'shivCSS': (options.shivCSS !== false),
+
+    /**
+     * Is equal to true if a browser supports creating unknown/HTML5 elements
+     * @memberOf html5
+     * @type boolean
+     */
+    'supportsUnknownElements': supportsUnknownElements,
+
+    /**
+     * A flag to indicate that the document's `createElement` and `createDocumentFragment`
+     * methods should be overwritten.
+     * @memberOf html5
+     * @type Boolean
+     */
+    'shivMethods': (options.shivMethods !== false),
+
+    /**
+     * A string to describe the type of `html5` object ("default" or "default print").
+     * @memberOf html5
+     * @type String
+     */
+    'type': 'default',
+
+    // shivs the document according to the specified `html5` object options
+    'shivDocument': shivDocument,
+
+    //creates a shived element
+    createElement: createElement,
+
+    //creates a shived documentFragment
+    createDocumentFragment: createDocumentFragment,
+
+    //extends list of elements
+    addElements: addElements
+  };
+
+  /*--------------------------------------------------------------------------*/
+
+  // expose html5
+  window.html5 = html5;
+
+  // shiv the document
+  shivDocument(document);
+
+}(this, document));
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/ap/app/zte_webui/js/3rd/images/ui-bg_diagonals-thick_18_b81900_40x40.png
new file mode 100755
index 0000000..fb86795
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_diagonals-thick_18_b81900_40x40.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_diagonals-thick_20_666666_40x40.png b/ap/app/zte_webui/js/3rd/images/ui-bg_diagonals-thick_20_666666_40x40.png
new file mode 100755
index 0000000..bf25771
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_diagonals-thick_20_666666_40x40.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_flat_0_aaaaaa_40x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100755
index 0000000..20b81e6
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_0_aaaaaa_40x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_flat_0_eeeeee_40x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_0_eeeeee_40x100.png
new file mode 100755
index 0000000..12cf4fd
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_0_eeeeee_40x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_flat_10_000000_40x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_10_000000_40x100.png
new file mode 100755
index 0000000..11a5c2f
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_10_000000_40x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_flat_55_ffffff_40x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_55_ffffff_40x100.png
new file mode 100755
index 0000000..939196e
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_55_ffffff_40x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_flat_75_ffffff_40x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100755
index 0000000..939196e
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_flat_75_ffffff_40x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_glass_100_f6f6f6_1x400.png b/ap/app/zte_webui/js/3rd/images/ui-bg_glass_100_f6f6f6_1x400.png
new file mode 100755
index 0000000..dec5183
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_glass_100_f6f6f6_1x400.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_glass_100_fdf5ce_1x400.png b/ap/app/zte_webui/js/3rd/images/ui-bg_glass_100_fdf5ce_1x400.png
new file mode 100755
index 0000000..da5e455
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_glass_100_fdf5ce_1x400.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_glass_65_ffffff_1x400.png b/ap/app/zte_webui/js/3rd/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100755
index 0000000..ae24893
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_gloss-wave_35_f6a828_500x100.png
new file mode 100755
index 0000000..ead9907
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_gloss-wave_35_f6a828_500x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
new file mode 100755
index 0000000..f0214e3
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png
new file mode 100755
index 0000000..a7a0619
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_25_0073ea_1x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_25_0073ea_1x100.png
new file mode 100755
index 0000000..2988e5e
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_25_0073ea_1x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_50_0073ea_1x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_50_0073ea_1x100.png
new file mode 100755
index 0000000..550e7be
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_50_0073ea_1x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
new file mode 100755
index 0000000..afe0eb5
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_0073ea_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_0073ea_256x240.png
new file mode 100755
index 0000000..9b41194
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_0073ea_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_222222_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_222222_256x240.png
new file mode 100755
index 0000000..5e0adcc
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_228ef1_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_228ef1_256x240.png
new file mode 100755
index 0000000..073f261
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_228ef1_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_454545_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_454545_256x240.png
new file mode 100755
index 0000000..913a82e
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_666666_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_666666_256x240.png
new file mode 100755
index 0000000..5009158
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_666666_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_FFF_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_FFF_256x240.png
new file mode 100755
index 0000000..409f48f
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_FFF_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_ef8c08_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_ef8c08_256x240.png
new file mode 100755
index 0000000..dca2e31
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_ef8c08_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_ff0084_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_ff0084_256x240.png
new file mode 100755
index 0000000..1e6befb
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_ff0084_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_ffd27a_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_ffd27a_256x240.png
new file mode 100755
index 0000000..94a2b92
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_ffd27a_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/images/ui-icons_ffffff_256x240.png b/ap/app/zte_webui/js/3rd/images/ui-icons_ffffff_256x240.png
new file mode 100755
index 0000000..409f48f
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/images/ui-icons_ffffff_256x240.png
Binary files differ
diff --git a/ap/app/zte_webui/js/3rd/jquery.additional-methods.js b/ap/app/zte_webui/js/3rd/jquery.additional-methods.js
new file mode 100755
index 0000000..e250c79
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.additional-methods.js
@@ -0,0 +1,617 @@
+/**
+ * jQuery Validation Plugin 1.9.0
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
+ * http://docs.jquery.com/Plugins/Validation
+ *
+ * Copyright (c) 2006 - 2011 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+(function () {
+
+    function stripHtml(value) {
+        // remove html tags and space chars
+        return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ')
+            // remove numbers and punctuation
+            .replace(/[0-9.(),;:!?%#$'"_+=\/-]*/g, '');
+    }
+
+    jQuery.validator.addMethod("maxWords", function (value, element, params) {
+        return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length < params;
+    }, jQuery.validator.format("Please enter {0} words or less."));
+
+    jQuery.validator.addMethod("minWords", function (value, element, params) {
+        return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params;
+    }, jQuery.validator.format("Please enter at least {0} words."));
+
+    jQuery.validator.addMethod("rangeWords", function (value, element, params) {
+        return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params[0] && value.match(/bw+b/g).length < params[1];
+    }, jQuery.validator.format("Please enter between {0} and {1} words."));
+
+})();
+
+jQuery.validator.addMethod("letterswithbasicpunc", function (value, element) {
+    return this.optional(element) || /^[a-z-.,()'\"\s]+$/i.test(value);
+}, "Letters or punctuation only please");
+
+jQuery.validator.addMethod("alphanumeric", function (value, element) {
+    return this.optional(element) || /^\w+$/i.test(value);
+}, "Letters, numbers, spaces or underscores only please");
+
+jQuery.validator.addMethod("lettersonly", function (value, element) {
+    return this.optional(element) || /^[a-z]+$/i.test(value);
+}, "Letters only please");
+
+jQuery.validator.addMethod("nowhitespace", function (value, element) {
+    return this.optional(element) || /^\S+$/i.test(value);
+}, "No white space please");
+
+jQuery.validator.addMethod("ziprange", function (value, element) {
+    return this.optional(element) || /^90[2-5]\d\{2}-\d{4}$/.test(value);
+}, "Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx");
+
+jQuery.validator.addMethod("integer", function (value, element) {
+    return this.optional(element) || /^-?\d+$/.test(value);
+}, "A positive or negative non-decimal number please");
+
+/**
+ * Return true, if the value is a valid vehicle identification number (VIN).
+ *
+ * Works with all kind of text inputs.
+ *
+ * @example <input type="text" size="20" name="VehicleID" class="{required:true,vinUS:true}" />
+ * @desc Declares a required input element whose value must be a valid vehicle identification number.
+ *
+ * @name jQuery.validator.methods.vinUS
+ * @type Boolean
+ * @cat Plugins/Validate/Methods
+ */
+jQuery.validator.addMethod(
+    "vinUS",
+    function (v) {
+        if (v.length != 17)
+            return false;
+        var i, n, d, f, cd, cdv;
+        var LL = ["A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
+        var VL = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9];
+        var FL = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2];
+        var rs = 0;
+        for (i = 0; i < 17; i++) {
+            f = FL[i];
+            d = v.slice(i, i + 1);
+            if (i == 8) {
+                cdv = d;
+            }
+            if (!isNaN(d)) {
+                d *= f;
+            }
+            else {
+                for (n = 0; n < LL.length; n++) {
+                    if (d.toUpperCase() === LL[n]) {
+                        d = VL[n];
+                        d *= f;
+                        if (isNaN(cdv) && n == 8) {
+                            cdv = LL[n];
+                        }
+                        break;
+                    }
+                }
+            }
+            rs += d;
+        }
+        cd = rs % 11;
+        if (cd == 10) {
+            cd = "X";
+        }
+        if (cd == cdv) {
+            return true;
+        }
+        return false;
+    },
+    "The specified vehicle identification number (VIN) is invalid."
+);
+
+/**
+ * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.
+ *
+ * @example jQuery.validator.methods.date("01/01/1900")
+ * @result true
+ *
+ * @example jQuery.validator.methods.date("01/13/1990")
+ * @result false
+ *
+ * @example jQuery.validator.methods.date("01.01.1900")
+ * @result false
+ *
+ * @example <input name="pippo" class="{dateITA:true}" />
+ * @desc Declares an optional input element whose value must be a valid date.
+ *
+ * @name jQuery.validator.methods.dateITA
+ * @type Boolean
+ * @cat Plugins/Validate/Methods
+ */
+jQuery.validator.addMethod(
+    "dateITA",
+    function (value, element) {
+        var check = false;
+        var re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
+        if (re.test(value)) {
+            var adata = value.split('/');
+            var gg = parseInt(adata[0], 10);
+            var mm = parseInt(adata[1], 10);
+            var aaaa = parseInt(adata[2], 10);
+            var xdata = new Date(aaaa, mm - 1, gg);
+            if (( xdata.getFullYear() == aaaa ) && ( xdata.getMonth() == mm - 1 ) && ( xdata.getDate() == gg ))
+                check = true;
+            else
+                check = false;
+        } else
+            check = false;
+        return this.optional(element) || check;
+    },
+    "Please enter a correct date"
+);
+
+jQuery.validator.addMethod("dateNL", function (value, element) {
+        return this.optional(element) || /^\d\d?[\.\/-]\d\d?[\.\/-]\d\d\d?\d?$/.test(value);
+    }, "Vul hier een geldige datum in."
+);
+
+jQuery.validator.addMethod("time", function (value, element) {
+    return this.optional(element) || /^([01]\d|2[0-3])(:[0-5]\d){0,2}$/.test(value);
+}, "Please enter a valid time, between 00:00 and 23:59");
+jQuery.validator.addMethod("time12h", function (value, element) {
+    return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AP]M))$/i.test(value);
+}, "Please enter a valid time, between 00:00 am and 12:00 pm");
+
+/**
+ * matches US phone number format
+ *
+ * where the area code may not start with 1 and the prefix may not start with 1
+ * allows '-' or ' ' as a separator and allows parens around area code
+ * some people may want to put a '1' in front of their number
+ *
+ * 1(212)-999-2345
+ * or
+ * 212 999 2344
+ * or
+ * 212-999-0983
+ *
+ * but not
+ * 111-123-5434
+ * and not
+ * 212 123 4567
+ */
+jQuery.validator.addMethod("phoneUS", function (phone_number, element) {
+    phone_number = phone_number.replace(/\s+/g, "");
+    return this.optional(element) || phone_number.length > 9 &&
+        phone_number.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
+}, "Please specify a valid phone number");
+
+jQuery.validator.addMethod('phoneUK', function (phone_number, element) {
+    return this.optional(element) || phone_number.length > 9 &&
+        phone_number.match(/^(\(?(0|\+44)[1-9]{1}\d{1,4}?\)?\s?\d{3,4}\s?\d{3,4})$/);
+}, 'Please specify a valid phone number');
+
+jQuery.validator.addMethod('mobileUK', function (phone_number, element) {
+    return this.optional(element) || phone_number.length > 9 &&
+        phone_number.match(/^((0|\+44)7(5|6|7|8|9){1}\d{2}\s?\d{6})$/);
+}, 'Please specify a valid mobile number');
+
+// TODO check if value starts with <, otherwise don't try stripping anything
+jQuery.validator.addMethod("strippedminlength", function (value, element, param) {
+    return jQuery(value).text().length >= param;
+}, jQuery.validator.format("Please enter at least {0} characters"));
+
+// same as email, but TLD is optional
+jQuery.validator.addMethod("email2", function (value, element, param) {
+    return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
+}, jQuery.validator.messages.email);
+
+// same as url, but TLD is optional
+jQuery.validator.addMethod("url2", function (value, element, param) {
+    return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
+}, jQuery.validator.messages.url);
+
+// NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator
+// Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0
+// Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings)
+jQuery.validator.addMethod("creditcardtypes", function (value, element, param) {
+
+    if (/[^0-9-]+/.test(value))
+        return false;
+
+    value = value.replace(/\D/g, "");
+
+    var validTypes = 0x0000;
+
+    if (param.mastercard)
+        validTypes |= 0x0001;
+    if (param.visa)
+        validTypes |= 0x0002;
+    if (param.amex)
+        validTypes |= 0x0004;
+    if (param.dinersclub)
+        validTypes |= 0x0008;
+    if (param.enroute)
+        validTypes |= 0x0010;
+    if (param.discover)
+        validTypes |= 0x0020;
+    if (param.jcb)
+        validTypes |= 0x0040;
+    if (param.unknown)
+        validTypes |= 0x0080;
+    if (param.all)
+        validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;
+
+    if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard
+        return value.length == 16;
+    }
+    if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa
+        return value.length == 16;
+    }
+    if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex
+        return value.length == 15;
+    }
+    if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub
+        return value.length == 14;
+    }
+    if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute
+        return value.length == 15;
+    }
+    if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover
+        return value.length == 16;
+    }
+    if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb
+        return value.length == 16;
+    }
+    if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb
+        return value.length == 15;
+    }
+    if (validTypes & 0x0080) { //unknown
+        return true;
+    }
+    return false;
+}, "Please enter a valid credit card number.");
+
+jQuery.validator.addMethod("ipv4", function (value, element, param) {
+    return this.optional(element) || /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/i.test(value);
+}, "Please enter a valid IP v4 address.");
+
+jQuery.validator.addMethod("ipv6", function (value, element, param) {
+    return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);
+}, "Please enter a valid IP v6 address.");
+
+/**
+ * Return true if the field value matches the given format RegExp
+ *
+ * @example jQuery.validator.methods.pattern("AR1004",element,/^AR\d{4}$/)
+ * @result true
+ *
+ * @example jQuery.validator.methods.pattern("BR1004",element,/^AR\d{4}$/)
+ * @result false
+ *
+ * @name jQuery.validator.methods.pattern
+ * @type Boolean
+ * @cat Plugins/Validate/Methods
+ */
+jQuery.validator.addMethod("pattern", function (value, element, param) {
+    return this.optional(element) || param.test(value);
+}, "Invalid format.");
+
+// PX Custom Validator
+jQuery.validator.addMethod("ssid", function (value, element, param) {
+    return this.optional(element) || (value.indexOf(" ") != 0 && value.lastIndexOf(" ") != (value.length - 1) && /^[0-9a-zA-Z!#\(\)\+\-\.\/%=\?@\^_\{|\}~\x20]{1,32}$/.test(value));
+}, "Please enter a valid SSID.");
+
+jQuery.validator.addMethod("ssid_ap", function (value, element, param) {
+    return this.optional(element) || !(/[,;"\\]/.test(value));
+}, "Please enter a valid SSID.");
+
+jQuery.validator.addMethod("name_check", function (value, element, param) {
+    return this.optional(element) || !(/[{}\|\[\]~`\\]/.test(value));
+}, "Please enter a valid name.");
+
+jQuery.validator.addMethod("phonenumber_check", function (value, element, param) {
+    return this.optional(element) || /^[\d#\*\+pe\?][\d#\*pe\?]{0,}$/.test(value);
+}, "Please enter a valid phone number.");
+
+jQuery.validator.addMethod("sms_service_center_check", function (value, element, param) {
+    return this.optional(element) || /^[\+|00][\d]{1,}$/.test(value);
+}, "Please enter a valid phone number.");
+
+jQuery.validator.addMethod("email_check", function (value, element, param) {
+    return this.optional(element) || /^\w+(-\w+)*(.\w+)*@\w+(-\w+)*(\.[\da-zA-Z]{2,3})+$/.test(value);
+}, "Please enter a valid email.");
+
+jQuery.validator.addMethod("pin_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9]{4,8}$/.test(value);
+}, "Please enter a valid PIN code.");
+
+jQuery.validator.addMethod("puk_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9]{8}$/.test(value);
+}, "Please enter a valid PUK code.");
+
+jQuery.validator.addMethod("password_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9a-zA-Z!#$*\+,\-\.%:=\?@\[\]\^_\{|\}~]{1,32}$/.test(value);
+}, "Please enter a valid password.");
+
+jQuery.validator.addMethod("manage_info_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9a-zA-Z!#$*\+,\-\.%:=\?@\[\]\^_\{|\}~]{1,32}$/.test(value);
+}, "Please enter a valid password.");
+
+jQuery.validator.addMethod("secretcode_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9a-zA-Z!#$*\+,\-\.%:=\?@\[\]\^_\{|\}~]{1,32}$/.test(value);
+}, "Please enter a valid password.");
+
+jQuery.validator.addMethod("wps_pin_check", function (value, element, param) {
+    function validateChecksum(PIN) {
+        var accum = 0;
+        accum += 3 * (parseInt(PIN / 10000000) % 10);
+        accum += 1 * (parseInt(PIN / 1000000) % 10);
+        accum += 3 * (parseInt(PIN / 100000) % 10);
+        accum += 1 * (parseInt(PIN / 10000) % 10);
+        accum += 3 * (parseInt(PIN / 1000) % 10);
+        accum += 1 * (parseInt(PIN / 100) % 10);
+        accum += 3 * (parseInt(PIN / 10) % 10);
+        accum += 1 * (parseInt(PIN / 1) % 10);
+        return ((accum % 10) == 0);
+    }
+
+    var result = value.length == 8 && validateChecksum(value);
+    return this.optional(element) || result;
+}, "Invalid PIN number");
+
+jQuery.validator.addMethod("wps_pin_length_check", function (value, element, param) {
+    return this.optional(element) || value.length == 4 || value.length == 8;
+});
+jQuery.validator.addMethod("lanip_check", function (value, element, param) {
+    var isIp = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/i.test(value);
+    var result = false;
+    if(isIp) {
+        var iparr = value.split(".");
+        result =  checkRange(iparr[0], 1, 223) && !checkRange(iparr[0], 127, 127) && checkRange(iparr[1], 0, 255) && checkRange(iparr[2], 0, 255) && checkRange(iparr[3], 1, 254);
+    }
+
+    return this.optional(element) || result;
+});
+
+jQuery.validator.addMethod("comment_check", function (value, element, param) {
+    //not include space from 92/93
+    return this.optional(element) || /^[0-9a-zA-Z!#\(\)\+\-\.\/%=\?@\^_\{|\}~]{1,32}$/.test(value);
+});
+
+jQuery.validator.addMethod("check_file_path", function(value, element, param) {
+	var result = true;
+	if (value.length != 1 && (value.charAt(0) == '/' && value.charAt(1) == '/')) {
+		result = false;
+	}
+
+	var chars = [ '\\', ':', '*', '|', '#', '<', '>', '"', '?', "'", '&', '~', '`', '+' ];
+	for ( var i = 0; i < value.length; i++) {
+		if ($.inArray(value[i], chars) != -1) {
+			result = false;
+		}
+	}
+	return this.optional(element) || result;
+});
+
+jQuery.validator.addMethod("portCompare", function (value, element, param) {
+    var endVal = parseInt(value, 10);
+    var startVal = parseInt($(param).val(), 10);
+    return param.indexOf("Start") != -1? startVal <= endVal : startVal >= endVal;
+});
+
+jQuery.validator.addMethod("mac_check", function (value, element, param) {
+    var isMac = /^([0-9a-fA-F][0-9a-fA-F]:){5}([0-9a-fA-F][0-9a-fA-F])$/.test(value);
+    if(isMac) {
+        var macArr = value.toUpperCase().split(':');
+        var sub1 = '0x'+macArr[0];
+        return !checkAllField(macArr, 'FF') && !checkAllField(macArr, '00') && ((sub1 & 1)!=1);
+    }
+
+    function checkAllField(itemArr, value) {
+        return _.all(itemArr, function(item) {
+            return item == value;
+        });
+    }
+
+    return this.optional(element) || isMac;
+});
+
+jQuery.validator.addMethod("ip_check", function (value, element, param) {
+    var isIp = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/i.test(value);
+    var result = false;
+    if(isIp) {
+        var iparr = value.split(".");
+        result =  checkRange(iparr[0], 1, 223) && checkRange(iparr[1], 0, 255) && checkRange(iparr[2], 0, 255) && checkRange(iparr[3], 1, 254);
+    }
+
+    return this.optional(element) || result;
+});
+
+jQuery.validator.addMethod("dmz_ip_check", function (value, element, param) {
+    var isIp = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/i.test(value);
+    var result = false;
+    if(isIp) {
+        var iparr = value.split(".");
+        result =  checkRange(iparr[0], 1, 255) && checkRange(iparr[1], 0, 255) && checkRange(iparr[2], 0, 255) && checkRange(iparr[3], 1, 254);
+    }
+
+    return this.optional(element) || result;
+});
+
+jQuery.validator.addMethod("apn_check", function (value, element, param) {
+    if (value.charAt(0) == '.' || value.charAt(0) == '-' || value.charAt(value.length - 1) == '.' || value.charAt(value.length - 1) == '-') {
+        return false;
+    }
+    return this.optional(element) || (/^[0-9a-zA-Z\.-]{1,64}$/).test(value) && value.indexOf("($)") == -1;
+});
+
+jQuery.validator.addMethod("apn_profile_name_check", function (value, element, param) {
+    return this.optional(element) || (/^[0-9a-zA-Z\.!#\(\)\*\+%\-=\?@\[\]\^_\{\}\|~:, ]{1,30}$/).test(value) && value.indexOf("($)") == -1;
+});
+
+jQuery.validator.addMethod("ppp_username_check", function (value, element, param) {
+    return this.optional(element) || (/^[0-9a-zA-Z!#$&()*\+,\-\.\/%:;<=>?@\[\]^_\{|\}~ ]*$/.test(value) && value.indexOf("($)") == -1);
+});
+jQuery.validator.addMethod("ppp_password_check", function (value, element, param) {
+    return this.optional(element) || (/^[0-9a-zA-Z!#$&()*\+,\-\.\/%:;<=>?@\[\]^_\{|\}~ ]*$/.test(value) && value.indexOf("($)") == -1);
+});
+jQuery.validator.addMethod("ppp_secretcode_check", function (value, element, param) {
+    return this.optional(element) || (/^[0-9a-zA-Z!#$&()*\+,\-\.\/%:;<=>?@\[\]^_\{|\}~ ]*$/.test(value) && value.indexOf("($)") == -1);
+});
+jQuery.validator.addMethod("unlock_code_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9a-fA-F]{16}/.test(value);
+});
+
+jQuery.validator.addMethod("wifi_password_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9a-zA-Z!#\(\)\+\-\.\/%=\?@\^_\{|\}~]*$/.test(value);
+});
+jQuery.validator.addMethod("wifi_wep_password_check", function (value, element, param) {
+    return this.optional(element) || /^([0-9A-Fa-f]{10}|[0-9A-Fa-f]{26}|[\x00-\x7f]{5}|[\x00-\x7f]{13})$/.test(value);
+});
+jQuery.validator.addMethod("range_except", function (value, element, param) {
+    return this.optional(element) || (( value >= param[0] && value < 32000 )||( value > 32007 && value <= param[1] ));
+});
+jQuery.validator.addMethod("any_digits", function (value, element, param) {
+    return this.optional(element) || /^\d+$/.test(value);
+});
+
+jQuery.validator.addMethod("sntp_invalid_server_name", function(value, element, param){
+	return this.optional(element) || /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value) || /^[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62}(\.[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62})+$/.test(value);
+});
+jQuery.validator.addMethod("url_check", function(value, element, param){
+	 var strRegex = "^((https|http|ftp|rtsp|mms)?://)"       
+                    + "?(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?" //ftp的user@      
+                    + "(([0-9]{1,3}\.){3}[0-9]{1,3}" // IP形式的URL- 199.194.52.184      
+                    + "|" // 允许IP和DOMAIN(域名)      
+                    + "([0-9a-zA-Z_!~*'()-]+\.)*" // 域名- www.      
+                    + "([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z]\." // 二级域名      
+                    + "[a-zA-Z]{2,6})" // first level domain- .com or .museum      
+                    + "(:[0-9]{1,4})?" // 端口- :80      
+                    + "((/?)|"       
+                    + "(/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+/?)$";      
+    var re=new RegExp(strRegex);    
+
+	return this.optional(element) ||re.test(value);  ;
+//^[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62}(\.[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62})+$/.test(value);
+});
+jQuery.validator.addMethod("url_filter_check", function(value, element, param){
+	 var strRegex = "^((http|ftp|rtsp|mms)?://)"       
+                    + "?(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?" //ftp的user@      
+                    + "(([0-9]{1,3}\.){3}[0-9]{1,3}" // IP形式的URL- 199.194.52.184      
+                    + "|" // 允许IP和DOMAIN(域名)      
+                    + "([0-9a-zA-Z_!~*'()-]+\.)*" // 域名- www.      
+                    + "([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z]\." // 二级域名      
+                    + "[a-zA-Z]{2,6})" // first level domain- .com or .museum      
+                    + "(:[0-9]{1,4})?" // 端口- :80      
+                    + "((/?)|"       
+                    + "(/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+/?)$";      
+    var re=new RegExp(strRegex);    
+
+	return this.optional(element) ||re.test(value);  ;
+//^[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62}(\.[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62})+$/.test(value);
+});
+jQuery.validator.addMethod("voip_outbound_port_check", function(value, element, param){
+	var isNum = /^[0-9]{4,5}$/.test(value);
+	var result = false;
+	if(isNum) {
+		if(parseInt(value) >= 1024 &&  parseInt(value) <= 65535) {
+			return true;
+		}
+	}
+	return this.optional(element) || result;
+});
+jQuery.validator.addMethod("voip_time_check", function(value, element, param){
+	var isNum = /^[0-9]{1,4}$/.test(value);
+	var result = false;
+	if(isNum) {
+		if(parseInt(value) >= 1 &&  parseInt(value) <= 3600) {
+			return true;
+		}
+	}
+	return this.optional(element) || result;
+});
+jQuery.validator.addMethod("voip_sip_port_check", function(value, element, param){
+	var isNum = /^[0-9]{4,5}$/.test(value);
+	var result = false;
+	if(isNum) {
+		if(parseInt(value) >= 1026 &&  parseInt(value) <= 65535) {
+			return true;
+		}
+	}
+	return this.optional(element) || result;
+});
+jQuery.validator.addMethod("voip_port_compare", function(value, element, param){
+	var maxVal = parseInt(value, 10);
+    var minVal = parseInt($(param).val(), 10);
+    return param.indexOf("min") != -1? minVal <= maxVal : minVal >= maxVal;
+});
+jQuery.validator.addMethod("sip_domain_check", function (value, element, param) {
+    return this.optional(element)|| /^[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62}(\.[a-zA-Z0-9](-?[a-zA-Z0-9]){0,62})+$/.test(value);
+});
+jQuery.validator.addMethod("sip_realm_check", function (value, element, param) {
+    return this.optional(element)|| /^[0-9a-zA-Z.@:+-;?=%&]+$/.test(value);
+});
+jQuery.validator.addMethod("sip_proxy_server_check", function (value, element, param) {
+    return this.optional(element)|| /^[0-9a-zA-Z.@:+-;?=%&]+$/.test(value);
+});
+jQuery.validator.addMethod("display_name_check", function (value, element, param) {
+    return this.optional(element)|| /^[0-9a-zA-Z.@:+-;?=%&]+$/.test(value);
+});
+jQuery.validator.addMethod("authorized_username_check", function (value, element, param) {
+    return this.optional(element)|| /^[0-9a-zA-Z.@:+-;?=%&]+$/.test(value);
+});
+jQuery.validator.addMethod("account_password_check", function (value, element, param) {
+    return this.optional(element)|| /^[0-9a-zA-Z.@:+-;?=%&]+$/.test(value);
+});
+jQuery.validator.addMethod("forwarding_uri_check", function (value, element, param) {
+	var unicodeReg = /[\u4E00-\u9FA5]|[\uFE30-\uFFA0]/gi;
+	if(unicodeReg.test(value)) {
+		return false;
+	} else {
+		return /^[0-9\*#\+]+$/.test(value);
+	}
+});
+jQuery.validator.addMethod("login_password_length_check", function (value, element, param) {
+    return this.optional(element) || value.length >= 4;
+});
+
+jQuery.validator.addMethod("equalToPin", function (value, element, param) {
+    return this.optional(element) || value == $(param).val();
+});
+
+jQuery.validator.addMethod("equalToPassword", function (value, element, param) {
+    return this.optional(element) || value == $(param).val();
+});
+
+jQuery.validator.addMethod("equalTo", function (value, element, param) {
+    return this.optional(element) || value == $(param).val();
+});
+
+jQuery.validator.addMethod("wps_pin_validator", function (value, element, param) {
+    return this.optional(element) || /^\d{4}$/.test(value) || /^\d{8}$/.test(value) || /^\d{4}[ -]\d{4}$/.test(value);
+});
+
+jQuery.validator.addMethod("decimalRange", function (value, element, param) {
+	return this.optional(element) || /^(0|[1-9]\d*)(\.\d{1,2})?$/.test(value);
+});
+
+jQuery.validator.addMethod("ddns_hashvalue_check", function (value, element, param) {
+    return this.optional(element) || /^[0-9a-zA-Z=]*$/.test(value);
+});
+
+jQuery.validator.addMethod("siteName_check", function (value, element, param) {
+	var isSiteName = /[\*\$\[&:,;<>'"\\`\]¥\|\?\/]{1,32}/.test(value);
+    return this.optional(element) || !isSiteName;
+});
+
+jQuery.validator.addMethod("siteLink_check", function (value, element, param) {
+	var isSiteName = /^(https?):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
+    return this.optional(element) || isSiteName;
+});
diff --git a/ap/app/zte_webui/js/3rd/jquery.chosen.js b/ap/app/zte_webui/js/3rd/jquery.chosen.js
new file mode 100755
index 0000000..56e8e9b
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.chosen.js
@@ -0,0 +1,1424 @@
+/*
+Chosen, a Select Box Enhancer for jQuery and Prototype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Version 1.6.2
+Full source at https://github.com/harvesthq/chosen
+Copyright (c) 2011-2016 Harvest http://getharvest.com
+
+MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
+This file is generated by `grunt build`, do not edit it by hand.
+*/
+
+(function() {
+  var $, AbstractChosen, Chosen, SelectParser, _ref,
+    __hasProp = {}.hasOwnProperty,
+    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+  $ = jQuery;
+  
+  SelectParser = (function() {
+    function SelectParser() {
+      this.options_index = 0;
+      this.parsed = [];
+    }
+
+    SelectParser.prototype.add_node = function(child) {
+      if (child.nodeName.toUpperCase() === "OPTGROUP") {
+        return this.add_group(child);
+      } else {
+        return this.add_option(child);
+      }
+    };
+
+    SelectParser.prototype.add_group = function(group) {
+      var group_position, option, _i, _len, _ref, _results;
+      group_position = this.parsed.length;
+      this.parsed.push({
+        array_index: group_position,
+        group: true,
+        label: this.escapeExpression(group.label),
+        title: group.title ? group.title : void 0,
+        children: 0,
+        disabled: group.disabled,
+        classes: group.className
+      });
+      _ref = group.childNodes;
+      _results = [];
+      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+        option = _ref[_i];
+        _results.push(this.add_option(option, group_position, group.disabled));
+      }
+      return _results;
+    };
+
+    SelectParser.prototype.add_option = function(option, group_position, group_disabled) {
+      if (option.nodeName.toUpperCase() === "OPTION") {
+        if (option.text !== "") {
+          if (group_position != null) {
+            this.parsed[group_position].children += 1;
+          }
+          this.parsed.push({
+            array_index: this.parsed.length,
+            options_index: this.options_index,
+            value: option.value,
+            text: option.text,
+            html: option.innerHTML,
+            title: option.title ? option.title : void 0,
+            selected: option.selected,
+            disabled: group_disabled === true ? group_disabled : option.disabled,
+            group_array_index: group_position,
+            group_label: group_position != null ? this.parsed[group_position].label : null,
+            classes: option.className,
+            style: option.style.cssText
+          });
+        } else {
+          this.parsed.push({
+            array_index: this.parsed.length,
+            options_index: this.options_index,
+            empty: true
+          });
+        }
+        return this.options_index += 1;
+      }
+    };
+
+    SelectParser.prototype.escapeExpression = function(text) {
+      var map, unsafe_chars;
+      if ((text == null) || text === false) {
+        return "";
+      }
+      if (!/[\&\<\>\"\'\`]/.test(text)) {
+        return text;
+      }
+      map = {
+        "<": "&lt;",
+        ">": "&gt;",
+        '"': "&quot;",
+        "'": "&#x27;",
+        "`": "&#x60;"
+      };
+      unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g;
+      return text.replace(unsafe_chars, function(chr) {
+        return map[chr] || "&amp;";
+      });
+    };
+
+    return SelectParser;
+
+  })();
+
+  SelectParser.select_to_array = function(select) {
+    var child, parser, _i, _len, _ref;
+    parser = new SelectParser();
+    _ref = select.childNodes;
+    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+      child = _ref[_i];
+      parser.add_node(child);
+    }
+    return parser.parsed;
+  };
+
+  var contentRegex = /^[\d#\*\+pe\?][\d#\*pe\?]{0,}$/;
+  AbstractChosen = (function() {
+    function AbstractChosen(form_field, options) {
+      this.form_field = form_field;
+      this.options = options != null ? options : {};
+	  //if (!AbstractChosen.browser_is_supported()) 
+	  //{//1.6.2
+      //  return;
+      //}
+      this.is_multiple = this.form_field.multiple;
+      this.set_default_text();
+      this.set_default_values();
+      this.setup();
+      this.set_up_html();
+      this.register_observers();
+      this.on_ready();
+    }
+
+    AbstractChosen.prototype.set_default_values = function() {
+      var _this = this;
+      this.click_test_action = function(evt) {
+        return _this.test_active_click(evt);
+      };
+      this.activate_action = function(evt) {
+        return _this.activate_field(evt);
+      };
+      this.active_field = false;
+      this.mouse_on_container = false;
+      this.results_showing = false;
+      this.result_highlighted = null;
+      this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false;
+      this.disable_search_threshold = this.options.disable_search_threshold || 0;
+      this.disable_search = this.options.disable_search || false;
+      this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true;
+      this.group_search = this.options.group_search != null ? this.options.group_search : true;
+      this.search_contains = this.options.search_contains || false;
+      this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true;
+      this.max_selected_options = this.options.max_selected_options || Infinity;
+      this.inherit_select_classes = this.options.inherit_select_classes || false;
+      this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true;
+      this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true;
+      this.include_group_label_in_selected = this.options.include_group_label_in_selected || false;
+      this.max_shown_results = this.options.max_shown_results || Number.POSITIVE_INFINITY;
+      return this.case_sensitive_search = this.options.case_sensitive_search || false;
+    };
+
+    AbstractChosen.prototype.set_default_text = function() {
+      if (this.form_field.getAttribute("data-placeholder")) {
+        this.default_text = this.form_field.getAttribute("data-placeholder");
+      } else if (this.is_multiple) {
+        this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text;
+      } else {
+        this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text;
+      }
+      return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text;
+    };
+
+    AbstractChosen.prototype.choice_label = function(item) {
+      if (this.include_group_label_in_selected && (item.group_label != null)) {
+        return "<b class='group-name'>" + item.group_label + "</b>" + item.html;
+      } else {
+        return item.html;
+      }
+    };
+
+    AbstractChosen.prototype.mouse_enter = function() {
+      return this.mouse_on_container = true;
+    };
+
+    AbstractChosen.prototype.mouse_leave = function() {
+      return this.mouse_on_container = false;
+    };
+
+    AbstractChosen.prototype.input_focus = function(evt) {
+      var _this = this;
+      if (this.is_multiple) {
+        if (!this.active_field) {
+          return setTimeout((function() {
+            return _this.container_mousedown();
+          }), 50);
+        }
+      } else {
+        if (!this.active_field) {
+          return this.activate_field();
+        }
+      }
+    };
+
+    AbstractChosen.prototype.input_blur = function(evt) {
+      var _this = this;
+      if (!this.mouse_on_container) {
+        this.active_field = false;
+        if (this.max_selected_options > this.choices_count() && contentRegex.test(this.search_field.val())) {
+          this.result_clear_highlight();
+          this.result_select(evt);
+        }
+        return setTimeout((function() {
+          return _this.blur_test();
+        }), 100);
+      }
+    };
+
+    AbstractChosen.prototype.results_option_build = function(options) {
+      var content, data, data_content, shown_results, _i, _len, _ref;
+      content = '';
+      shown_results = 0;
+      _ref = this.results_data;
+      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+        data = _ref[_i];
+        data_content = '';
+        if (data.group) {
+          data_content = this.result_add_group(data);
+        } else {
+          data_content = this.result_add_option(data);
+        }
+        if (data_content !== '') {
+          shown_results++;
+          content += data_content;
+        }
+        if (options != null ? options.first : void 0) {
+          if (data.selected && this.is_multiple) {
+            this.choice_build(data);
+          } else if (data.selected && !this.is_multiple) {
+            this.single_set_selected_text(this.choice_label(data));
+          }
+        }
+        if (shown_results >= this.max_shown_results) {
+          break;
+        }
+      }
+      return content;
+    };
+
+    AbstractChosen.prototype.result_add_option = function(option) {
+      var classes, option_el;
+      if (!option.search_match) {
+        return '';
+      }
+      if (!this.include_option_in_results(option)) {
+        return '';
+      }
+      classes = [];
+      if (!option.disabled && !(option.selected && this.is_multiple)) {
+        classes.push("active-result");
+      }
+      if (option.disabled && !(option.selected && this.is_multiple)) {
+        classes.push("disabled-result");
+      }
+      if (option.selected) {
+        classes.push("result-selected");
+      }
+      if (option.group_array_index != null) {
+        classes.push("group-option");
+      }
+      if (option.classes !== "") {
+        classes.push(option.classes);
+      }
+      option_el = document.createElement("li");
+      option_el.className = classes.join(" ");
+      option_el.style.cssText = option.style;
+      option_el.setAttribute("data-option-array-index", option.array_index);
+      option_el.innerHTML = option.search_text;
+      if (option.title) {
+        option_el.title = option.title;
+      }
+      return this.outerHTML(option_el);
+    };
+
+    AbstractChosen.prototype.result_add_group = function(group) {
+      var classes, group_el;
+      if (!(group.search_match || group.group_match)) {
+        return '';
+      }
+      if (!(group.active_options > 0)) {
+        return '';
+      }
+      classes = [];
+      classes.push("group-result");
+      if (group.classes) {
+        classes.push(group.classes);
+      }
+      group_el = document.createElement("li");
+      group_el.className = classes.join(" ");
+      group_el.innerHTML = group.search_text;
+      if (group.title) {
+        group_el.title = group.title;
+      }
+      return this.outerHTML(group_el);
+    };
+
+    AbstractChosen.prototype.results_update_field = function() {
+      this.set_default_text();
+      if (!this.is_multiple) {
+        this.results_reset_cleanup();
+      }
+      this.result_clear_highlight();
+      this.results_build();
+      if (this.results_showing) {
+        return this.winnow_results();
+      }
+    };
+
+    AbstractChosen.prototype.reset_single_select_options = function() {
+      var result, _i, _len, _ref, _results;
+      _ref = this.results_data;
+      _results = [];
+      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+        result = _ref[_i];
+        if (result.selected) {
+          _results.push(result.selected = false);
+        } else {
+          _results.push(void 0);
+        }
+      }
+      return _results;
+    };
+
+    AbstractChosen.prototype.results_toggle = function() {
+      if (this.results_showing) {
+        return this.results_hide();
+      } else {
+        return this.results_show();
+      }
+    };
+
+    AbstractChosen.prototype.results_search = function(evt) {
+      if (this.results_showing) {
+        return this.winnow_results();
+      } else {
+        return this.results_show();
+      }
+    };
+
+    AbstractChosen.prototype.winnow_results = function() {
+      var escapedSearchText, option, regex, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref;
+      this.no_results_clear();
+      results = 0;
+      searchText = this.get_search_text();//searchText = this.search_field.val() === $.i18n.prop('select_some_options') ? "" : $('<div/>').text($.trim(this.search_field.val())).html();
+      escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");//regexAnchor = this.search_contains ? "" : "^";
+      zregex = new RegExp(escapedSearchText, 'i');//regex = new RegExp(regexAnchor + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
+      regex = this.get_search_regex(escapedSearchText);//zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
+      _ref = this.results_data;
+      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+        option = _ref[_i];
+        option.search_match = false;
+        results_group = null;
+        if (this.include_option_in_results(option)) {//if (!option.disabled && !option.empty) {
+          if (option.group) {
+            option.group_match = false;
+            option.active_options = 0;
+            //$('#' + option.dom_id).css('display', 'none');
+          }
+          if ((option.group_array_index != null) && this.results_data[option.group_array_index]) {
+            results_group = this.results_data[option.group_array_index];
+            if (results_group.active_options === 0 && results_group.search_match) {
+              results += 1;
+            }
+            results_group.active_options += 1;
+          }
+          option.search_text = option.group ? option.label : option.html;
+          if (!(option.group && !this.group_search)) {
+            option.search_match = this.search_string_match(option.search_text, regex);
+            if (option.search_match && !option.group) {
+              results += 1;
+            }
+            if (option.search_match) {
+              if (searchText.length) {
+                startpos = option.search_text.search(zregex);
+                text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length);
+                option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
+              }
+              if (results_group != null) {
+                results_group.group_match = true;
+              }
+            } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) {
+              option.search_match = true;
+            }
+          }
+        }
+      }
+      this.result_clear_highlight();
+      if (results < 1 && searchText.length) {
+        this.update_results_content("");
+        return this.no_results(searchText);
+      } else {
+        this.update_results_content(this.results_option_build());
+        return this.winnow_results_set_highlight();
+      }
+    };
+
+    AbstractChosen.prototype.get_search_regex = function(escaped_search_string) {
+      var regex_anchor, regex_flag;
+      regex_anchor = this.search_contains ? "" : "^";
+      regex_flag = this.case_sensitive_search ? "" : "i";
+      return new RegExp(regex_anchor + escaped_search_string, regex_flag);
+    };
+
+    AbstractChosen.prototype.search_string_match = function(search_string, regex) {
+      var part, parts, _i, _len;
+      if (regex.test(search_string)) {
+        return true;
+      } else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) {
+        parts = search_string.replace(/\[|\]/g, "").split(" ");
+        if (parts.length) {
+          for (_i = 0, _len = parts.length; _i < _len; _i++) {
+            part = parts[_i];
+            if (regex.test(part)) {
+              return true;
+            }
+          }
+        }
+      }
+    };
+
+    AbstractChosen.prototype.choices_count = function() {
+      var option, _i, _len, _ref;
+      if (this.selected_option_count != null) {
+        return this.selected_option_count;
+      }
+      this.selected_option_count = 0;
+      _ref = this.form_field.options;
+      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+        option = _ref[_i];
+        if (option.selected) {
+          this.selected_option_count += 1;
+        }
+      }
+      return this.selected_option_count;
+    };
+
+    AbstractChosen.prototype.choices_click = function(evt) {
+      evt.preventDefault();
+      if (!(this.results_showing || this.is_disabled)) {
+        return this.results_show();
+      }
+    };
+
+    AbstractChosen.prototype.keyup_checker = function(evt) {
+      var stroke, _ref;
+      stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
+      this.search_field_scale();
+      switch (stroke) {
+        case 8:
+          if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) {
+            return this.keydown_backstroke();
+          } else if (!this.pending_backstroke) {
+            this.result_clear_highlight();
+            return this.results_search();
+          }
+          break;
+        case 13:
+          evt.preventDefault();
+            var searchVal = this.search_field.val();
+            if (this.results_showing && this.result_highlight ){
+                return this.result_select(evt);
+            } else if (this.results_showing && !this.result_highlight && contentRegex.test(searchVal)) {
+                return this.result_select(evt, true);
+            } else if (this.results_showing && !this.result_highlight && !contentRegex.test(searchVal)) {
+                this.generate_invalid_number_note();
+            } else if (!this.result_highlight && contentRegex.test(searchVal)) {
+			    return this.result_select(evt);
+		    }
+          break;
+        case 27:
+          if (this.results_showing) this.results_hide();
+          return true;
+        case 59:
+        case 186:
+          evt.preventDefault();
+		  var searchVal = this.search_field.val();
+		  searchVal = this.search_field.val().length < 3 ? searchVal : searchVal.substring(0, searchVal.length - 1);
+		  this.search_field.val(searchVal);
+		  if (this.results_showing && this.result_highlight ){
+			return this.result_select(evt);
+		  } else if (this.results_showing && !this.result_highlight && contentRegex.test(searchVal)) {
+			return this.result_select(evt);
+		  } else if (this.results_showing && !this.result_highlight && !contentRegex.test(searchVal)) {
+            this.generate_invalid_number_note();
+          }else if (!this.result_highlight && contentRegex.test(searchVal)) {
+			return this.result_select(evt);
+		  } 
+          break;
+        case 9:
+        case 38:
+        case 40:
+        case 16:
+        case 91:
+        case 17:
+        case 18:
+          break;
+        default:
+          return this.results_search();
+      }
+    };
+   AbstractChosen.clearInvalidNoteTimer = null;
+    AbstractChosen.prototype.generate_invalid_number_note = function() {
+        if(this.clearInvalidNoteTimer){
+            window.clearTimeout(this.clearInvalidNoteTimer);
+            this.clearInvalidNoteTimer = null;
+        }
+        $('#searchNumberInvalidWord').hide().remove();
+        $('<i class="colorRed" id="searchNumberInvalidWord" data-trans="phone_number_invalid"></i>').appendTo('.no-results');
+        $('.no-results').translate();
+        this.clearInvalidNoteTimer = addTimeout(function(){
+            $('#searchNumberInvalidWord').hide().remove();
+        }, 3000);
+    }
+    /*AbstractChosen.prototype.generate_field_id = function() {
+      var new_id;
+      new_id = this.generate_random_id();
+      this.form_field.id = new_id;
+      return new_id;
+    };
+
+    AbstractChosen.prototype.generate_random_char = function() {
+      var chars, newchar, rand;
+      chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+      rand = Math.floor(Math.random() * chars.length);
+      return newchar = chars.substring(rand, rand + 1);
+    };*/
+
+    AbstractChosen.prototype.clipboard_event_checker = function(evt) {
+      var _this = this;
+      return setTimeout((function() {
+        return _this.results_search();
+      }), 50);
+    };
+
+    AbstractChosen.prototype.container_width = function() {
+      if (this.options.width != null) {
+        return this.options.width;
+      } else {
+        return "" + this.form_field.offsetWidth + "px";
+      }
+    };
+
+    AbstractChosen.prototype.include_option_in_results = function(option) {
+      if (this.is_multiple && (!this.display_selected_options && option.selected)) {
+        return false;
+      }
+      if (!this.display_disabled_options && option.disabled) {
+        return false;
+      }
+      if (option.empty) {
+        return false;
+      }
+      return true;
+    };
+
+    AbstractChosen.prototype.search_results_touchstart = function(evt) {
+      this.touch_started = true;
+      return this.search_results_mouseover(evt);
+    };
+
+    AbstractChosen.prototype.search_results_touchmove = function(evt) {
+      this.touch_started = false;
+      return this.search_results_mouseout(evt);
+    };
+
+    AbstractChosen.prototype.search_results_touchend = function(evt) {
+      if (this.touch_started) {
+        return this.search_results_mouseup(evt);
+      }
+    };
+
+    AbstractChosen.prototype.outerHTML = function(element) {
+      var tmp;
+      if (element.outerHTML) {
+        return element.outerHTML;
+      }
+      tmp = document.createElement("div");
+      tmp.appendChild(element);
+      return tmp.innerHTML;
+    };
+
+    AbstractChosen.browser_is_supported = function() {
+      if ("Microsoft Internet Explorer" === window.navigator.appName) {
+        return document.documentMode >= 8;
+      }
+      if (/iP(od|hone)/i.test(window.navigator.userAgent) || /IEMobile/i.test(window.navigator.userAgent) || /Windows Phone/i.test(window.navigator.userAgent) || /BlackBerry/i.test(window.navigator.userAgent) || /BB10/i.test(window.navigator.userAgent) || /Android.*Mobile/i.test(window.navigator.userAgent)) {
+        return false;
+      }
+      return true;
+    };	
+
+    AbstractChosen.default_multiple_text = $.i18n.prop("select_some_options");//"Select Some Options";
+
+    AbstractChosen.default_single_text = $.i18n.prop("select_an_option");//"Select an Option";
+
+    AbstractChosen.default_no_result_text = $.i18n.prop("sms_chat_input_confirm");//"No results match";
+
+    return AbstractChosen;
+
+  })();
+
+
+  $.fn.extend({
+    chosen: function(options) {
+      if (!AbstractChosen.browser_is_supported()) {
+        //return this;
+      }
+      return this.each(function(input_field) {
+        var $this, chosen;
+        $this = $(this);
+        chosen = $this.data('chosen');
+        if (options === 'destroy') {
+          if (chosen instanceof Chosen) {
+            chosen.destroy();
+          }
+          return;
+        }
+        if (!(chosen instanceof Chosen)) {
+          $this.data('chosen', new Chosen(this, options));
+        }
+      });
+    }
+  });
+
+  Chosen = (function(_super) {
+    __extends(Chosen, _super);
+
+    function Chosen() {
+      _ref = Chosen.__super__.constructor.apply(this, arguments);
+      return _ref;
+    }
+
+    Chosen.prototype.setup = function() {
+      this.form_field_jq = $(this.form_field);
+      this.current_selectedIndex = this.form_field.selectedIndex;
+      return this.is_rtl = this.form_field_jq.hasClass("chosen-rtl");
+    };
+
+    Chosen.prototype.set_up_html = function() {
+      var container_classes, container_props;
+      container_classes = ["chosen-container"];
+      container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single"));
+      if (this.inherit_select_classes && this.form_field.className) {
+        container_classes.push(this.form_field.className);
+      }
+      if (this.is_rtl) {
+        container_classes.push("chosen-rtl");
+      }
+      container_props = {
+        'class': container_classes.join(' '),
+        'style': "width: " + (this.container_width()) + ";",
+        'title': this.form_field.title
+      };
+      if (this.form_field.id.length) {
+        container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen";
+      }
+      this.container = $("<div />", container_props);
+      if (this.is_multiple) {
+        this.container.html('<ul class="chosen-choices"><li class="search-field"><input type="text" id="chosen-search-field-input" maxlength="40" data-trans="select_some_options" value="' + $.i18n.prop('select_some_options') + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>');
+      } else {
+        this.container.html('<a class="chosen-single chosen-default"><span>' + $.i18n.prop('select_some_options') + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>');
+      }
+      this.form_field_jq.hide().after(this.container);
+      this.dropdown = this.container.find('div.chosen-drop').first();
+      this.search_field = this.container.find('input').first();
+      this.search_results = this.container.find('ul.chosen-results').first();
+      this.search_field_scale();
+      this.search_no_results = this.container.find('li.no-results').first();
+      if (this.is_multiple) {
+        this.search_choices = this.container.find('ul.chosen-choices').first();
+        this.search_container = this.container.find('li.search-field').first();
+      } else {
+        this.search_container = this.container.find('div.chosen-search').first();
+        this.selected_item = this.container.find('.chosen-single').first();
+      }
+      this.results_build();
+      this.set_tab_index();
+      return this.set_label_behavior();
+    };
+
+    Chosen.prototype.on_ready = function() {
+      return this.form_field_jq.trigger("chosen:ready", {
+        chosen: this
+      });
+    };
+
+    Chosen.prototype.register_observers = function() {
+      var _this = this;
+      this.container.bind('touchstart.chosen', function(evt) {
+        _this.container_mousedown(evt);
+        return evt.preventDefault();
+      });
+      this.container.bind('touchend.chosen', function(evt) {
+        _this.container_mouseup(evt);
+        return evt.preventDefault();
+      });
+      this.container.bind('mousedown.chosen', function(evt) {
+        _this.container_mousedown(evt);
+      });
+      this.container.bind('mouseup.chosen', function(evt) {
+        _this.container_mouseup(evt);
+      });
+      this.container.bind('mouseenter.chosen', function(evt) {
+        _this.mouse_enter(evt);
+      });
+      this.container.bind('mouseleave.chosen', function(evt) {
+        _this.mouse_leave(evt);
+      });
+      this.search_results.bind('mouseup.chosen', function(evt) {
+        _this.search_results_mouseup(evt);
+      });
+      this.search_results.bind('mouseover.chosen', function(evt) {
+        _this.search_results_mouseover(evt);
+      });
+      this.search_results.bind('mouseout.chosen', function(evt) {
+        _this.search_results_mouseout(evt);
+      });
+      this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) {
+        _this.search_results_mousewheel(evt);
+      });
+      this.search_results.bind('touchstart.chosen', function(evt) {
+        _this.search_results_touchstart(evt);
+      });
+      this.search_results.bind('touchmove.chosen', function(evt) {
+        _this.search_results_touchmove(evt);
+      });
+      this.search_results.bind('touchend.chosen', function(evt) {
+        _this.search_results_touchend(evt);
+      });
+      this.form_field_jq.bind("chosen:updated.chosen", function(evt) {
+        _this.results_update_field(evt);
+      });
+      this.form_field_jq.bind("chosen:activate.chosen", function(evt) {
+        _this.activate_field(evt);
+      });
+      this.form_field_jq.bind("chosen:open.chosen", function(evt) {
+        _this.container_mousedown(evt);
+      });
+      this.form_field_jq.bind("chosen:close.chosen", function(evt) {
+        _this.input_blur(evt);
+      });
+      this.search_field.bind('blur.chosen', function(evt) {
+        _this.input_blur(evt);
+      });
+      this.search_field.bind('keyup.chosen', function(evt) {
+        _this.keyup_checker(evt);
+      });
+      this.search_field.bind('keydown.chosen', function(evt) {
+        _this.keydown_checker(evt);
+      });
+      this.search_field.bind('focus.chosen', function(evt) {
+        _this.input_focus(evt);
+      });
+      this.search_field.bind('cut.chosen', function(evt) {
+        _this.clipboard_event_checker(evt);
+      });
+      this.search_field.bind('paste.chosen', function(evt) {
+        _this.clipboard_event_checker(evt);
+      });
+      if (this.is_multiple) {
+        return this.search_choices.bind('click.chosen', function(evt) {
+          _this.choices_click(evt);
+        });
+      } else {
+        return this.container.bind('click.chosen', function(evt) {
+          evt.preventDefault();
+        });
+      }
+    };
+
+    Chosen.prototype.destroy = function() {
+      $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
+      if (this.search_field[0].tabIndex) {
+        this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex;
+      }
+      this.container.remove();
+      this.form_field_jq.removeData('chosen');
+      return this.form_field_jq.show();
+    };
+
+    Chosen.prototype.search_field_disabled = function() {
+      this.is_disabled = this.form_field_jq[0].disabled;
+      if (this.is_disabled) {
+        this.container.addClass('chosen-disabled');
+        this.search_field[0].disabled = true;
+        if (!this.is_multiple) {
+          this.selected_item.unbind("focus.chosen", this.activate_action);
+        }
+        return this.close_field();
+      } else {
+        this.container.removeClass('chosen-disabled');
+        this.search_field[0].disabled = false;
+        if (!this.is_multiple) {
+          return this.selected_item.bind("focus.chosen", this.activate_action);
+        }
+      }
+    };
+
+    Chosen.prototype.container_mousedown = function(evt) {
+      if (!this.is_disabled) {
+        if (evt && evt.type === "mousedown" && !this.results_showing) {
+          evt.preventDefault();
+        }
+        if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) {
+            if (!this.active_field) {
+                if (this.is_multiple) {
+                    this.search_field.val("");
+                }
+                $(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action);//$(document).click(this.click_test_action);//1.6.2
+                this.results_show();
+            } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) {
+                evt.preventDefault();
+                this.results_toggle();
+            }
+            return this.activate_field();
+        }
+      }
+    };
+
+    Chosen.prototype.container_mouseup = function(evt) {
+      if (evt.target.nodeName === "ABBR" && !this.is_disabled) {
+        return this.results_reset(evt);
+      }
+    };
+
+    Chosen.prototype.search_results_mousewheel = function(evt) {
+      var delta;
+      if (evt.originalEvent) {
+        delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail;
+      }
+      if (delta != null) {
+        evt.preventDefault();
+        if (evt.type === 'DOMMouseScroll') {
+          delta = delta * 40;
+        }
+        return this.search_results.scrollTop(delta + this.search_results.scrollTop());
+      }
+    };
+
+    Chosen.prototype.blur_test = function(evt) {
+      if (!this.active_field && this.container.hasClass("chosen-container-active")) {
+        return this.close_field();
+      }
+    };
+
+    Chosen.prototype.close_field = function() {
+      $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
+      //if (!this.is_multiple) {//??????????????????????????//
+        //this.selected_item.attr("tabindex", this.search_field.attr("tabindex"));
+        //this.search_field.attr("tabindex", -1);
+      //}
+      this.active_field = false;
+      this.results_hide();
+      this.container.removeClass("chosen-container-active");
+      this.clear_backstroke();
+      this.show_search_field_default();
+      //this.search_field.blur();//????????????????????????/
+      return this.search_field_scale();
+    };
+
+    Chosen.prototype.activate_field = function() {
+      //if (!this.is_multiple && !this.active_field) {//??????????????
+        //this.search_field.attr("tabindex", this.selected_item.attr("tabindex"));
+        //this.selected_item.attr("tabindex", -1);
+      //}
+      this.container.addClass("chosen-container-active");
+      this.active_field = true;
+      this.search_field.val(this.search_field.val());
+      return this.search_field.focus();
+    };
+
+    Chosen.prototype.test_active_click = function(evt) {
+      var active_container;
+      active_container = $(evt.target).closest('.chosen-container');
+      if (active_container.length && this.container[0] === active_container[0]) {
+        return this.active_field = true;
+      } else {
+        return this.close_field();
+      }
+    };
+
+    Chosen.prototype.results_build = function() {
+      this.parsing = true;
+      this.selected_option_count = null;
+      this.results_data = SelectParser.select_to_array(this.form_field);
+      if (this.is_multiple) {
+        this.search_choices.find("li.search-choice").remove();
+      } else if (!this.is_multiple) {
+        this.single_set_selected_text();//this.selected_item.addClass("chzn-default").find("span").text($.i18n.prop('select_some_options'));
+        if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) {
+          this.search_field[0].readOnly = true;
+          this.container.addClass("chosen-container-single-nosearch");
+        } else {
+          this.search_field[0].readOnly = false;
+          this.container.removeClass("chosen-container-single-nosearch");
+        }
+      }
+      this.update_results_content(this.results_option_build({
+        first: true
+      }));
+      this.search_field_disabled();
+      this.show_search_field_default();
+      this.search_field_scale();
+      return this.parsing = false;
+    };
+
+    Chosen.prototype.result_do_highlight = function(el) {
+      var high_bottom, high_top, maxHeight, visible_bottom, visible_top;
+      if (el.length) {
+        this.result_clear_highlight();
+        this.result_highlight = el;
+        this.result_highlight.addClass("highlighted");
+        maxHeight = parseInt(this.search_results.css("maxHeight"), 10);
+        visible_top = this.search_results.scrollTop();
+        visible_bottom = maxHeight + visible_top;
+        high_top = this.result_highlight.position().top + this.search_results.scrollTop();
+        high_bottom = high_top + this.result_highlight.outerHeight();
+        if (high_bottom >= visible_bottom) {
+          return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0);
+        } else if (high_top < visible_top) {
+          return this.search_results.scrollTop(high_top);
+        }
+      }
+    };
+
+    Chosen.prototype.result_clear_highlight = function() {
+      if (this.result_highlight) {
+        this.result_highlight.removeClass("highlighted");
+      }
+      return this.result_highlight = null;
+    };
+
+    Chosen.prototype.results_show = function() {
+      if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
+        this.form_field_jq.trigger("chosen:maxselected", {
+          chosen: this
+        });
+        return false;
+      }
+      this.container.addClass("chosen-with-drop");
+      this.results_showing = true;
+      this.search_field.focus();
+      this.search_field.val(this.search_field.val());
+      this.winnow_results();
+      return this.form_field_jq.trigger("chosen:showing_dropdown", {
+        chosen: this
+      });
+    };
+
+    Chosen.prototype.update_results_content = function(content) {
+      return this.search_results.html(content);
+    };
+
+    Chosen.prototype.results_hide = function() {
+      if (this.results_showing) {
+        this.result_clear_highlight();
+        this.container.removeClass("chosen-with-drop");
+        this.form_field_jq.trigger("chosen:hiding_dropdown", {
+          chosen: this
+        });
+      }
+      return this.results_showing = false;
+    };
+
+    Chosen.prototype.set_tab_index = function(el) {
+      var ti;
+      if (this.form_field.tabIndex) {
+        ti = this.form_field.tabIndex;
+        this.form_field.tabIndex = -1;
+        return this.search_field[0].tabIndex = ti;
+      }
+    };
+
+    Chosen.prototype.set_label_behavior = function() {
+      var _this = this;
+      this.form_field_label = this.form_field_jq.parents("label");
+      if (!this.form_field_label.length && this.form_field.id.length) {
+        this.form_field_label = $("label[for='" + this.form_field.id + "']");
+      }
+      if (this.form_field_label.length > 0) {
+        return this.form_field_label.bind('click.chosen', function(evt) {
+          if (_this.is_multiple) {
+            return _this.container_mousedown(evt);
+          } else {
+            return _this.activate_field();
+          }
+        });
+      }
+    };
+
+    Chosen.prototype.show_search_field_default = function() {
+      if (this.is_multiple && this.choices_count() < 1 && !this.active_field) {
+        this.search_field.val($.i18n.prop('select_some_options'));
+        return this.search_field.addClass("default");
+      } else {
+        this.search_field.val("");
+        return this.search_field.removeClass("default");
+      }
+    };
+
+    Chosen.prototype.search_results_mouseup = function(evt) {
+      var target;
+      target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
+      if (target.length) {
+        this.result_highlight = target;
+        this.result_select(evt);
+        return this.search_field.focus();
+      }
+    };
+
+    Chosen.prototype.search_results_mouseover = function(evt) {
+      var target;
+      target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
+      if (target) {
+        return this.result_do_highlight(target);
+      }
+    };
+
+    Chosen.prototype.search_results_mouseout = function(evt) {
+      if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) {
+        return this.result_clear_highlight();
+      }
+    };
+
+    Chosen.prototype.choice_build = function(item) {
+      var choice, close_link,
+        _this = this;
+      choice = $('<li />', {
+        "class": "search-choice"
+      }).html("<span>" + (this.choice_label(item)) + "</span>");
+      if (item.disabled) {
+        choice.addClass('search-choice-disabled');
+      } else {
+        close_link = $('<a />', {
+          "class": 'search-choice-close',
+          'data-option-array-index': item.array_index
+        });
+        close_link.bind('click.chosen', function(evt) {
+          return _this.choice_destroy_link_click(evt);
+        });
+        choice.append(close_link);
+      }
+      return this.search_container.before(choice);
+    };
+
+    Chosen.prototype.choice_destroy_link_click = function(evt) {
+      evt.preventDefault();
+      evt.stopPropagation();
+      if (!this.is_disabled) {
+        return this.choice_destroy($(evt.target));
+      }
+    };
+
+    Chosen.prototype.choice_destroy = function(link) {
+      if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) {
+        this.show_search_field_default();
+        if (this.is_multiple && this.choices_count() > 0 && this.search_field.val().length < 1) {
+          this.results_hide();
+        }
+        link.parents('li').first().remove();
+        return this.search_field_scale();
+      }
+    };
+
+    Chosen.prototype.results_reset = function() {
+      this.reset_single_select_options();
+      this.form_field.options[0].selected = true;
+      this.single_set_selected_text();
+      /*this.selected_item.find("span").text($.i18n.prop('select_some_options'));
+      if (!this.is_multiple) {
+        this.selected_item.addClass("chzn-default");
+      }*/
+      this.show_search_field_default();
+      this.results_reset_cleanup();
+      this.form_field_jq.trigger("change");
+      if (this.active_field) {
+        return this.results_hide();
+      }
+    };
+
+    Chosen.prototype.results_reset_cleanup = function() {
+      this.current_selectedIndex = this.form_field.selectedIndex;
+      return this.selected_item.find("abbr").remove();
+    };
+
+    Chosen.prototype.result_select = function(evt, hide_search_result) {
+      var high, item;
+      if (this.result_highlight) {
+        high = this.result_highlight;
+            //high_id = high.attr("id");
+        this.result_clear_highlight();
+        if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
+          this.form_field_jq.trigger("chosen:maxselected", {
+            chosen: this
+          });
+          return false;
+        }
+        if (this.is_multiple) {
+                high.removeClass("active-result");//this.result_deactivate(high);
+        } else {
+                /*this.search_results.find(".result-selected").removeClass("result-selected");
+                this.result_single_selected = high;
+                this.selected_item.removeClass("chzn-default");*/
+          this.reset_single_select_options();
+        }
+        high.addClass("result-selected");
+        //position = high_id.substr(high_id.lastIndexOf("_") + 1);
+        item = this.results_data[high[0].getAttribute("data-option-array-index")];//item = this.results_data[position];
+        item.selected = true;
+			
+			//if(this.max_selected_options > this.choices){
+                this.form_field.options[item.options_index].selected = true;
+			//}
+            this.selected_option_count = null;
+            if (this.is_multiple) {
+              this.choice_build(item);
+            } else {
+				this.single_set_selected_text(this.choice_label(item));
+                //this.selected_item.find("span").first().text(item.text);
+                //if (this.allow_single_deselect) {
+                //    this.single_deselect_control_build();
+                //}
+            }
+        if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) {
+          this.results_hide();
+        }
+            this.show_search_field_default();//this.search_field.val("");
+        if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) {
+          this.form_field_jq.trigger("change", {
+            'selected': this.form_field.options[item.options_index].value
+                });
+            }
+            this.current_selectedIndex = this.form_field.selectedIndex;
+			evt.preventDefault();
+            return this.search_field_scale();
+        } else {
+            // add the content to the selected widget during click Enter button
+            var searchVal = this.search_field.val();
+            var isExist = false;
+            var numLength = 8;
+            for(var i = 0; i < this.form_field.options.length; i++){
+                if(this.form_field.options[i].value == getLastNumber(searchVal,numLength)){//if(this.form_field.options[i].value == searchVal){                
+				    if(this.max_selected_options > this.choices_count()){
+						this.form_field.options[i].selected = true;
+					}                  
+                  isExist = true;
+                  break;
+                }
+            }
+            if(!isExist && this.max_selected_options > this.choices_count()){
+                var enable = true;
+                //if (this.max_selected_options > this.choices){enable = true;} else { enable = false;}
+                var newOpp = new Option(searchVal, getLastNumber(searchVal,numLength), false, enable);//var newOpp = new Option(searchVal, searchVal, false, enable);
+                newOpp.source = "0";//show this option is not from the PB or received SMS
+                this.form_field.add(newOpp);
+            }
+            this.results_build();
+            this.no_results_clear();
+            return this.search_field_scale();
+        }
+    };
+
+    /*Chosen.prototype.result_activate = function(el) {
+      return el.addClass("active-result");
+    };
+
+    Chosen.prototype.result_deactivate = function(el) {
+      return el.removeClass("active-result");
+    };*/
+	
+    Chosen.prototype.single_set_selected_text = function(text) {
+      if (text == null) {
+        text = this.default_text;
+      }
+      if (text === this.default_text) {
+        this.selected_item.addClass("chosen-default");
+      } else {
+        this.single_deselect_control_build();
+        this.selected_item.removeClass("chosen-default");
+      }
+      return this.selected_item.find("span").html(text);
+    };
+	
+    Chosen.prototype.result_deselect = function(pos) {
+      var result_data, _i;
+      result_data = this.results_data[pos];
+      if (!this.form_field.options[result_data.options_index].disabled) {
+        result_data.selected = false;
+        this.form_field.options[result_data.options_index].selected = false;
+        this.selected_option_count = null;
+        this.result_clear_highlight();
+        if (this.results_showing) {
+          this.winnow_results();
+        }
+        this.form_field_jq.trigger("change", {
+          deselected: this.form_field.options[result_data.options_index].value
+        });
+		if(this.form_field.options[result_data.options_index].text.indexOf("/") < 0 && this.form_field.options[result_data.options_index].source == "0"){ 
+            if(!!window.ActiveXObject || "ActiveXObject" in window){
+                this.form_field.options[result_data.options_index].removeNode(true);
+            }else{
+                this.form_field.options[result_data.options_index].remove();
+            }
+            this.results_build();
+		}
+        this.search_field_scale();
+        return true;
+      } else {
+        return false;
+      }
+    };
+
+    Chosen.prototype.single_deselect_control_build = function() {
+      if (!this.allow_single_deselect) {
+        return;
+      }
+      if (!this.selected_item.find("abbr").length) {
+        this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>");
+      }
+      return this.selected_item.addClass("chosen-single-with-deselect");
+    };
+	
+    Chosen.prototype.get_search_text = function() {
+      return $('<div/>').text($.trim(this.search_field.val())).html();
+    };
+
+    /*Chosen.prototype.winnow_results_clear = function() {
+      var li, lis, _i, _len, _results;
+      this.search_field.val("");
+      lis = this.search_results.find("li");
+      _results = [];
+      for (_i = 0, _len = lis.length; _i < _len; _i++) {
+        li = lis[_i];
+        li = $(li);
+        if (li.hasClass("group-result")) {
+          _results.push(li.css('display', 'auto'));
+        } else if (!this.is_multiple || !li.hasClass("result-selected")) {
+          _results.push(this.result_activate(li));
+        } else {
+          _results.push(void 0);
+        }
+      }
+      return _results;
+    };*/
+
+    Chosen.prototype.winnow_results_set_highlight = function() {
+      var do_high, selected_results;
+      selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : [];
+      do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first();
+      if (do_high != null) {
+        return this.result_do_highlight(do_high);
+      }
+    };
+
+    Chosen.prototype.no_results = function(terms) {
+      var no_results_html;
+      no_results_html = $('<li class="no-results"><b data-trans="sms_chat_input_confirm">' + this.results_none_found + '</b> <span></span></li>');
+      this.search_results.append(no_results_html);
+      $(".no-results").translate();
+      //return this.search_results;
+	  return this.form_field_jq.trigger("chosen:no_results", {
+        chosen: this
+      });
+    };
+
+    Chosen.prototype.no_results_clear = function() {
+      return this.search_results.find(".no-results").remove();
+    };
+
+    Chosen.prototype.keydown_arrow = function() {
+      var next_sib;
+      if (this.results_showing && this.result_highlight) {
+        next_sib = this.result_highlight.nextAll("li.active-result").first();
+        if (next_sib) {
+          return this.result_do_highlight(next_sib);
+        }
+      } else {
+        return this.results_show();
+      }
+    };
+
+    Chosen.prototype.keyup_arrow = function() {
+      var prev_sibs;
+      if (!this.results_showing && !this.is_multiple) {
+        return this.results_show();
+      } else if (this.result_highlight) {
+        prev_sibs = this.result_highlight.prevAll("li.active-result");
+        if (prev_sibs.length) {
+          return this.result_do_highlight(prev_sibs.first());
+        } else {
+          if (this.choices_count() > 0) {
+            this.results_hide();
+          }
+          return this.result_clear_highlight();
+        }
+      }
+    };
+
+    Chosen.prototype.keydown_backstroke = function() {
+      var next_available_destroy;
+      if (this.pending_backstroke) {
+        this.choice_destroy(this.pending_backstroke.find("a").first());
+        return this.clear_backstroke();
+      } else {
+        next_available_destroy = this.search_container.siblings("li.search-choice").last();
+        if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) {
+          this.pending_backstroke = next_available_destroy;
+          if (this.single_backstroke_delete) {
+            return this.keydown_backstroke();
+          } else {
+            return this.pending_backstroke.addClass("search-choice-focus");
+          }
+        }
+      }
+    };
+
+    Chosen.prototype.clear_backstroke = function() {
+      if (this.pending_backstroke) {
+        this.pending_backstroke.removeClass("search-choice-focus");
+      }
+      return this.pending_backstroke = null;
+    };
+
+    Chosen.prototype.keydown_checker = function(evt) {
+      var stroke, _ref1;
+      stroke = (_ref1 = evt.which) != null ? _ref1 : evt.keyCode;
+      this.search_field_scale();
+      if (stroke !== 8 && this.pending_backstroke) {
+        this.clear_backstroke();
+      }
+      switch (stroke) {
+        case 8:
+          this.backstroke_length = this.search_field.val().length;
+          break;
+        case 9:
+          if (this.results_showing && !this.is_multiple) {
+            this.result_select(evt);
+          }
+          this.mouse_on_container = false;
+          break;
+        case 13:
+          if (this.results_showing) {
+            evt.preventDefault();
+          }
+          break;
+        case 32:
+          if (this.disable_search) {
+            evt.preventDefault();
+          }
+          break;
+        case 38:
+          evt.preventDefault();
+          this.keyup_arrow();
+          break;
+        case 40:
+          evt.preventDefault();
+          this.keydown_arrow();
+          break;
+        case 59:
+        case 186:
+		  if(this.search_field.val().length < 3){
+			evt.preventDefault();
+		  }
+          break;
+      }
+    };
+
+    Chosen.prototype.search_field_scale = function() {
+      var div, f_width, h, style, style_block, styles, w, _i, _len;
+      if (this.is_multiple) {
+        h = 0;
+        w = 0;
+        style_block = "position:absolute; left: -1000px; top: -1000px; display:none;";
+        styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing'];
+        for (_i = 0, _len = styles.length; _i < _len; _i++) {
+          style = styles[_i];
+          style_block += style + ":" + this.search_field.css(style) + ";";
+        }
+        div = $('<div />', {
+          'style': style_block
+        });
+        div.text(this.search_field.val());
+        $('body').append(div);
+        w = div.width() + 25;
+        div.remove();
+        f_width = this.container.outerWidth();//1.6.2
+        if (w > f_width - 10) {
+          w = f_width - 10;
+        }
+        return this.search_field.css({
+          'width': w + 'px'
+        });
+      }
+    };
+
+    Chosen.prototype.generate_random_id = function() {
+      var string;
+      string = "sel" + this.generate_random_char() + this.generate_random_char() + this.generate_random_char();
+      while ($("#" + string).length > 0) {
+        string += this.generate_random_char();
+      }
+      return string;
+    };
+
+    return Chosen;
+
+  })(AbstractChosen);
+
+}).call(this);
diff --git a/ap/app/zte_webui/js/3rd/jquery.fileinput.js b/ap/app/zte_webui/js/3rd/jquery.fileinput.js
new file mode 100755
index 0000000..80971a1
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.fileinput.js
@@ -0,0 +1,104 @@
+/**
+ * --------------------------------------------------------------------
+ * jQuery customfileinput plugin
+ * Author: Scott Jehl, scott@filamentgroup.com
+ * Copyright (c) 2009 Filament Group 
+ * licensed under MIT (filamentgroup.com/examples/mit-license.txt)
+ * --------------------------------------------------------------------
+ */
+$.fn.customFileInput = function(){
+	var isChanged = false;
+    var maxLength = 32;
+	//apply events and styles for file input element
+	var fileInput = $(this)
+		.addClass('customfile-input') //add class for CSS
+		.mouseover(function(){ upload.addClass('customfile-hover'); })
+		.mouseout(function(){ upload.removeClass('customfile-hover'); })
+		.focus(function(){
+			upload.addClass('customfile-focus');
+			fileInput.data('val', fileInput.val());
+		})
+		.blur(function(){ 
+			upload.removeClass('customfile-focus');
+			$(this).trigger('checkChange');
+		 })
+		 .bind('disable',function(){
+		 	fileInput.attr('disabled',true);
+			upload.addClass('customfile-disabled');
+		})
+		.bind('enable',function(){
+			fileInput.removeAttr('disabled');
+			upload.removeClass('customfile-disabled');
+		})
+		.bind('checkChange', function(){
+			if(fileInput.val() && fileInput.val() != fileInput.data('val')){
+				fileInput.trigger('change');
+			}
+		})
+		.bind('change',function(){
+			isChanged = true;
+			//get file name
+			var fileName = $(this).val().split(/\\/).pop();
+			//get file extension
+			var fileExt = 'icon-' + getFileType(fileName);//'customfile-ext-' + fileName.split('.').pop().toLowerCase();
+			//update the feedback
+            var tmpFileName = '';
+            var checkLen = 0;
+            for(var i = 0; i < fileName.length && checkLen < maxLength; i++){
+                var c = fileName.charAt(i);
+                if(getEncodeType(c).encodeType == 'UNICODE'){
+                    checkLen += 3;
+                }else{
+                    checkLen += 1;
+                }
+                tmpFileName += c;
+            }
+            if(fileName != tmpFileName){
+                tmpFileName = tmpFileName + '...';
+            } else {
+                tmpFileName = fileName;
+            }
+			uploadFeedback
+				.html(HTMLEncode(tmpFileName)) //set feedback text to filename
+				.removeClass(uploadFeedback.data('fileExt') || '') //remove any existing file extension class
+				.addClass(fileExt) //add file extension class
+				.data('fileExt', fileExt) //store file extension for class removal on next change
+				.addClass('customfile-feedback-populated'); //add class to show populated state
+            upload.attr('title', fileName);
+			//change text of button	
+			uploadButton.html("<span id='uploadBtn' data-trans='change_btn'>"+$.i18n.prop('change_btn')+"</span>");
+		})
+		.click(function(){ //for IE and Opera, make sure change fires after choosing a file, using an async callback
+			fileInput.data('val', fileInput.val());
+			setTimeout(function(){
+				fileInput.trigger('checkChange');
+			},100);
+		});
+		
+	//create custom control container
+	var upload = $('<div class="customfile"></div>');
+	//create custom control button
+	var uploadButton = $('<span class="customfile-button" aria-hidden="true"><span  id="uploadBtn" data-trans="browse_btn">'+$.i18n.prop('browse_btn')+'</span></span>').appendTo(upload);
+	//create custom control feedback
+	var uploadFeedback = $('<span class="customfile-feedback" aria-hidden="true"><span data-trans="no_file_selected">'+$.i18n.prop("no_file_selected")+'</span></span>').appendTo(upload);
+	
+	//match disabled state
+	if(fileInput.is('[disabled]')){
+		fileInput.trigger('disable');
+	}
+
+	//on mousemove, keep file input under the cursor to steal click
+	upload
+		.mousemove(function(e){
+			fileInput.css({
+				'left': e.pageX - upload.offset().left - fileInput.outerWidth() + 20, //position right side 20px right of cursor X)
+                'top': e.pageY - upload.offset().top - 14
+			});	
+		})
+		.insertAfter(fileInput); //insert after the input
+	
+	fileInput.appendTo(upload);
+		
+	//return jQuery
+	return $(this);
+};
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/jquery.i18n.js b/ap/app/zte_webui/js/3rd/jquery.i18n.js
new file mode 100755
index 0000000..547a753
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.i18n.js
@@ -0,0 +1,471 @@
+/******************************************************************************
+ * jquery.i18n.properties
+ * 
+ * Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and 
+ * MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+ * 
+ * @version     1.1.x
+ * @author      Nuno Fernandes
+ *              Matthew Lohbihler
+ * @url         www.codingwithcoffee.com
+ * @inspiration Localisation assistance for jQuery (http://keith-wood.name/localisation.html)
+ *              by Keith Wood (kbwood{at}iinet.com.au) June 2007
+ * 
+ *****************************************************************************/
+
+(function($) {
+$.i18n = {};
+
+/** Map holding bundle keys (if mode: 'map') */
+$.i18n.map = {};
+    
+/**
+ * Load and parse message bundle files (.properties),
+ * making bundles keys available as javascript variables.
+ * 
+ * i18n files are named <name>.js, or <name>_<language>.js or <name>_<language>_<country>.js
+ * Where:
+ *      The <language> argument is a valid ISO Language Code. These codes are the lower-case, 
+ *      two-letter codes as defined by ISO-639. You can find a full list of these codes at a 
+ *      number of sites, such as: http://www.loc.gov/standards/iso639-2/englangn.html
+ *      The <country> argument is a valid ISO Country Code. These codes are the upper-case,
+ *      two-letter codes as defined by ISO-3166. You can find a full list of these codes at a
+ *      number of sites, such as: http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
+ * 
+ * Sample usage for a bundles/Messages.properties bundle:
+ * $.i18n.properties({
+ *      name:      'Messages', 
+ *      language:  'en_US',
+ *      path:      'bundles'
+ * });
+ * @param  name			(string/string[], optional) names of file to load (eg, 'Messages' or ['Msg1','Msg2']). Defaults to "Messages"
+ * @param  language		(string, optional) language/country code (eg, 'en', 'en_US', 'pt_PT'). if not specified, language reported by the browser will be used instead.
+ * @param  path			(string, optional) path of directory that contains file to load
+ * @param  mode			(string, optional) whether bundles keys are available as JavaScript variables/functions or as a map (eg, 'vars' or 'map')
+ * @param  cache        (boolean, optional) whether bundles should be cached by the browser, or forcibly reloaded on each page load. Defaults to false (i.e. forcibly reloaded)
+ * @param  encoding 	(string, optional) the encoding to request for bundles. Property file resource bundles are specified to be in ISO-8859-1 format. Defaults to UTF-8 for backward compatibility.
+ * @param  callback     (function, optional) callback function to be called after script is terminated
+ */
+$.i18n.properties = function(settings) {
+	// set up settings
+    var defaults = {
+        name:           'Messages',
+        language:       '',
+        path:           '',  
+        mode:           'vars',
+        cache:			false,
+        encoding:       'UTF-8',
+        callback:       null
+    };
+    settings = $.extend(defaults, settings);    
+    if(settings.language === null || settings.language == '') {
+	   settings.language = $.i18n.browserLang();
+	}
+	if(settings.language === null) {settings.language='';}
+	
+	// load and parse bundle files
+	var files = getFiles(settings.name);
+	for(i=0; i<files.length; i++) {
+		// 1. load base (eg, Messages.properties)
+		//loadAndParseFile(settings.path + files[i] + '.properties', settings);
+        // 2. with language code (eg, Messages_pt.properties)
+//		if(settings.language.length >= 2) {
+//            loadAndParseFile(settings.path + files[i] + '_' + settings.language.substring(0, 2) +'.properties', settings);
+//		}
+		// 3. with language code and country code (eg, Messages_pt_PT.properties)
+        if(settings.language.length >= 2) {
+            loadAndParseFile(settings.path + files[i] + '_' + settings.language.substring(0, 5) +'.properties', settings);
+        }
+	}
+	
+	// call callback
+	if(settings.callback){ settings.callback(); }
+};
+
+
+/**
+ * When configured with mode: 'map', allows access to bundle values by specifying its key.
+ * Eg, jQuery.i18n.prop('com.company.bundles.menu_add')
+ */
+$.i18n.prop = function(key /* Add parameters as function arguments as necessary  */) {
+	var value = $.i18n.map[key];
+	if (value == null)
+		return key;
+	
+	var phvList;
+	if (arguments.length == 2 && $.isArray(arguments[1]))
+		// An array was passed as the only parameter, so assume it is the list of place holder values.
+		phvList = arguments[1];
+
+	// Place holder replacement
+	/**
+	 * Tested with:
+	 *   test.t1=asdf ''{0}''
+	 *   test.t2=asdf '{0}' '{1}'{1}'zxcv
+	 *   test.t3=This is \"a quote" 'a''{0}''s'd{fgh{ij'
+	 *   test.t4="'''{'0}''" {0}{a}
+	 *   test.t5="'''{0}'''" {1}
+	 *   test.t6=a {1} b {0} c
+	 *   test.t7=a 'quoted \\ s\ttringy' \t\t x
+	 *
+	 * Produces:
+	 *   test.t1, p1 ==> asdf 'p1'
+	 *   test.t2, p1 ==> asdf {0} {1}{1}zxcv
+	 *   test.t3, p1 ==> This is "a quote" a'{0}'sd{fgh{ij
+	 *   test.t4, p1 ==> "'{0}'" p1{a}
+	 *   test.t5, p1 ==> "'{0}'" {1}
+	 *   test.t6, p1 ==> a {1} b p1 c
+	 *   test.t6, p1, p2 ==> a p2 b p1 c
+	 *   test.t6, p1, p2, p3 ==> a p2 b p1 c
+	 *   test.t7 ==> a quoted \ s	tringy 		 x
+	 */
+	
+	var i;
+	if (typeof(value) == 'string') {
+        // Handle escape characters. Done separately from the tokenizing loop below because escape characters are 
+		// active in quoted strings.
+        i = 0;
+        while ((i = value.indexOf('\\', i)) != -1) {
+ 		    if (value.charAt(i+1) == 't')
+ 			    value = value.substring(0, i) + '\t' + value.substring((i++) + 2); // tab
+ 		    else if (value.charAt(i+1) == 'r')
+ 			    value = value.substring(0, i) + '\r' + value.substring((i++) + 2); // return
+ 		    else if (value.charAt(i+1) == 'n')
+ 			    value = value.substring(0, i) + '\n' + value.substring((i++) + 2); // line feed
+ 		    else if (value.charAt(i+1) == 'f')
+ 			    value = value.substring(0, i) + '\f' + value.substring((i++) + 2); // form feed
+ 		    else if (value.charAt(i+1) == '\\')
+ 			    value = value.substring(0, i) + '\\' + value.substring((i++) + 2); // \
+ 		    else
+ 			    value = value.substring(0, i) + value.substring(i+1); // Quietly drop the character
+        }
+		
+		// Lazily convert the string to a list of tokens.
+		var arr = [], j, index;
+		i = 0;
+		while (i < value.length) {
+			if (value.charAt(i) == '\'') {
+				// Handle quotes
+				if (i == value.length-1)
+					value = value.substring(0, i); // Silently drop the trailing quote
+				else if (value.charAt(i+1) == '\'')
+					value = value.substring(0, i) + value.substring(++i); // Escaped quote
+				else {
+					// Quoted string
+					j = i + 2;
+					while ((j = value.indexOf('\'', j)) != -1) {
+						if (j == value.length-1 || value.charAt(j+1) != '\'') {
+							// Found start and end quotes. Remove them
+							value = value.substring(0,i) + value.substring(i+1, j) + value.substring(j+1);
+							i = j - 1;
+							break;
+						}
+						else {
+							// Found a double quote, reduce to a single quote.
+							value = value.substring(0,j) + value.substring(++j);
+						}
+					}
+					
+					if (j == -1) {
+						// There is no end quote. Drop the start quote
+						value = value.substring(0,i) + value.substring(i+1);
+					}
+				}
+			}
+			else if (value.charAt(i) == '{') {
+				// Beginning of an unquoted place holder.
+				j = value.indexOf('}', i+1);
+				if (j == -1)
+					i++; // No end. Process the rest of the line. Java would throw an exception
+				else {
+					// Add 1 to the index so that it aligns with the function arguments.
+					index = parseInt(value.substring(i+1, j));
+					if (!isNaN(index) && index >= 0) {
+						// Put the line thus far (if it isn't empty) into the array
+						var s = value.substring(0, i);
+						if (s != "")
+							arr.push(s);
+						// Put the parameter reference into the array
+						arr.push(index);
+						// Start the processing over again starting from the rest of the line.
+						i = 0;
+						value = value.substring(j+1);
+					}
+					else
+						i = j + 1; // Invalid parameter. Leave as is.
+				}
+			}
+			else
+				i++;
+		}
+		
+		// Put the remainder of the no-empty line into the array.
+		if (value != "")
+			arr.push(value);
+		value = arr;
+		
+		// Make the array the value for the entry.
+		$.i18n.map[key] = arr;
+	}
+	
+	if (value.length == 0)
+		return "";
+	if (value.lengh == 1 && typeof(value[0]) == "string")
+		return value[0];
+	
+	var s = "";
+	for (i=0; i<value.length; i++) {
+		if (typeof(value[i]) == "string")
+			s += value[i];
+		// Must be a number
+		else if (phvList && value[i] < phvList.length)
+			s += phvList[value[i]];
+		else if (!phvList && value[i] + 1 < arguments.length)
+			s += arguments[value[i] + 1];
+		else
+			s += "{"+ value[i] +"}";
+	}
+	
+	return s;
+};
+
+/** Language reported by browser, normalized code */
+$.i18n.browserLang = function() {
+	return normaliseLanguageCode(navigator.language /* Mozilla */ || navigator.userLanguage /* IE */);
+};
+
+
+/** Load and parse .properties files */
+function loadAndParseFile(filename, settings) {
+	$.ajax({
+        url:        filename,
+        async:      false,
+        cache:		settings.cache,
+        contentType:'text/plain;charset='+ settings.encoding,
+        dataType:   'text',
+        success:    function(data, status) {
+        				parseData(data, settings.mode); 
+					}
+    });
+}
+
+/** Parse .properties files */
+function parseData(data, mode) {
+   var parsed = '';
+   var parameters = data.split( /\n/ );
+   var regPlaceHolder = /(\{\d+\})/g;
+   var regRepPlaceHolder = /\{(\d+)\}/g;
+   var unicodeRE = /(\\u.{4})/ig;
+   for(var i=0; i<parameters.length; i++ ) {
+       parameters[i] = parameters[i].replace( /^\s\s*/, '' ).replace( /\s\s*$/, '' ); // trim
+       if(parameters[i].length > 0 && parameters[i].match("^#")!="#") { // skip comments
+           var pair = parameters[i].split('=');
+           if(pair.length > 0) {
+               /** Process key & value */
+               var name = unescape(pair[0]).replace( /^\s\s*/, '' ).replace( /\s\s*$/, '' ); // trim
+               var value = pair.length == 1 ? "" : pair[1];
+               // process multi-line values
+               while(value.match(/\\$/)=="\\") {
+               		value = value.substring(0, value.length - 1);
+               		value += parameters[++i].replace( /\s\s*$/, '' ); // right trim
+               }               
+               // Put values with embedded '='s back together
+               for(var s=2;s<pair.length;s++){ value +='=' + pair[s]; }
+               value = value.replace( /^\s\s*/, '' ).replace( /\s\s*$/, '' ); // trim
+               
+               /** Mode: bundle keys in a map */
+               if(mode == 'map' || mode == 'both') {
+                   // handle unicode chars possibly left out
+                   var unicodeMatches = value.match(unicodeRE);
+                   if(unicodeMatches) {
+                     for(var u=0; u<unicodeMatches.length; u++) {
+                        value = value.replace( unicodeMatches[u], unescapeUnicode(unicodeMatches[u]));
+                     }
+                   }
+                   // add to map
+                   $.i18n.map[name] = value;
+               }
+               
+               /** Mode: bundle keys as vars/functions */
+               if(mode == 'vars' || mode == 'both') {
+                   value = value.replace( /"/g, '\\"' ); // escape quotation mark (")
+                   
+                   // make sure namespaced key exists (eg, 'some.key') 
+                   checkKeyNamespace(name);
+                   
+                   // value with variable substitutions
+                   if(regPlaceHolder.test(value)) {
+                       var parts = value.split(regPlaceHolder);
+                       // process function args
+                       var first = true;
+                       var fnArgs = '';
+                       var usedArgs = [];
+                       for(var p=0; p<parts.length; p++) {
+                           if(regPlaceHolder.test(parts[p]) && (usedArgs.length == 0 || usedArgs.indexOf(parts[p]) == -1)) {
+                               if(!first) {fnArgs += ',';}
+                               fnArgs += parts[p].replace(regRepPlaceHolder, 'v$1');
+                               usedArgs.push(parts[p]);
+                               first = false;
+                           }
+                       }
+                       parsed += name + '=function(' + fnArgs + '){';
+                       // process function body
+                       var fnExpr = '"' + value.replace(regRepPlaceHolder, '"+v$1+"') + '"';
+                       parsed += 'return ' + fnExpr + ';' + '};';
+                       
+                   // simple value
+                   }else{
+                       parsed += name+'="'+value+'";';
+                   }
+               } // END: Mode: bundle keys as vars/functions
+           } // END: if(pair.length > 0)
+       } // END: skip comments
+   }
+   eval(parsed);
+}
+
+/** Make sure namespace exists (for keys with dots in name) */
+// TODO key parts that start with numbers quietly fail. i.e. month.short.1=Jan
+function checkKeyNamespace(key) {
+	var regDot = /\./;
+	if(regDot.test(key)) {
+		var fullname = '';
+		var names = key.split( /\./ );
+		for(var i=0; i<names.length; i++) {
+			if(i>0) {fullname += '.';}
+			fullname += names[i];
+			if(eval('typeof '+fullname+' == "undefined"')) {
+				eval(fullname + '={};');
+			}
+		}
+	}
+}
+
+/** Make sure filename is an array */
+function getFiles(names) {
+	return (names && names.constructor == Array) ? names : [names];
+}
+
+/** Ensure language code is in the format aa_AA. */
+function normaliseLanguageCode(lang) {
+    lang = lang.toLowerCase();
+    if(lang.length > 3) {
+        lang = lang.substring(0, 3) + lang.substring(3).toUpperCase();
+    }
+    return lang;
+}
+
+/** Unescape unicode chars ('\u00e3') */
+function unescapeUnicode(str) {
+  // unescape unicode codes
+  var codes = [];
+  var code = parseInt(str.substr(2), 16);
+  if (code >= 0 && code < Math.pow(2, 16)) {
+     codes.push(code);
+  }
+  // convert codes to text
+  var unescaped = '';
+  for (var i = 0; i < codes.length; ++i) {
+    unescaped += String.fromCharCode(codes[i]);
+  }
+  return unescaped;
+}
+
+/* Cross-Browser Split 1.0.1
+(c) Steven Levithan <stevenlevithan.com>; MIT License
+An ECMA-compliant, uniform cross-browser split method */
+var cbSplit;
+// avoid running twice, which would break `cbSplit._nativeSplit`'s reference to the native `split`
+if (!cbSplit) {    
+  cbSplit = function(str, separator, limit) {
+      // if `separator` is not a regex, use the native `split`
+      if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
+        if(typeof cbSplit._nativeSplit == "undefined")
+          return str.split(separator, limit);
+        else
+          return cbSplit._nativeSplit.call(str, separator, limit);
+      }
+  
+      var output = [],
+          lastLastIndex = 0,
+          flags = (separator.ignoreCase ? "i" : "") +
+                  (separator.multiline  ? "m" : "") +
+                  (separator.sticky     ? "y" : ""),
+          separator = RegExp(separator.source, flags + "g"), // make `global` and avoid `lastIndex` issues by working with a copy
+          separator2, match, lastIndex, lastLength;
+  
+      str = str + ""; // type conversion
+      if (!cbSplit._compliantExecNpcg) {
+          separator2 = RegExp("^" + separator.source + "$(?!\\s)", flags); // doesn't need /g or /y, but they don't hurt
+      }
+  
+      /* behavior for `limit`: if it's...
+      - `undefined`: no limit.
+      - `NaN` or zero: return an empty array.
+      - a positive number: use `Math.floor(limit)`.
+      - a negative number: no limit.
+      - other: type-convert, then use the above rules. */
+      if (limit === undefined || +limit < 0) {
+          limit = Infinity;
+      } else {
+          limit = Math.floor(+limit);
+          if (!limit) {
+              return [];
+          }
+      }
+  
+      while (match = separator.exec(str)) {
+          lastIndex = match.index + match[0].length; // `separator.lastIndex` is not reliable cross-browser
+  
+          if (lastIndex > lastLastIndex) {
+              output.push(str.slice(lastLastIndex, match.index));
+  
+              // fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
+              if (!cbSplit._compliantExecNpcg && match.length > 1) {
+                  match[0].replace(separator2, function () {
+                      for (var i = 1; i < arguments.length - 2; i++) {
+                          if (arguments[i] === undefined) {
+                              match[i] = undefined;
+                          }
+                      }
+                  });
+              }
+  
+              if (match.length > 1 && match.index < str.length) {
+                  Array.prototype.push.apply(output, match.slice(1));
+              }
+  
+              lastLength = match[0].length;
+              lastLastIndex = lastIndex;
+  
+              if (output.length >= limit) {
+                  break;
+              }
+          }
+  
+          if (separator.lastIndex === match.index) {
+              separator.lastIndex++; // avoid an infinite loop
+          }
+      }
+  
+      if (lastLastIndex === str.length) {
+          if (lastLength || !separator.test("")) {
+              output.push("");
+          }
+      } else {
+          output.push(str.slice(lastLastIndex));
+      }
+  
+      return output.length > limit ? output.slice(0, limit) : output;
+  };
+  
+  cbSplit._compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group
+  cbSplit._nativeSplit = String.prototype.split;
+
+} // end `if (!cbSplit)`
+String.prototype.split = function (separator, limit) {
+    return cbSplit(this, separator, limit);
+};
+
+})(jQuery);
+                
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/jquery.simplemodal.js b/ap/app/zte_webui/js/3rd/jquery.simplemodal.js
new file mode 100755
index 0000000..9e9d5a4
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.simplemodal.js
@@ -0,0 +1,712 @@
+/*

+ * SimpleModal 1.4.2 - jQuery Plugin

+ * http://simplemodal.com/

+ * Copyright (c) 2011 Eric Martin

+ * Licensed under MIT and GPL

+ * Date: Sat, Dec 17 2011 15:35:38 -0800

+ */

+

+/**

+ * SimpleModal is a lightweight jQuery plugin that provides a simple

+ * interface to create a modal dialog.

+ *

+ * The goal of SimpleModal is to provide developers with a cross-browser

+ * overlay and container that will be populated with data provided to

+ * SimpleModal.

+ *

+ * There are two ways to call SimpleModal:

+ * 1) As a chained function on a jQuery object, like $('#myDiv').modal();.

+ * This call would place the DOM object, #myDiv, inside a modal dialog.

+ * Chaining requires a jQuery object. An optional options object can be

+ * passed as a parameter.

+ *

+ * @example $('<div>my data</div>').modal({options});

+ * @example $('#myDiv').modal({options});

+ * @example jQueryObject.modal({options});

+ *

+ * 2) As a stand-alone function, like $.modal(data). The data parameter

+ * is required and an optional options object can be passed as a second

+ * parameter. This method provides more flexibility in the types of data

+ * that are allowed. The data could be a DOM object, a jQuery object, HTML

+ * or a string.

+ *

+ * @example $.modal('<div>my data</div>', {options});

+ * @example $.modal('my data', {options});

+ * @example $.modal($('#myDiv'), {options});

+ * @example $.modal(jQueryObject, {options});

+ * @example $.modal(document.getElementById('myDiv'), {options});

+ *

+ * A SimpleModal call can contain multiple elements, but only one modal

+ * dialog can be created at a time. Which means that all of the matched

+ * elements will be displayed within the modal container.

+ *

+ * SimpleModal internally sets the CSS needed to display the modal dialog

+ * properly in all browsers, yet provides the developer with the flexibility

+ * to easily control the look and feel. The styling for SimpleModal can be

+ * done through external stylesheets, or through SimpleModal, using the

+ * overlayCss, containerCss, and dataCss options.

+ *

+ * SimpleModal has been tested in the following browsers:

+ * - IE 6+

+ * - Firefox 2+

+ * - Opera 9+

+ * - Safari 3+

+ * - Chrome 1+

+ *

+ * @name SimpleModal

+ * @type jQuery

+ * @requires jQuery v1.2.4

+ * @cat Plugins/Windows and Overlays

+ * @author Eric Martin (http://ericmmartin.com)

+ * @version 1.4.2

+ */

+

+;(function (factory) {

+	if (typeof define === 'function' && define.amd) {

+		// AMD. Register as an anonymous module.

+		define(['jquery'], factory);

+	} else {

+		// Browser globals

+		factory(jQuery);

+	}

+}

+(function ($) {

+	var d = [],

+		doc = $(document),

+		ie6 = $.browser.msie && parseInt($.browser.version) === 6 && typeof window['XMLHttpRequest'] !== 'object',

+		ie7 = $.browser.msie && parseInt($.browser.version) === 7,

+		ieQuirks = null,

+		wndw = $(window),

+		w = [];

+

+	/*

+	 * Create and display a modal dialog.

+	 *

+	 * @param {string, object} data A string, jQuery object or DOM object

+	 * @param {object} [options] An optional object containing options overrides

+	 */

+	$.modal = function (data, options) {

+		return $.modal.impl.init(data, options);

+	};

+

+	/*

+	 * Close the modal dialog.

+	 */

+	$.modal.close = function () {

+		$.modal.impl.close();

+	};

+

+	/*

+	 * Set focus on first or last visible input in the modal dialog. To focus on the last

+	 * element, call $.modal.focus('last'). If no input elements are found, focus is placed

+	 * on the data wrapper element.

+	 */

+	$.modal.focus = function (pos) {

+		$.modal.impl.focus(pos);

+	};

+

+	/*

+	 * Determine and set the dimensions of the modal dialog container.

+	 * setPosition() is called if the autoPosition option is true.

+	 */

+	$.modal.setContainerDimensions = function () {

+		$.modal.impl.setContainerDimensions();

+	};

+

+	/*

+	 * Re-position the modal dialog.

+	 */

+	$.modal.setPosition = function () {

+		$.modal.impl.setPosition();

+	};

+

+	/*

+	 * Update the modal dialog. If new dimensions are passed, they will be used to determine

+	 * the dimensions of the container.

+	 *

+	 * setContainerDimensions() is called, which in turn calls setPosition(), if enabled.

+	 * Lastly, focus() is called is the focus option is true.

+	 */

+	$.modal.update = function (height, width) {

+		$.modal.impl.update(height, width);

+	};

+

+	/*

+	 * Chained function to create a modal dialog.

+	 *

+	 * @param {object} [options] An optional object containing options overrides

+	 */

+	$.fn.modal = function (options) {

+		return $.modal.impl.init(this, options);

+	};

+

+	/*

+	 * SimpleModal default options

+	 *

+	 * appendTo:		(String:'body') The jQuery selector to append the elements to. For .NET, use 'form'.

+	 * focus:			(Boolean:true) Focus in the first visible, enabled element?

+	 * opacity:			(Number:50) The opacity value for the overlay div, from 0 - 100

+	 * overlayId:		(String:'simplemodal-overlay') The DOM element id for the overlay div

+	 * overlayCss:		(Object:{}) The CSS styling for the overlay div

+	 * containerId:		(String:'simplemodal-container') The DOM element id for the container div

+	 * containerCss:	(Object:{}) The CSS styling for the container div

+	 * dataId:			(String:'simplemodal-data') The DOM element id for the data div

+	 * dataCss:			(Object:{}) The CSS styling for the data div

+	 * minHeight:		(Number:null) The minimum height for the container

+	 * minWidth:		(Number:null) The minimum width for the container

+	 * maxHeight:		(Number:null) The maximum height for the container. If not specified, the window height is used.

+	 * maxWidth:		(Number:null) The maximum width for the container. If not specified, the window width is used.

+	 * autoResize:		(Boolean:false) Automatically resize the container if it exceeds the browser window dimensions?

+	 * autoPosition:	(Boolean:true) Automatically position the container upon creation and on window resize?

+	 * zIndex:			(Number: 1000) Starting z-index value

+	 * close:			(Boolean:true) If true, closeHTML, escClose and overClose will be used if set.

+	 							If false, none of them will be used.

+	 * closeHTML:		(String:'<a class="modalCloseImg" title="Close"></a>') The HTML for the default close link.

+								SimpleModal will automatically add the closeClass to this element.

+	 * closeClass:		(String:'simplemodal-close') The CSS class used to bind to the close event

+	 * escClose:		(Boolean:true) Allow Esc keypress to close the dialog?

+	 * overlayClose:	(Boolean:false) Allow click on overlay to close the dialog?

+	 * fixed:			(Boolean:true) If true, the container will use a fixed position. If false, it will use a

+								absolute position (the dialog will scroll with the page)

+	 * position:		(Array:null) Position of container [top, left]. Can be number of pixels or percentage

+	 * persist:			(Boolean:false) Persist the data across modal calls? Only used for existing

+								DOM elements. If true, the data will be maintained across modal calls, if false,

+								the data will be reverted to its original state.

+	 * modal:			(Boolean:true) User will be unable to interact with the page below the modal or tab away from the dialog.

+								If false, the overlay, iframe, and certain events will be disabled allowing the user to interact

+								with the page below the dialog.

+	 * onOpen:			(Function:null) The callback function used in place of SimpleModal's open

+	 * onShow:			(Function:null) The callback function used after the modal dialog has opened

+	 * onClose:			(Function:null) The callback function used in place of SimpleModal's close

+	 */

+	$.modal.defaults = {

+		appendTo: 'body',

+		focus: true,

+		opacity: 50,

+		overlayId: 'simplemodal-overlay',

+		overlayCss: {},

+		containerId: 'simplemodal-container',

+		containerCss: {},

+		dataId: 'simplemodal-data',

+		dataCss: {},

+		minHeight: null,

+		minWidth: null,

+		maxHeight: null,

+		maxWidth: null,

+		autoResize: false,

+		autoPosition: true,

+		zIndex: 1000,

+		close: true,

+		closeHTML: '<a class="modalCloseImg" title="Close"></a>',

+		closeClass: 'simplemodal-close',

+		escClose: true,

+		overlayClose: false,

+		fixed: true,

+		position: null,

+		persist: false,

+		modal: true,

+		onOpen: null,

+		onShow: null,

+		onClose: null

+	};

+

+	/*

+	 * Main modal object

+	 * o = options

+	 */

+	$.modal.impl = {

+		/*

+		 * Contains the modal dialog elements and is the object passed

+		 * back to the callback (onOpen, onShow, onClose) functions

+		 */

+		d: {},

+		/*

+		 * Initialize the modal dialog

+		 */

+		init: function (data, options) {

+			var s = this;

+

+			// don't allow multiple calls

+			if (s.d.data) {

+				return false;

+			}

+

+			// $.boxModel is undefined if checked earlier

+			ieQuirks = $.browser.msie && !$.boxModel;

+

+			// merge defaults and user options

+			s.o = $.extend({}, $.modal.defaults, options);

+

+			// keep track of z-index

+			s.zIndex = s.o.zIndex;

+

+			// set the onClose callback flag

+			s.occb = false;

+

+			// determine how to handle the data based on its type

+			if (typeof data === 'object') {

+				// convert DOM object to a jQuery object

+				data = data instanceof jQuery ? data : $(data);

+				s.d.placeholder = false;

+

+				// if the object came from the DOM, keep track of its parent

+				if (data.parent().parent().size() > 0) {

+					data.before($('<span></span>')

+						.attr('id', 'simplemodal-placeholder')

+						.css({display: 'none'}));

+

+					s.d.placeholder = true;

+					s.display = data.css('display');

+

+					// persist changes? if not, make a clone of the element

+					if (!s.o.persist) {

+						s.d.orig = data.clone(true);

+					}

+				}

+			}

+			else if (typeof data === 'string' || typeof data === 'number') {

+				// just insert the data as innerHTML

+				data = $('<div></div>').html(data);

+			}

+			else {

+				// unsupported data type!

+				alert('SimpleModal Error: Unsupported data type: ' + typeof data);

+				return s;

+			}

+

+			// create the modal overlay, container and, if necessary, iframe

+			s.create(data);

+			data = null;

+

+			// display the modal dialog

+			s.open();

+

+			// useful for adding events/manipulating data in the modal dialog

+			if ($.isFunction(s.o.onShow)) {

+				s.o.onShow.apply(s, [s.d]);

+			}

+

+			// don't break the chain =)

+			return s;

+		},

+		/*

+		 * Create and add the modal overlay and container to the page

+		 */

+		create: function (data) {

+			var s = this;

+

+			// get the window properties

+			s.getDimensions();

+

+			// add an iframe to prevent select options from bleeding through

+			if (s.o.modal && ie6) {

+				s.d.iframe = $('<iframe src="javascript:false;"></iframe>')

+					.css($.extend(s.o.iframeCss, {

+						display: 'none',

+						opacity: 0,

+						position: 'fixed',

+						height: w[0],

+						width: w[1],

+						zIndex: s.o.zIndex,

+						top: 0,

+						left: 0

+					}))

+					.appendTo(s.o.appendTo);

+			}

+

+			// create the overlay

+			s.d.overlay = $('<div></div>')

+				.attr('id', s.o.overlayId)

+				.addClass('simplemodal-overlay')

+				.css($.extend(s.o.overlayCss, {

+					display: 'none',

+					opacity: s.o.opacity / 100,

+					height: s.o.modal ? d[0] : 0,

+					width: s.o.modal ? d[1] : 0,

+					position: 'fixed',

+					left: 0,

+					top: 0,

+					zIndex: s.o.zIndex + 1

+				}))

+				.appendTo(s.o.appendTo);

+

+			// create the container

+			s.d.container = $('<div></div>')

+				.attr('id', s.o.containerId)

+				.addClass('simplemodal-container')

+				.css($.extend(

+					{position: s.o.fixed ? 'fixed' : 'absolute'},

+					s.o.containerCss,

+					{display: 'none', zIndex: s.o.zIndex + 2}

+				))

+				.append(s.o.close && s.o.closeHTML

+					? $(s.o.closeHTML).addClass(s.o.closeClass)

+					: '')

+				.appendTo(s.o.appendTo);

+

+			s.d.wrap = $('<div></div>')

+				.attr('tabIndex', -1)

+				.addClass('simplemodal-wrap')

+				.css({height: '100%', outline: 0, width: '100%'})

+				.appendTo(s.d.container);

+

+			// add styling and attributes to the data

+			// append to body to get correct dimensions, then move to wrap

+			s.d.data = data

+				.attr('id', data.attr('id') || s.o.dataId)

+				.addClass('simplemodal-data')

+				.css($.extend(s.o.dataCss, {

+						display: 'none'

+				}))

+				.appendTo('body');

+			data = null;

+

+			s.setContainerDimensions();

+			s.d.data.appendTo(s.d.wrap);

+

+			// fix issues with IE

+			if (ie6 || ieQuirks) {

+				s.fixIE();

+			}

+		},

+		/*

+		 * Bind events

+		 */

+		bindEvents: function () {

+			var s = this;

+

+			// bind the close event to any element with the closeClass class

+			$('.' + s.o.closeClass).bind('click.simplemodal', function (e) {

+				e.preventDefault();

+				s.close();

+			});

+

+			// bind the overlay click to the close function, if enabled

+			if (s.o.modal && s.o.close && s.o.overlayClose) {

+				s.d.overlay.bind('click.simplemodal', function (e) {

+					e.preventDefault();

+					s.close();

+				});

+			}

+

+			// bind keydown events

+			doc.bind('keydown.simplemodal', function (e) {

+				if (s.o.modal && e.keyCode === 9) { // TAB

+					s.watchTab(e);

+				}

+				else if ((s.o.close && s.o.escClose) && e.keyCode === 27) { // ESC

+					e.preventDefault();

+					s.close();

+				}

+			});

+

+			// update window size

+			wndw.bind('resize.simplemodal orientationchange.simplemodal', function () {

+				// redetermine the window width/height

+				s.getDimensions();

+

+				// reposition the dialog

+				s.o.autoResize ? s.setContainerDimensions() : s.o.autoPosition && s.setPosition();

+

+				if (ie6 || ieQuirks) {

+					s.fixIE();

+				}

+				else if (s.o.modal) {

+					// update the iframe & overlay

+					s.d.iframe && s.d.iframe.css({height: w[0], width: w[1]});

+					s.d.overlay.css({height: d[0], width: d[1]});

+				}

+			});

+		},

+		/*

+		 * Unbind events

+		 */

+		unbindEvents: function () {

+			$('.' + this.o.closeClass).unbind('click.simplemodal');

+			doc.unbind('keydown.simplemodal');

+			wndw.unbind('.simplemodal');

+			this.d.overlay.unbind('click.simplemodal');

+		},

+		/*

+		 * Fix issues in IE6 and IE7 in quirks mode

+		 */

+		fixIE: function () {

+			var s = this, p = s.o.position;

+

+			// simulate fixed position - adapted from BlockUI

+			$.each([s.d.iframe || null, !s.o.modal ? null : s.d.overlay, s.d.container.css('position') === 'fixed' ? s.d.container : null], function (i, el) {

+				if (el) {

+					var bch = 'document.body.clientHeight', bcw = 'document.body.clientWidth',

+						bsh = 'document.body.scrollHeight', bsl = 'document.body.scrollLeft',

+						bst = 'document.body.scrollTop', bsw = 'document.body.scrollWidth',

+						ch = 'document.documentElement.clientHeight', cw = 'document.documentElement.clientWidth',

+						sl = 'document.documentElement.scrollLeft', st = 'document.documentElement.scrollTop',

+						s = el[0].style;

+

+					s.position = 'absolute';

+					if (i < 2) {

+						s.removeExpression('height');

+						s.removeExpression('width');

+						s.setExpression('height','' + bsh + ' > ' + bch + ' ? ' + bsh + ' : ' + bch + ' + "px"');

+						s.setExpression('width','' + bsw + ' > ' + bcw + ' ? ' + bsw + ' : ' + bcw + ' + "px"');

+					}

+					else {

+						var te, le;

+						if (p && p.constructor === Array) {

+							var top = p[0]

+								? typeof p[0] === 'number' ? p[0].toString() : p[0].replace(/px/, '')

+								: el.css('top').replace(/px/, '');

+							te = top.indexOf('%') === -1

+								? top + ' + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"'

+								: parseInt(top.replace(/%/, '')) + ' * ((' + ch + ' || ' + bch + ') / 100) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"';

+

+							if (p[1]) {

+								var left = typeof p[1] === 'number' ? p[1].toString() : p[1].replace(/px/, '');

+								le = left.indexOf('%') === -1

+									? left + ' + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"'

+									: parseInt(left.replace(/%/, '')) + ' * ((' + cw + ' || ' + bcw + ') / 100) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"';

+							}

+						}

+						else {

+							te = '(' + ch + ' || ' + bch + ') / 2 - (this.offsetHeight / 2) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"';

+							le = '(' + cw + ' || ' + bcw + ') / 2 - (this.offsetWidth / 2) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"';

+						}

+						s.removeExpression('top');

+						s.removeExpression('left');

+						s.setExpression('top', te);

+						s.setExpression('left', le);

+					}

+				}

+			});

+		},

+		/*

+		 * Place focus on the first or last visible input

+		 */

+		focus: function (pos) {

+			var s = this, p = pos && $.inArray(pos, ['first', 'last']) !== -1 ? pos : 'first';

+

+			// focus on dialog or the first visible/enabled input element

+			var input = $(':input:enabled:visible:' + p, s.d.wrap);

+			setTimeout(function () {

+				input.length > 0 ? input.focus() : s.d.wrap.focus();

+			}, 10);

+		},

+		getDimensions: function () {

+			// fix a jQuery/Opera bug with determining the window height

+			var s = this,

+				h = $.browser.opera && $.browser.version > '9.5' && $.fn.jquery < '1.3'

+						|| $.browser.opera && $.browser.version < '9.5' && $.fn.jquery > '1.2.6'

+				? wndw[0].innerHeight : wndw.height();

+

+			d = [doc.height(), doc.width()];

+			w = [h, wndw.width()];

+		},

+		getVal: function (v, d) {

+			return v ? (typeof v === 'number' ? v

+					: v === 'auto' ? 0

+					: v.indexOf('%') > 0 ? ((parseInt(v.replace(/%/, '')) / 100) * (d === 'h' ? w[0] : w[1]))

+					: parseInt(v.replace(/px/, '')))

+				: null;

+		},

+		/*

+		 * Update the container. Set new dimensions, if provided.

+		 * Focus, if enabled. Re-bind events.

+		 */

+		update: function (height, width) {

+			var s = this;

+

+			// prevent update if dialog does not exist

+			if (!s.d.data) {

+				return false;

+			}

+

+			// reset orig values

+			s.d.origHeight = s.getVal(height, 'h');

+			s.d.origWidth = s.getVal(width, 'w');

+

+			// hide data to prevent screen flicker

+			s.d.data.hide();

+			height && s.d.container.css('height', height);

+			width && s.d.container.css('width', width);

+			s.setContainerDimensions();

+			s.d.data.show();

+			s.o.focus && s.focus();

+

+			// rebind events

+			s.unbindEvents();

+			s.bindEvents();

+		},

+		setContainerDimensions: function () {

+			var s = this,

+				badIE = ie6 || ie7;

+

+			// get the dimensions for the container and data

+			var ch = s.d.origHeight ? s.d.origHeight : $.browser.opera ? s.d.container.height() : s.getVal(badIE ? s.d.container[0].currentStyle['height'] : s.d.container.css('height'), 'h'),

+				cw = s.d.origWidth ? s.d.origWidth : $.browser.opera ? s.d.container.width() : s.getVal(badIE ? s.d.container[0].currentStyle['width'] : s.d.container.css('width'), 'w'),

+				dh = s.d.data.outerHeight(true), dw = s.d.data.outerWidth(true);

+

+			s.d.origHeight = s.d.origHeight || ch;

+			s.d.origWidth = s.d.origWidth || cw;

+

+			// mxoh = max option height, mxow = max option width

+			var mxoh = s.o.maxHeight ? s.getVal(s.o.maxHeight, 'h') : null,

+				mxow = s.o.maxWidth ? s.getVal(s.o.maxWidth, 'w') : null,

+				mh = mxoh && mxoh < w[0] ? mxoh : w[0],

+				mw = mxow && mxow < w[1] ? mxow : w[1];

+

+			// moh = min option height

+			var moh = s.o.minHeight ? s.getVal(s.o.minHeight, 'h') : 'auto';

+			if (!ch) {

+				if (!dh) {ch = moh;}

+				else {

+					if (dh > mh) {ch = mh;}

+					else if (s.o.minHeight && moh !== 'auto' && dh < moh) {ch = moh;}

+					else {ch = dh;}

+				}

+			}

+			else {

+				ch = s.o.autoResize && ch > mh ? mh : ch < moh ? moh : ch;

+			}

+

+			// mow = min option width

+			var mow = s.o.minWidth ? s.getVal(s.o.minWidth, 'w') : 'auto'; 

+			if (!cw) {

+				if (!dw) {cw = mow;}

+				else {

+					if (dw > mw) {cw = mw;}

+					else if (s.o.minWidth && mow !== 'auto' && dw < mow) {cw = mow;}

+					else {cw = dw;}

+				}

+			}

+			else {

+				cw = s.o.autoResize && cw > mw ? mw : cw < mow ? mow : cw;

+			}

+

+			s.d.container.css({"min-height": ch, "width": cw});

+//			s.d.wrap.css({overflow: (dh > ch || dw > cw) ? 'auto' : 'visible'});

+			s.o.autoPosition && s.setPosition();

+		},

+		setPosition: function () {

+			var s = this, top, left,

+				hc = (w[0]/2) - (s.d.container.outerHeight(true)/2),

+				vc = (w[1]/2) - (s.d.container.outerWidth(true)/2),

+				st = s.d.container.css('position') !== 'fixed' ? wndw.scrollTop() : 0;

+

+			if (s.o.position && Object.prototype.toString.call(s.o.position) === '[object Array]') {

+				top = st + (s.o.position[0] || hc);

+				left = s.o.position[1] || vc;

+			} else {

+				top = st + hc;

+				left = vc;

+			}

+			s.d.container.css({left: left, top: top});

+		},

+		watchTab: function (e) {

+			var s = this;

+

+			if ($(e.target).parents('.simplemodal-container').length > 0) {

+				// save the list of inputs

+				s.inputs = $(':input:enabled:visible:first, :input:enabled:visible:last', s.d.data[0]);

+

+				// if it's the first or last tabbable element, refocus

+				if ((!e.shiftKey && e.target === s.inputs[s.inputs.length -1]) ||

+						(e.shiftKey && e.target === s.inputs[0]) ||

+						s.inputs.length === 0) {

+					e.preventDefault();

+					var pos = e.shiftKey ? 'last' : 'first';

+					s.focus(pos);

+				}

+			}

+			else {

+				// might be necessary when custom onShow callback is used

+				e.preventDefault();

+				s.focus();

+			}

+		},

+		/*

+		 * Open the modal dialog elements

+		 * - Note: If you use the onOpen callback, you must "show" the

+		 *			overlay and container elements manually

+		 *		 (the iframe will be handled by SimpleModal)

+		 */

+		open: function () {

+			var s = this;

+			// display the iframe

+			s.d.iframe && s.d.iframe.show();

+

+			if ($.isFunction(s.o.onOpen)) {

+				// execute the onOpen callback

+				s.o.onOpen.apply(s, [s.d]);

+			}

+			else {

+				// display the remaining elements

+				s.d.overlay.show();

+				s.d.container.show();

+				s.d.data.show();

+			}

+

+			s.o.focus && s.focus();

+

+			// bind default events

+			s.bindEvents();

+		},

+		/*

+		 * Close the modal dialog

+		 * - Note: If you use an onClose callback, you must remove the

+		 *         overlay, container and iframe elements manually

+		 *

+		 * @param {boolean} external Indicates whether the call to this

+		 *     function was internal or external. If it was external, the

+		 *     onClose callback will be ignored

+		 */

+		close: function () {

+			var s = this;

+

+			// prevent close when dialog does not exist

+			if (!s.d.data) {

+				return false;

+			}

+

+			// remove the default events

+			s.unbindEvents();

+

+			if ($.isFunction(s.o.onClose) && !s.occb) {

+				// set the onClose callback flag

+				s.occb = true;

+

+				// execute the onClose callback

+				s.o.onClose.apply(s, [s.d]);

+			}

+			else {

+				// if the data came from the DOM, put it back

+				if (s.d.placeholder) {

+					var ph = $('#simplemodal-placeholder');

+					// save changes to the data?

+					if (s.o.persist) {

+						// insert the (possibly) modified data back into the DOM

+						ph.replaceWith(s.d.data.removeClass('simplemodal-data').css('display', s.display));

+					}

+					else {

+						// remove the current and insert the original,

+						// unmodified data back into the DOM

+						s.d.data.hide().remove();

+						ph.replaceWith(s.d.orig);

+					}

+				}

+				else {

+					// otherwise, remove it

+					s.d.data.hide().remove();

+				}

+

+				// remove the remaining elements

+				s.d.container.hide().remove();

+				s.d.overlay.hide();

+				s.d.iframe && s.d.iframe.hide().remove();

+				s.d.overlay.remove();

+

+				// reset the dialog object

+				s.d = {};

+			}

+		}

+	};

+}));

diff --git a/ap/app/zte_webui/js/3rd/jquery.tmpl.js b/ap/app/zte_webui/js/3rd/jquery.tmpl.js
new file mode 100755
index 0000000..a615f5b
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.tmpl.js
@@ -0,0 +1,10 @@
+/*
+ * jQuery Templates Plugin 1.0.0pre
+ * http://github.com/jquery/jquery-tmpl
+ * Requires jQuery 1.4.2
+ *
+ * Copyright 2011, Software Freedom Conservancy, Inc.
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ */
+(function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h<m;h++){c=h;k=(h>0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i<j&&!(f=a.data(h[i++],"tmplItem")));if(f&&c)g[2]=function(b){a.tmpl.afterManip(this,b,k)};r.apply(this,g)}else r.apply(this,arguments);c=0;!e&&a.tmpl.complete(b);return this}});a.extend({tmpl:function(d,h,e,c){var i,k=!c;if(k){c=p;d=a.template[d]||a.template(null,d);f={}}else if(!d){d=c.tmpl;b[c.key]=c;c.nodes=[];c.wrapped&&n(c,c.wrapped);return a(j(c,null,c.tmpl(a,c)))}if(!d)return[];if(typeof h==="function")h=h.call(c||{});e&&e.wrapped&&n(e,e.wrapped);i=a.isArray(h)?a.map(h,function(a){return a?g(e,c,d,a):null}):[g(e,c,d,h)];return k?a(j(c,null,i)):i},tmplItem:function(b){var c;if(b instanceof a)b=b[0];while(b&&b.nodeType===1&&!(c=a.data(b,"tmplItem"))&&(b=b.parentNode));return c||p},template:function(c,b){if(b){if(typeof b==="string")b=o(b);else if(b instanceof a)b=b[0]||{};if(b.nodeType)b=a.data(b,"tmpl")||a.data(b,"tmpl",o(b.innerHTML));return typeof c==="string"?(a.template[c]=b):b}return c?typeof c!=="string"?a.template(null,c):a.template[c]||a.template(null,q.test(c)?c:a(c)):null},encode:function(a){return(""+a).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(__,$1,$2);__=[];",close:"call=$item.calls();__=call._.concat($item.wrap(call,__));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else f=e=i.$1||"null";g=h(g);return"');"+j[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(f).split("$1").join(e).split("$2").join(g||i.$2||"")+"__.push('"})+"');}return __;")}function n(c,b){c._wrap=j(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function h(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,h;for(e=0,p=o.length;e<p;e++){if((k=o[e]).nodeType!==1)continue;j=k.getElementsByTagName("*");for(h=j.length-1;h>=0;h--)m(j[h]);m(k)}function m(j){var p,h=j,k,e,m;if(m=j.getAttribute(d)){while(h.parentNode&&(h=h.parentNode).nodeType===1&&!(p=h.getAttribute(d)));if(p!==m){h=h.parentNode?h.nodeType===11?0:h.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[h]||f[h]);e.key=++i;b[i]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;h=a.data(j.parentNode,"tmplItem");h=h?h.key:0}if(e){k=e;while(k&&k.key!=h){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery);
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/jquery.translate.js b/ap/app/zte_webui/js/3rd/jquery.translate.js
new file mode 100755
index 0000000..1301956
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.translate.js
@@ -0,0 +1,94 @@
+(function ($) {

+    $.fn.translate = function () {

+    	var $this = $(this);

+    	$this.each(function(){

+    		var item = $(this);

+    		var trans = item.attr("data-trans");

+    		if(!!trans){

+            	translateElement(this, trans);

+    		}

+

+            var placeholder = item.attr("data-placeholder");

+            if(!!placeholder){

+                placeholderElement(this, placeholder);

+            }

+    	});

+

+    	$this.find("*[data-trans], *[data-placeholder]").each(function () {

+            var self = $(this);

+    		if(self.attr("id") == 'chosen-search-field-input'){

+    			var val = $("#chosenUserSelect").val();

+    			if(val && val.length > 0){

+    				return;

+    			}

+    		}

+            var trans = self.attr("data-trans");

+            var transData = self.attr("data-trans-data");

+            if (trans != "") {

+            	translateElement(this, trans, transData);

+            }

+

+            var placeholder = self.attr("data-placeholder");

+            if(!!placeholder){

+                placeholderElement(this, placeholder);

+            }

+        });

+

+    	//翻译国家码

+        $('*[data-transid]', $this).each(function () {

+        	var ele = $(this);

+            var transid = ele.attr('data-transid');

+            if(ele.attr("name") == "channel"){

+            	ele.find('option').each(function () {

+            		var item = $(this);

+            		if (item.val() != 0) {

+            			var val = item.val().split("_");

+            			item.html( val[1] + "MHz " + $.i18n.prop(transid + '_' + val[0]) );

+            		} else {

+            			item.html( $.i18n.prop(transid + '_0') );

+            		}

+            	});

+            }else{

+            	ele.find('option').each(function () {

+            		$(this).html($.i18n.prop(transid + '_' + $(this).attr('value')));

+            	});

+            }

+        });

+

+        function translateElement(ele, trans, transData){

+            var word;

+            if(transData == undefined) {

+                word = $.i18n.prop(trans);

+            } else {

+                word = $.i18n.prop.apply(null, [trans].concat(transData.split(",")));

+            }

+            var nodeName = ele.nodeName.toUpperCase();

+            if (nodeName == 'INPUT' || nodeName == 'SELECT' || nodeName == 'TEXTAREA') {

+                $(ele).val(word);

+            } else if (nodeName == 'BUTTON') {

+                $(ele).text(word);

+            } else {

+                $(ele).html(word);

+            }

+        }

+

+        function placeholderElement(ele, trans){

+            var word = $.i18n.prop(trans);

+            var nodeName = ele.nodeName.toUpperCase();

+            if (nodeName == 'INPUT') {

+                $(ele).attr('placeholder', word);

+            }

+        }

+

+        $('.content div.row', $this).each(function () {

+            var $row = $(this);

+            if ($row.has('.required').length > 0) {

+                $("label:first-child", $row).append("<i class='colorRed'>&nbsp;*</i>");

+            } else {

+                $("label:first-child", $row).append("<i class='colorRed' style='visibility: hidden;'>&nbsp;*</i>");

+            }

+        });

+

+        return $this;

+    };

+})(jQuery);

diff --git a/ap/app/zte_webui/js/3rd/jquery.validate.js b/ap/app/zte_webui/js/3rd/jquery.validate.js
new file mode 100755
index 0000000..ef398db
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jquery.validate.js
@@ -0,0 +1,1192 @@
+/**
+ * jQuery Validation Plugin 1.9.0
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
+ * http://docs.jquery.com/Plugins/Validation
+ *
+ * Copyright (c) 2006 - 2011 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+(function($) {
+
+$.extend($.fn, {
+	// http://docs.jquery.com/Plugins/Validation/validate
+	validate: function( options ) {
+
+		// if nothing is selected, return nothing; can't chain anyway
+		if (!this.length) {
+			options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
+			return;
+		}
+
+		// check if a validator for this form was already created
+		var validator = $.data(this[0], 'validator');
+		if ( validator ) {
+			return validator;
+		}
+
+		// Add novalidate tag if HTML5.
+		this.attr('novalidate', 'novalidate');
+
+		validator = new $.validator( options, this[0] );
+		$.data(this[0], 'validator', validator);
+
+		if ( validator.settings.onsubmit ) {
+
+			var inputsAndButtons = this.find("input, button");
+
+			// allow suppresing validation by adding a cancel class to the submit button
+			inputsAndButtons.filter(".cancel").click(function () {
+				validator.cancelSubmit = true;
+			});
+
+			// when a submitHandler is used, capture the submitting button
+			if (validator.settings.submitHandler) {
+				inputsAndButtons.filter(":submit").click(function () {
+					validator.submitButton = this;
+				});
+			}
+
+			// validate the form on submit
+			this.submit( function( event ) {
+				if ( validator.settings.debug )
+					// prevent form submit to be able to see console output
+					event.preventDefault();
+
+				function handle() {
+					if ( validator.settings.submitHandler ) {
+						if (validator.submitButton) {
+							// insert a hidden input as a replacement for the missing submit button
+							var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
+						}
+						validator.settings.submitHandler.call( validator, validator.currentForm );
+						if (validator.submitButton) {
+							// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
+							hidden.remove();
+						}
+						return false;
+					}
+					return true;
+				}
+
+				// prevent submit for invalid forms or custom submit handlers
+				if ( validator.cancelSubmit ) {
+					validator.cancelSubmit = false;
+					return handle();
+				}
+				if ( validator.form() ) {
+					if ( validator.pendingRequest ) {
+						validator.formSubmitted = true;
+						return false;
+					}
+					return handle();
+				} else {
+					validator.focusInvalid();
+					return false;
+				}
+			});
+		}
+
+		return validator;
+	},
+	// http://docs.jquery.com/Plugins/Validation/valid
+	valid: function() {
+        if ( $(this[0]).is('form')) {
+            return this.validate().form();
+        } else {
+            var valid = true;
+            var validator = $(this[0].form).validate();
+            this.each(function() {
+				valid &= validator.element(this);
+            });
+            return valid;
+        }
+    },
+	// attributes: space seperated list of attributes to retrieve and remove
+	removeAttrs: function(attributes) {
+		var result = {},
+			$element = this;
+		$.each(attributes.split(/\s/), function(index, value) {
+			result[value] = $element.attr(value);
+			$element.removeAttr(value);
+		});
+		return result;
+	},
+	// http://docs.jquery.com/Plugins/Validation/rules
+	rules: function(command, argument) {
+		var element = this[0];
+
+		if (command) {
+			var settings = $.data(element.form, 'validator').settings;
+			var staticRules = settings.rules;
+			var existingRules = $.validator.staticRules(element);
+			switch(command) {
+			case "add":
+				$.extend(existingRules, $.validator.normalizeRule(argument));
+				staticRules[element.name] = existingRules;
+				if (argument.messages)
+					settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
+				break;
+			case "remove":
+				if (!argument) {
+					delete staticRules[element.name];
+					return existingRules;
+				}
+				var filtered = {};
+				$.each(argument.split(/\s/), function(index, method) {
+					filtered[method] = existingRules[method];
+					delete existingRules[method];
+				});
+				return filtered;
+			}
+		}
+
+		var data = $.validator.normalizeRules(
+		$.extend(
+			{},
+			$.validator.metadataRules(element),
+			$.validator.classRules(element),
+			$.validator.attributeRules(element),
+			$.validator.staticRules(element)
+		), element);
+
+		// make sure required is at front
+		if (data.required) {
+			var param = data.required;
+			delete data.required;
+			data = $.extend({required: param}, data);
+		}
+
+		return data;
+	}
+});
+
+// Custom selectors
+$.extend($.expr[":"], {
+	// http://docs.jquery.com/Plugins/Validation/blank
+	blank: function(a) {return !$.trim("" + a.value);},
+	// http://docs.jquery.com/Plugins/Validation/filled
+	filled: function(a) {return !!$.trim("" + a.value);},
+	// http://docs.jquery.com/Plugins/Validation/unchecked
+	unchecked: function(a) {return !a.checked;}
+});
+
+// constructor for validator
+$.validator = function( options, form ) {
+	this.settings = $.extend( true, {}, $.validator.defaults, options );
+	this.currentForm = form;
+	this.init();
+};
+
+$.validator.format = function(source, params) {
+	if ( arguments.length == 1 )
+		return function() {
+			var args = $.makeArray(arguments);
+			args.unshift(source);
+			return $.validator.format.apply( this, args );
+		};
+	if ( arguments.length > 2 && params.constructor != Array  ) {
+		params = $.makeArray(arguments).slice(1);
+	}
+	if ( params.constructor != Array ) {
+		params = [ params ];
+	}
+	$.each(params, function(i, n) {
+        //if params of {0}, {1} have translate the translate
+        if($.validator.messages[n]) {
+            n = $.i18n.prop(n);
+        }
+		source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
+	});
+	return source;
+};
+
+$.extend($.validator, {
+
+	defaults: {
+		messages: {},
+		groups: {},
+		rules: {},
+		errorClass: "error",
+		validClass: "valid",
+		errorElement: "label",
+		focusInvalid: true,
+		errorContainer: $( [] ),
+		errorLabelContainer: $( [] ),
+		onsubmit: true,
+		ignore: ":hidden",
+		ignoreTitle: false,
+		onfocusin: function(element, event) {
+			this.lastActive = element;
+
+			// hide error label and remove error class on focus if enabled
+			if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
+				this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
+				this.addWrapper(this.errorsFor(element)).hide();
+			}
+		},
+		onfocusout: function(element, event) {
+			if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
+				this.element(element);
+			}
+		},
+		onkeyup: function(element, event) {
+			if ( element.name in this.submitted || element == this.lastElement ) {
+				this.element(element);
+			}
+		},
+		onclick: function(element, event) {
+			// click on selects, radiobuttons and checkboxes
+			if ( element.name in this.submitted )
+				this.element(element);
+			// or option elements, check parent select in that case
+			else if (element.parentNode.name in this.submitted)
+				this.element(element.parentNode);
+		},
+		highlight: function(element, errorClass, validClass) {
+			if (element.type === 'radio') {
+				this.findByName(element.name).addClass(errorClass).removeClass(validClass);
+			} else {
+				$(element).addClass(errorClass).removeClass(validClass);
+			}
+		},
+		unhighlight: function(element, errorClass, validClass) {
+			if (element.type === 'radio') {
+				this.findByName(element.name).removeClass(errorClass).addClass(validClass);
+			} else {
+				$(element).removeClass(errorClass).addClass(validClass);
+			}
+		}
+	},
+
+	// http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
+	setDefaults: function(settings) {
+		$.extend( $.validator.defaults, settings );
+	},
+
+	messages: {
+		required: "This field is required.",
+		remote: "Please fix this field.",
+		email: "Please enter a valid email address.",
+		url: "Please enter a valid URL.",
+		date: "Please enter a valid date.",
+		dateISO: "Please enter a valid date (ISO).",
+		number: "Please enter a valid number.",
+		digits: "Please enter only digits.",
+		creditcard: "Please enter a valid credit card number.",
+		equalTo: "Please enter the same value again.",
+		accept: "Please enter a value with a valid extension.",
+		maxlength: $.validator.format("Please enter no more than {0} characters."),
+		minlength: $.validator.format("Please enter at least {0} characters."),
+		rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
+		range: $.validator.format("Please enter a value between {0} and {1}."),
+		max: $.validator.format("Please enter a value less than or equal to {0}."),
+		min: $.validator.format("Please enter a value greater than or equal to {0}.")
+	},
+
+	autoCreateRanges: false,
+
+	prototype: {
+
+		init: function() {
+			this.labelContainer = $(this.settings.errorLabelContainer);
+			this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
+			this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
+			this.submitted = {};
+			this.valueCache = {};
+			this.pendingRequest = 0;
+			this.pending = {};
+			this.invalid = {};
+			this.reset();
+
+			var groups = (this.groups = {});
+			$.each(this.settings.groups, function(key, value) {
+				$.each(value.split(/\s/), function(index, name) {
+					groups[name] = key;
+				});
+			});
+			var rules = this.settings.rules;
+			$.each(rules, function(key, value) {
+				rules[key] = $.validator.normalizeRule(value);
+			});
+
+			function delegate(event) {
+				var validator = $.data(this[0].form, "validator"),
+					eventType = "on" + event.type.replace(/^validate/, "");
+				validator.settings[eventType] && validator.settings[eventType].call(validator, this[0], event);
+			}
+			$(this.currentForm)
+			       .validateDelegate("[type='text'], [type='password'], [type='file'], select, textarea, " +
+						"[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
+						"[type='email'], [type='datetime'], [type='date'], [type='month'], " +
+						"[type='week'], [type='time'], [type='datetime-local'], " +
+						"[type='range'], [type='color'] ",
+						"focusin focusout keyup", delegate)
+				.validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
+
+			if (this.settings.invalidHandler)
+				$(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Validator/form
+		form: function() {
+			this.checkForm();
+			$.extend(this.submitted, this.errorMap);
+			this.invalid = $.extend({}, this.errorMap);
+			if (!this.valid())
+				$(this.currentForm).triggerHandler("invalid-form", [this]);
+			this.showErrors();
+			return this.valid();
+		},
+
+		checkForm: function() {
+			this.prepareForm();
+			for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
+				this.check( elements[i] );
+			}
+			return this.valid();
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Validator/element
+		element: function( element ) {
+			element = this.validationTargetFor( this.clean( element ) );
+			this.lastElement = element;
+			this.prepareElement( element );
+			this.currentElements = $(element);
+			var result = this.check( element );
+			if ( result ) {
+				delete this.invalid[element.name];
+			} else {
+				this.invalid[element.name] = true;
+			}
+			if ( !this.numberOfInvalids() ) {
+				// Hide error containers on last error
+				this.toHide = this.toHide.add( this.containers );
+			}
+			this.showErrors();
+			return result;
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Validator/showErrors
+		showErrors: function(errors) {
+			if(errors) {
+				// add items to error list and map
+				$.extend( this.errorMap, errors );
+				this.errorList = [];
+				for ( var name in errors ) {
+					this.errorList.push({
+						message: errors[name],
+						element: this.findByName(name)[0]
+					});
+				}
+				// remove items from success list
+				this.successList = $.grep( this.successList, function(element) {
+					return !(element.name in errors);
+				});
+			}
+			this.settings.showErrors
+				? this.settings.showErrors.call( this, this.errorMap, this.errorList )
+				: this.defaultShowErrors();
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Validator/resetForm
+		resetForm: function() {
+			if ( $.fn.resetForm )
+				$( this.currentForm ).resetForm();
+			this.submitted = {};
+			this.lastElement = null;
+			this.prepareForm();
+			this.hideErrors();
+			this.elements().removeClass( this.settings.errorClass );
+		},
+
+		numberOfInvalids: function() {
+			return this.objectLength(this.invalid);
+		},
+
+		objectLength: function( obj ) {
+			var count = 0;
+			for ( var i in obj )
+				count++;
+			return count;
+		},
+
+		hideErrors: function() {
+			this.addWrapper( this.toHide ).hide();
+		},
+
+		valid: function() {
+			return this.size() == 0;
+		},
+
+		size: function() {
+			return this.errorList.length;
+		},
+
+		focusInvalid: function() {
+			if( this.settings.focusInvalid ) {
+				try {
+					$(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
+					.filter(":visible")
+					.focus()
+					// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
+					.trigger("focusin");
+				} catch(e) {
+					// ignore IE throwing errors when focusing hidden elements
+				}
+			}
+		},
+
+		findLastActive: function() {
+			var lastActive = this.lastActive;
+			return lastActive && $.grep(this.errorList, function(n) {
+				return n.element.name == lastActive.name;
+			}).length == 1 && lastActive;
+		},
+
+		elements: function() {
+			var validator = this,
+				rulesCache = {};
+
+			// select all valid inputs inside the form (no submit or reset buttons)
+			return $(this.currentForm)
+			.find("input, select, textarea")
+			.not(":submit, :reset, :image, [disabled]")
+			.not( this.settings.ignore )
+			.filter(function() {
+				!this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
+
+				// select only the first element for each name, and only those with rules specified
+				if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
+					return false;
+
+				rulesCache[this.name] = true;
+				return true;
+			});
+		},
+
+		clean: function( selector ) {
+			return $( selector )[0];
+		},
+
+		errors: function() {
+			return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
+		},
+
+		reset: function() {
+			this.successList = [];
+			this.errorList = [];
+			this.errorMap = {};
+			this.toShow = $([]);
+			this.toHide = $([]);
+			this.currentElements = $([]);
+		},
+
+		prepareForm: function() {
+			this.reset();
+			this.toHide = this.errors().add( this.containers );
+		},
+
+		prepareElement: function( element ) {
+			this.reset();
+			this.toHide = this.errorsFor(element);
+		},
+
+		check: function( element ) {
+			element = this.validationTargetFor( this.clean( element ) );
+
+			var rules = $(element).rules();
+			var dependencyMismatch = false;
+			for (var method in rules ) {
+				var rule = { method: method, parameters: rules[method] };
+				try {
+					var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
+
+					// if a method indicates that the field is optional and therefore valid,
+					// don't mark it as valid when there are no other rules
+					if ( result == "dependency-mismatch" ) {
+						dependencyMismatch = true;
+						continue;
+					}
+					dependencyMismatch = false;
+
+					if ( result == "pending" ) {
+						this.toHide = this.toHide.not( this.errorsFor(element) );
+						return;
+					}
+
+					if( !result ) {
+						this.formatAndAdd( element, rule );
+						return false;
+					}
+				} catch(e) {
+					this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
+						 + ", check the '" + rule.method + "' method", e);
+					throw e;
+				}
+			}
+			if (dependencyMismatch)
+				return;
+			if ( this.objectLength(rules) )
+				this.successList.push(element);
+			return true;
+		},
+
+		// return the custom message for the given element and validation method
+		// specified in the element's "messages" metadata
+		customMetaMessage: function(element, method) {
+			if (!$.metadata)
+				return;
+
+			var meta = this.settings.meta
+				? $(element).metadata()[this.settings.meta]
+				: $(element).metadata();
+
+			return meta && meta.messages && meta.messages[method];
+		},
+
+		// return the custom message for the given element name and validation method
+		customMessage: function( name, method ) {
+			var m = this.settings.messages[name];
+			return m && (m.constructor == String
+				? m
+				: m[method]);
+		},
+
+		// return the first defined argument, allowing empty strings
+		findDefined: function() {
+			for(var i = 0; i < arguments.length; i++) {
+				if (arguments[i] !== undefined)
+					return arguments[i];
+			}
+			return undefined;
+		},
+
+		defaultMessage: function( element, method) {
+			return this.findDefined(
+				this.customMessage( element.name, method ),
+				this.customMetaMessage( element, method ),
+				// title is never undefined, so handle empty string as undefined
+				!this.settings.ignoreTitle && element.title || undefined,
+				$.validator.messages[method],
+				"<strong>Warning: No message defined for " + element.name + "</strong>"
+			);
+		},
+
+		formatAndAdd: function( element, rule ) {
+			var message = this.defaultMessage( element, rule.method ),
+				theregex = /\$?\{(\d+)\}/g;
+			if ( typeof message == "function" ) {
+				message = message.call(this, rule.parameters, element);
+			} else if (theregex.test(message)) {
+				message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
+			}
+			this.errorList.push({
+				message: message,
+				element: element
+			});
+
+			this.errorMap[element.name] = message;
+			this.submitted[element.name] = message;
+		},
+
+		addWrapper: function(toToggle) {
+			if ( this.settings.wrapper )
+				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
+			return toToggle;
+		},
+
+		defaultShowErrors: function() {
+			for ( var i = 0; this.errorList[i]; i++ ) {
+				var error = this.errorList[i];
+				this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
+				this.showLabel( error.element, error.message );
+			}
+			if( this.errorList.length ) {
+				this.toShow = this.toShow.add( this.containers );
+			}
+			if (this.settings.success) {
+				for ( var i = 0; this.successList[i]; i++ ) {
+					this.showLabel( this.successList[i] );
+				}
+			}
+			if (this.settings.unhighlight) {
+				for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
+					this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
+				}
+			}
+			this.toHide = this.toHide.not( this.toShow );
+			this.hideErrors();
+			this.addWrapper( this.toShow ).show();
+		},
+
+		validElements: function() {
+			return this.currentElements.not(this.invalidElements());
+		},
+
+		invalidElements: function() {
+			return $(this.errorList).map(function() {
+				return this.element;
+			});
+		},
+
+		showLabel: function(element, message) {
+			var label = this.errorsFor( element );
+			if ( label.length ) {
+				// refresh error/success class
+				label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
+
+				// check if we have a generated label, replace the message then
+				label.attr("generated") && label.html(message);
+			} else {
+				// create label
+				label = $("<" + this.settings.errorElement + "/>")
+					.attr({"for":  this.idOrName(element), generated: true})
+					.addClass(this.settings.errorClass)
+					.html(message || "");
+				if ( this.settings.wrapper ) {
+					// make sure the element is visible, even in IE
+					// actually showing the wrapped element is handled elsewhere
+					label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
+				}
+				if ( !this.labelContainer.append(label).length )
+					this.settings.errorPlacement
+						? this.settings.errorPlacement(label, $(element) )
+						: label.insertAfter(element);
+			}
+			if ( !message && this.settings.success ) {
+				label.text("");
+				typeof this.settings.success == "string"
+					? label.addClass( this.settings.success )
+					: this.settings.success( label );
+			}
+			this.toShow = this.toShow.add(label);
+		},
+
+		errorsFor: function(element) {
+			var name = this.idOrName(element);
+    		return this.errors().filter(function() {
+				return $(this).attr('for') == name;
+			});
+		},
+
+		idOrName: function(element) {
+			return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
+		},
+
+		validationTargetFor: function(element) {
+			// if radio/checkbox, validate first element in group instead
+			if (this.checkable(element)) {
+				element = this.findByName( element.name ).not(this.settings.ignore)[0];
+			}
+			return element;
+		},
+
+		checkable: function( element ) {
+			return /radio|checkbox/i.test(element.type);
+		},
+
+		findByName: function( name ) {
+			// select by name and filter by form for performance over form.find("[name=...]")
+			var form = this.currentForm;
+			return $(document.getElementsByName(name)).map(function(index, element) {
+				return element.form == form && element.name == name && element  || null;
+			});
+		},
+
+		getLength: function(value, element) {
+			switch( element.nodeName.toLowerCase() ) {
+			case 'select':
+				return $("option:selected", element).length;
+			case 'input':
+				if( this.checkable( element) )
+					return this.findByName(element.name).filter(':checked').length;
+			}
+			return value.length;
+		},
+
+		depend: function(param, element) {
+			return this.dependTypes[typeof param]
+				? this.dependTypes[typeof param](param, element)
+				: true;
+		},
+
+		dependTypes: {
+			"boolean": function(param, element) {
+				return param;
+			},
+			"string": function(param, element) {
+				return !!$(param, element.form).length;
+			},
+			"function": function(param, element) {
+				return param(element);
+			}
+		},
+
+		optional: function(element) {
+			return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
+		},
+
+		startRequest: function(element) {
+			if (!this.pending[element.name]) {
+				this.pendingRequest++;
+				this.pending[element.name] = true;
+			}
+		},
+
+		stopRequest: function(element, valid) {
+			this.pendingRequest--;
+			// sometimes synchronization fails, make sure pendingRequest is never < 0
+			if (this.pendingRequest < 0)
+				this.pendingRequest = 0;
+			delete this.pending[element.name];
+			if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
+				$(this.currentForm).submit();
+				this.formSubmitted = false;
+			} else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
+				$(this.currentForm).triggerHandler("invalid-form", [this]);
+				this.formSubmitted = false;
+			}
+		},
+
+		previousValue: function(element) {
+			return $.data(element, "previousValue") || $.data(element, "previousValue", {
+				old: null,
+				valid: true,
+				message: this.defaultMessage( element, "remote" )
+			});
+		}
+
+	},
+
+	classRuleSettings: {
+		required: {required: true},
+		email: {email: true},
+		url: {url: true},
+		date: {date: true},
+		dateISO: {dateISO: true},
+		dateDE: {dateDE: true},
+		number: {number: true},
+		numberDE: {numberDE: true},
+		digits: {digits: true},
+		creditcard: {creditcard: true}
+	},
+
+	addClassRules: function(className, rules) {
+		className.constructor == String ?
+			this.classRuleSettings[className] = rules :
+			$.extend(this.classRuleSettings, className);
+	},
+
+	classRules: function(element) {
+		var rules = {};
+		var classes = $(element).attr('class');
+		classes && $.each(classes.split(' '), function() {
+			if (this in $.validator.classRuleSettings) {
+				$.extend(rules, $.validator.classRuleSettings[this]);
+			}
+		});
+		return rules;
+	},
+
+	attributeRules: function(element) {
+		var rules = {};
+		var $element = $(element);
+
+		for (var method in $.validator.methods) {
+			var value;
+			// If .prop exists (jQuery >= 1.6), use it to get true/false for required
+			if (method === 'required' && typeof $.fn.prop === 'function') {
+				value = $element.prop(method);
+			} else {
+				value = $element.attr(method);
+			}
+			if (value) {
+				rules[method] = value;
+			} else if ($element[0].getAttribute("type") === method) {
+				rules[method] = true;
+			}
+		}
+
+		// maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
+		if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
+			delete rules.maxlength;
+		}
+
+		return rules;
+	},
+
+	metadataRules: function(element) {
+		if (!$.metadata) return {};
+
+		var meta = $.data(element.form, 'validator').settings.meta;
+		return meta ?
+			$(element).metadata()[meta] :
+			$(element).metadata();
+	},
+
+	staticRules: function(element) {
+		var rules = {};
+		var validator = $.data(element.form, 'validator');
+		if (validator.settings.rules) {
+			rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
+		}
+		return rules;
+	},
+
+	normalizeRules: function(rules, element) {
+		// handle dependency check
+		$.each(rules, function(prop, val) {
+			// ignore rule when param is explicitly false, eg. required:false
+			if (val === false) {
+				delete rules[prop];
+				return;
+			}
+			if (val.param || val.depends) {
+				var keepRule = true;
+				switch (typeof val.depends) {
+					case "string":
+						keepRule = !!$(val.depends, element.form).length;
+						break;
+					case "function":
+						keepRule = val.depends.call(element, element);
+						break;
+				}
+				if (keepRule) {
+					rules[prop] = val.param !== undefined ? val.param : true;
+				} else {
+					delete rules[prop];
+				}
+			}
+		});
+
+		// evaluate parameters
+		$.each(rules, function(rule, parameter) {
+			rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
+		});
+
+		// clean number parameters
+		$.each(['minlength', 'maxlength', 'min', 'max'], function() {
+			if (rules[this]) {
+				rules[this] = Number(rules[this]);
+			}
+		});
+		$.each(['rangelength', 'range'], function() {
+			if (rules[this]) {
+				rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
+			}
+		});
+
+		if ($.validator.autoCreateRanges) {
+			// auto-create ranges
+			if (rules.min && rules.max) {
+				rules.range = [rules.min, rules.max];
+				delete rules.min;
+				delete rules.max;
+			}
+			if (rules.minlength && rules.maxlength) {
+				rules.rangelength = [rules.minlength, rules.maxlength];
+				delete rules.minlength;
+				delete rules.maxlength;
+			}
+		}
+
+		// To support custom messages in metadata ignore rule methods titled "messages"
+		if (rules.messages) {
+			delete rules.messages;
+		}
+
+		return rules;
+	},
+
+	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
+	normalizeRule: function(data) {
+		if( typeof data == "string" ) {
+			var transformed = {};
+			$.each(data.split(/\s/), function() {
+				transformed[this] = true;
+			});
+			data = transformed;
+		}
+		return data;
+	},
+
+	// http://docs.jquery.com/Plugins/Validation/Validator/addMethod
+	addMethod: function(name, method, message) {
+		$.validator.methods[name] = method;
+		$.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
+		if (method.length < 3) {
+			$.validator.addClassRules(name, $.validator.normalizeRule(name));
+		}
+	},
+
+	methods: {
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/required
+		required: function(value, element, param) {
+			// check if dependency is met
+			if ( !this.depend(param, element) )
+				return "dependency-mismatch";
+			switch( element.nodeName.toLowerCase() ) {
+			case 'select':
+				// could be an array for select-multiple or a string, both are fine this way
+				var val = $(element).val();
+				return val && val.length > 0;
+			case 'input':
+				if ( this.checkable(element) )
+					return this.getLength(value, element) > 0;
+			default:
+				return $.trim(value).length > 0;
+			}
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/remote
+		remote: function(value, element, param) {
+			if ( this.optional(element) )
+				return "dependency-mismatch";
+
+			var previous = this.previousValue(element);
+			if (!this.settings.messages[element.name] )
+				this.settings.messages[element.name] = {};
+			previous.originalMessage = this.settings.messages[element.name].remote;
+			this.settings.messages[element.name].remote = previous.message;
+
+			param = typeof param == "string" && {url:param} || param;
+
+			if ( this.pending[element.name] ) {
+				return "pending";
+			}
+			if ( previous.old === value ) {
+				return previous.valid;
+			}
+
+			previous.old = value;
+			var validator = this;
+			this.startRequest(element);
+			var data = {};
+			data[element.name] = value;
+			$.ajax($.extend(true, {
+				url: param,
+				mode: "abort",
+				port: "validate" + element.name,
+				dataType: "json",
+				data: data,
+				success: function(response) {
+					validator.settings.messages[element.name].remote = previous.originalMessage;
+					var valid = response === true;
+					if ( valid ) {
+						var submitted = validator.formSubmitted;
+						validator.prepareElement(element);
+						validator.formSubmitted = submitted;
+						validator.successList.push(element);
+						validator.showErrors();
+					} else {
+						var errors = {};
+						var message = response || validator.defaultMessage( element, "remote" );
+						errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
+						validator.showErrors(errors);
+					}
+					previous.valid = valid;
+					validator.stopRequest(element, valid);
+				}
+			}, param));
+			return "pending";
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/minlength
+		minlength: function(value, element, param) {
+			return this.optional(element) || this.getLength($.trim(value), element) >= param;
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/maxlength
+		maxlength: function(value, element, param) {
+			return this.optional(element) || this.getLength($.trim(value), element) <= param;
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/rangelength
+		rangelength: function(value, element, param) {
+			var length = this.getLength($.trim(value), element);
+			return this.optional(element) || ( length >= param[0] && length <= param[1] );
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/min
+		min: function( value, element, param ) {
+			return this.optional(element) || value >= param;
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/max
+		max: function( value, element, param ) {
+			return this.optional(element) || value <= param;
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/range
+		range: function( value, element, param ) {
+			return this.optional(element) || ( value >= param[0] && value <= param[1] );
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/email
+		email: function(value, element) {
+			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
+			return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value);
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/url
+		url: function(value, element) {
+			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
+			return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/date
+		date: function(value, element) {
+			return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/dateISO
+		dateISO: function(value, element) {
+			return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/number
+		number: function(value, element) {
+			return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/digits
+		digits: function(value, element) {
+            return this.optional(element) || value == '0' || /^[1-9]\d*$/.test(value);
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/creditcard
+		// based on http://en.wikipedia.org/wiki/Luhn
+		creditcard: function(value, element) {
+			if ( this.optional(element) )
+				return "dependency-mismatch";
+			// accept only spaces, digits and dashes
+			if (/[^0-9 -]+/.test(value))
+				return false;
+			var nCheck = 0,
+				nDigit = 0,
+				bEven = false;
+
+			value = value.replace(/\D/g, "");
+
+			for (var n = value.length - 1; n >= 0; n--) {
+				var cDigit = value.charAt(n);
+				var nDigit = parseInt(cDigit, 10);
+				if (bEven) {
+					if ((nDigit *= 2) > 9)
+						nDigit -= 9;
+				}
+				nCheck += nDigit;
+				bEven = !bEven;
+			}
+
+			return (nCheck % 10) == 0;
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/accept
+		accept: function(value, element, param) {
+			param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
+			return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
+		},
+
+		// http://docs.jquery.com/Plugins/Validation/Methods/equalTo
+		equalTo: function(value, element, param) {
+			// bind to the blur event of the target in order to revalidate whenever the target field is updated
+			// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
+			var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
+				$(element).valid();
+			});
+			return value == target.val();
+		}
+
+	}
+
+});
+
+// deprecated, use $.validator.format instead
+$.format = $.validator.format;
+
+})(jQuery);
+
+// ajax mode: abort
+// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
+// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
+;(function($) {
+	var pendingRequests = {};
+	// Use a prefilter if available (1.5+)
+	if ( $.ajaxPrefilter ) {
+		$.ajaxPrefilter(function(settings, _, xhr) {
+			var port = settings.port;
+			if (settings.mode == "abort") {
+				if ( pendingRequests[port] ) {
+					pendingRequests[port].abort();
+				}
+				pendingRequests[port] = xhr;
+			}
+		});
+	} else {
+		// Proxy ajax
+		var ajax = $.ajax;
+		$.ajax = function(settings) {
+			var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
+				port = ( "port" in settings ? settings : $.ajaxSettings ).port;
+			if (mode == "abort") {
+				if ( pendingRequests[port] ) {
+					pendingRequests[port].abort();
+				}
+				return (pendingRequests[port] = ajax.apply(this, arguments));
+			}
+			return ajax.apply(this, arguments);
+		};
+	}
+})(jQuery);
+
+// provides cross-browser focusin and focusout events
+// IE has native support, in other browsers, use event caputuring (neither bubbles)
+
+// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
+// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
+;(function($) {
+	// only implement if not provided by jQuery core (since 1.4)
+	// TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
+	if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
+		$.each({
+			focus: 'focusin',
+			blur: 'focusout'
+		}, function( original, fix ){
+			$.event.special[fix] = {
+				setup:function() {
+					this.addEventListener( original, handler, true );
+				},
+				teardown:function() {
+					this.removeEventListener( original, handler, true );
+				},
+				handler: function(e) {
+					arguments[0] = $.event.fix(e);
+					arguments[0].type = fix;
+					return $.event.handle.apply(this, arguments);
+				}
+			};
+			function handler(e) {
+				e = $.event.fix(e);
+				e.type = fix;
+				return $.event.handle.call(this, e);
+			}
+		});
+	};
+	$.extend($.fn, {
+		validateDelegate: function(delegate, type, handler) {
+			return this.bind(type, function(event) {
+				var target = $(event.target);
+				if (target.is(delegate)) {
+					return handler.apply(target, arguments);
+				}
+			});
+		}
+	});
+})(jQuery);
diff --git a/ap/app/zte_webui/js/3rd/jqui.js b/ap/app/zte_webui/js/3rd/jqui.js
new file mode 100755
index 0000000..8ad022f
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/jqui.js
@@ -0,0 +1,6 @@
+/* jQuery UI - v1.11.1 - 2014-09-01
+* http://jqueryui.com
+* Includes: core.js, widget.js, mouse.js, slider.js
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}e.ui=e.ui||{},e.extend(e.ui,{version:"0.0.0",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var s=0,n=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,a=n.call(arguments,1),o=0,r=a.length;r>o;o++)for(i in a[o])s=a[o][i],a[o].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(a){var o="string"==typeof a,r=n.call(arguments,1),h=this;return a=!o&&r.length?e.widget.extend.apply(null,[a].concat(r)):a,o?this.each(function(){var i,n=e.data(this,s);return"instance"===a?(h=n,!1):n?e.isFunction(n[a])&&"_"!==a.charAt(0)?(i=n[a].apply(n,r),i!==n&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+a+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var t=e.data(this,s);t?(t.option(a||{}),t._init&&t._init()):e.data(this,s,new i(a,this))}),h}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=s++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var a=!1;e(document).mouseup(function(){a=!1}),e.widget("ui.mouse",{version:"0.0.0",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!a){this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),a=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):t.which?this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted):this._mouseUp(t)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),a=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),e.widget("ui.slider",e.ui.mouse,{version:"0.0.0",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},numPages:5,_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var t,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),a="<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",o=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),t=n.length;i>t;t++)o.push(a);this.handles=n.add(e(o.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(t){e(this).data("ui-slider-handle-index",t)})},_createRange:function(){var t=this.options,i="";t.range?(t.range===!0&&(t.values?t.values.length&&2!==t.values.length?t.values=[t.values[0],t.values[0]]:e.isArray(t.values)&&(t.values=t.values.slice(0)):t.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=e("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===t.range||"max"===t.range?" ui-slider-range-"+t.range:""))):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){this._off(this.handles),this._on(this.handles,this._handleEvents),this._hoverable(this.handles),this._focusable(this.handles)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(t){var i,s,n,a,o,r,h,l,u=this,d=this.options;return d.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:t.pageX,y:t.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(t){var i=Math.abs(s-u.values(t));(n>i||n===i&&(t===u._lastChangedValue||u.values(t)===d.min))&&(n=i,a=e(this),o=t)}),r=this._start(t,o),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,a.addClass("ui-state-active").focus(),h=a.offset(),l=!e(t.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:t.pageX-h.left-a.width()/2,top:t.pageY-h.top-a.height()/2-(parseInt(a.css("borderTopWidth"),10)||0)-(parseInt(a.css("borderBottomWidth"),10)||0)+(parseInt(a.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,o,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},i=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,i),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,i,s,n,a;return"horizontal"===this.orientation?(t=this.elementSize.width,i=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,i=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/t,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),a=this._valueMin()+s*n,this._trimAlignValue(a)},_start:function(e,t){var i={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("start",e,i)},_slide:function(e,t,i){var s,n,a;this.options.values&&this.options.values.length?(s=this.values(t?0:1),2===this.options.values.length&&this.options.range===!0&&(0===t&&i>s||1===t&&s>i)&&(i=s),i!==this.values(t)&&(n=this.values(),n[t]=i,a=this._trigger("slide",e,{handle:this.handles[t],value:i,values:n}),s=this.values(t?0:1),a!==!1&&this.values(t,i))):i!==this.value()&&(a=this._trigger("slide",e,{handle:this.handles[t],value:i}),a!==!1&&this.value(i))},_stop:function(e,t){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("stop",e,i)},_change:function(e,t){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._lastChangedValue=t,this._trigger("change",e,i)}},value:function(e){return arguments.length?(this.options.value=this._trimAlignValue(e),this._refreshValue(),this._change(null,0),void 0):this._value()},values:function(t,i){var s,n,a;if(arguments.length>1)return this.options.values[t]=this._trimAlignValue(i),this._refreshValue(),this._change(null,t),void 0;if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();for(s=this.options.values,n=arguments[0],a=0;s.length>a;a+=1)s[a]=this._trimAlignValue(n[a]),this._change(null,a);this._refreshValue()},_setOption:function(t,i){var s,n=0;switch("range"===t&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),e.isArray(this.options.values)&&(n=this.options.values.length),"disabled"===t&&this.element.toggleClass("ui-state-disabled",!!i),this._super(t,i),t){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue(),this.handles.css("horizontal"===i?"bottom":"left","");break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var e=this.options.value;return e=this._trimAlignValue(e)},_values:function(e){var t,i,s;if(arguments.length)return t=this.options.values[e],t=this._trimAlignValue(t);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(e){if(this._valueMin()>=e)return this._valueMin();if(e>=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,i=(e-this._valueMin())%t,s=e-i;return 2*Math.abs(i)>=t&&(s+=i>0?t:-t),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var t,i,s,n,a,o=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,u={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),u["horizontal"===h.orientation?"left":"bottom"]=i+"%",e(this).stop(1,1)[l?"animate":"css"](u,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-t+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-t+"%"},{queue:!1,duration:r.animate}))),t=i}):(s=this.value(),n=this._valueMin(),a=this._valueMax(),i=a!==n?100*((s-n)/(a-n)):0,u["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](u,r.animate),"min"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===o&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===o&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(t){var i,s,n,a,o=e(t.target).data("ui-slider-handle-index");switch(t.keyCode){case e.ui.keyCode.HOME:case e.ui.keyCode.END:case e.ui.keyCode.PAGE_UP:case e.ui.keyCode.PAGE_DOWN:case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(t.preventDefault(),!this._keySliding&&(this._keySliding=!0,e(t.target).addClass("ui-state-active"),i=this._start(t,o),i===!1))return}switch(a=this.options.step,s=n=this.options.values&&this.options.values.length?this.values(o):this.value(),t.keyCode){case e.ui.keyCode.HOME:n=this._valueMin();break;case e.ui.keyCode.END:n=this._valueMax();break;case e.ui.keyCode.PAGE_UP:n=this._trimAlignValue(s+(this._valueMax()-this._valueMin())/this.numPages);break;case e.ui.keyCode.PAGE_DOWN:n=this._trimAlignValue(s-(this._valueMax()-this._valueMin())/this.numPages);break;case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:if(s===this._valueMax())return;n=this._trimAlignValue(s+a);break;case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(s===this._valueMin())return;n=this._trimAlignValue(s-a)}this._slide(t,o,n)},keyup:function(t){var i=e(t.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(t,i),this._change(t,i),e(t.target).removeClass("ui-state-active"))}}})});
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/knockout.base.js b/ap/app/zte_webui/js/3rd/knockout.base.js
new file mode 100755
index 0000000..226a50a
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/knockout.base.js
@@ -0,0 +1,124 @@
+/*
+ * Knockout JavaScript library v3.4.2
+ * (c) The Knockout.js team - http://knockoutjs.com/
+ * License: MIT (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+(function() {(function(n){var x=this||(0,eval)("this"),t=x.document,M=x.navigator,u=x.jQuery,H=x.JSON;(function(n){"function"===typeof define&&define.amd?define(["exports","require"],n):"object"===typeof exports&&"object"===typeof module?n(module.exports||exports):n(x.ko={})})(function(N,O){function J(a,c){return null===a||typeof a in R?a===c:!1}function S(b,c){var d;return function(){d||(d=a.a.setTimeout(function(){d=n;b()},c))}}function T(b,c){var d;return function(){clearTimeout(d);d=a.a.setTimeout(b,c)}}function U(a,
+c){c&&c!==E?"beforeChange"===c?this.Ob(a):this.Ja(a,c):this.Pb(a)}function V(a,c){null!==c&&c.k&&c.k()}function W(a,c){var d=this.Mc,e=d[s];e.T||(this.ob&&this.Oa[c]?(d.Sb(c,a,this.Oa[c]),this.Oa[c]=null,--this.ob):e.s[c]||d.Sb(c,a,e.t?{$:a}:d.yc(a)),a.Ha&&a.Hc())}function K(b,c,d,e){a.d[b]={init:function(b,g,h,l,m){var k,r;a.m(function(){var q=g(),p=a.a.c(q),p=!d!==!p,A=!r;if(A||c||p!==k)A&&a.xa.Ca()&&(r=a.a.wa(a.f.childNodes(b),!0)),p?(A||a.f.fa(b,a.a.wa(r)),a.hb(e?e(m,q):m,b)):a.f.za(b),k=p},null,
+{i:b});return{controlsDescendantBindings:!0}}};a.h.va[b]=!1;a.f.aa[b]=!0}var a="undefined"!==typeof N?N:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.H=function(a,c,d){a[c]=d};a.version="0.0.0";a.b("version",a.version);a.options={deferUpdates:!1,useOnlyNativeEvents:!1};a.a=function(){function b(a,b){for(var c in a)a.hasOwnProperty(c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=
+b;return a}function e(b,c,d,e){var m=b[c].match(r)||[];a.a.r(d.match(r),function(b){a.a.ra(m,b,e)});b[c]=m.join(" ")}var f={__proto__:[]}instanceof Array,g="function"===typeof Symbol,h={},l={};h[M&&/Firefox\/2/i.test(M.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];h.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(h,function(a,b){if(b.length)for(var c=0,d=b.length;c<d;c++)l[b[c]]=a});var m={propertychange:!0},k=
+t&&function(){for(var a=3,b=t.createElement("div"),c=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:n}(),r=/\S+/g;return{gc:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],r:function(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c],c)},o:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},Vb:function(a,b,c){for(var d=
+0,e=a.length;d<e;d++)if(b.call(c,a[d],d))return a[d];return null},Na:function(b,c){var d=a.a.o(b,c);0<d?b.splice(d,1):0===d&&b.shift()},Wb:function(b){b=b||[];for(var c=[],d=0,e=b.length;d<e;d++)0>a.a.o(c,b[d])&&c.push(b[d]);return c},ib:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)c.push(b(a[d],d));return c},Ma:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)b(a[d],d)&&c.push(a[d]);return c},ta:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var c=0,d=b.length;c<
+d;c++)a.push(b[c]);return a},ra:function(b,c,d){var e=a.a.o(a.a.Bb(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},la:f,extend:c,$a:d,ab:f?d:c,D:b,Ea:function(a,b){if(!a)return a;var c={},d;for(d in a)a.hasOwnProperty(d)&&(c[d]=b(a[d],d,a));return c},rb:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},nc:function(b){b=a.a.W(b);for(var c=(b[0]&&b[0].ownerDocument||t).createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.ba(b[d]));return c},wa:function(b,c){for(var d=0,e=b.length,m=[];d<e;d++){var k=
+b[d].cloneNode(!0);m.push(c?a.ba(k):k)}return m},fa:function(b,c){a.a.rb(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},uc:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],m=e.parentNode,k=0,f=c.length;k<f;k++)m.insertBefore(c[k],e);k=0;for(f=d.length;k<f;k++)a.removeNode(d[k])}},Ba:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);for(;1<a.length&&a[a.length-1].parentNode!==b;)a.length--;if(1<a.length){var c=
+a[0],d=a[a.length-1];for(a.length=0;c!==d;)a.push(c),c=c.nextSibling;a.push(d)}}return a},wc:function(a,b){7>k?a.setAttribute("selected",b):a.selected=b},cb:function(a){return null===a||a===n?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},sd:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Rc:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==
+(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;return!!a},qb:function(b){return a.a.Rc(b,b.ownerDocument.documentElement)},Tb:function(b){return!!a.a.Vb(b,a.a.qb)},A:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},Zb:function(b){return a.onError?function(){try{return b.apply(this,arguments)}catch(c){throw a.onError&&a.onError(c),c;}}:b},setTimeout:function(b,c){return setTimeout(a.a.Zb(b),c)},dc:function(b){setTimeout(function(){a.onError&&a.onError(b);throw b;},0)},q:function(b,
+c,d){var e=a.a.Zb(d);d=k&&m[c];if(a.options.useOnlyNativeEvents||d||!u)if(d||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var f=function(a){e.call(b,a)},l="on"+c;b.attachEvent(l,f);a.a.G.qa(b,function(){b.detachEvent(l,f)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,e,!1);else u(b).bind(c,e)},Fa:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===
+a.a.A(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==d||"radio"==d):d=!1;if(a.options.useOnlyNativeEvents||!u||d)if("function"==typeof t.createEvent)if("function"==typeof b.dispatchEvent)d=t.createEvent(l[c]||"HTMLEvents"),d.initEvent(c,!0,!0,x,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");
+else u(b).trigger(c)},c:function(b){return a.I(b)?b():b},Bb:function(b){return a.I(b)?b.p():b},fb:function(b,c,d){var k;c&&("object"===typeof b.classList?(k=b.classList[d?"add":"remove"],a.a.r(c.match(r),function(a){k.call(b.classList,a)})):"string"===typeof b.className.baseVal?e(b.className,"baseVal",c,d):e(b,"className",c,d))},bb:function(b,c){var d=a.a.c(c);if(null===d||d===n)d="";var e=a.f.firstChild(b);!e||3!=e.nodeType||a.f.nextSibling(e)?a.f.fa(b,[b.ownerDocument.createTextNode(d)]):e.data=
+d;a.a.Wc(b)},vc:function(a,b){a.name=b;if(7>=k)try{var escapedName=a.name.replace(/[&<>'"]/g,function(r){return "&#"+r.charCodeAt(0)+";";});a.mergeAttributes(t.createElement("<input name='"+escapedName+"'/>"),!1)}catch(c){}},Wc:function(a){9<=k&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Sc:function(a){if(k){var b=a.style.width;a.style.width=0;a.style.width=b}},nd:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var d=[],e=b;e<=c;e++)d.push(e);return d},W:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},bc:function(a){return g?Symbol(a):a},xd:6===k,
+yd:7===k,C:k,ic:function(b,c){for(var d=a.a.W(b.getElementsByTagName("input")).concat(a.a.W(b.getElementsByTagName("textarea"))),e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},k=[],m=d.length-1;0<=m;m--)e(d[m])&&k.push(d[m]);return k},kd:function(b){return"string"==typeof b&&(b=a.a.cb(b))?H&&H.parse?H.parse(b):(new Function("return "+b))():null},Gb:function(b,c,d){if(!H||!H.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
+return H.stringify(a.a.c(b),c,d)},ld:function(c,d,e){e=e||{};var k=e.params||{},m=e.includeFields||this.gc,f=c;if("object"==typeof c&&"form"===a.a.A(c))for(var f=c.action,l=m.length-1;0<=l;l--)for(var g=a.a.ic(c,m[l]),h=g.length-1;0<=h;h--)k[g[h].name]=g[h].value;d=a.a.c(d);var r=t.createElement("form");r.style.display="none";r.action=f;r.method="post";for(var n in d)c=t.createElement("input"),c.type="hidden",c.name=n,c.value=a.a.Gb(a.a.c(d[n])),r.appendChild(c);b(k,function(a,b){var c=t.createElement("input");
+c.type="hidden";c.name=a;c.value=b;r.appendChild(c)});t.body.appendChild(r);e.submitter?e.submitter(r):r.submit();setTimeout(function(){r.parentNode.removeChild(r)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.r);a.b("utils.arrayFirst",a.a.Vb);a.b("utils.arrayFilter",a.a.Ma);a.b("utils.arrayGetDistinctValues",a.a.Wb);a.b("utils.arrayIndexOf",a.a.o);a.b("utils.arrayMap",a.a.ib);a.b("utils.arrayPushAll",a.a.ta);a.b("utils.arrayRemoveItem",a.a.Na);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",
+a.a.gc);a.b("utils.getFormFields",a.a.ic);a.b("utils.peekObservable",a.a.Bb);a.b("utils.postJson",a.a.ld);a.b("utils.parseJson",a.a.kd);a.b("utils.registerEventHandler",a.a.q);a.b("utils.stringifyJson",a.a.Gb);a.b("utils.range",a.a.nd);a.b("utils.toggleDomNodeCssClass",a.a.fb);a.b("utils.triggerEvent",a.a.Fa);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.D);a.b("utils.addOrRemoveItem",a.a.ra);a.b("utils.setTextContent",a.a.bb);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=
+function(a){var c=this;if(1===arguments.length)return function(){return c.apply(a,arguments)};var d=Array.prototype.slice.call(arguments,1);return function(){var e=d.slice(0);e.push.apply(e,arguments);return c.apply(a,e)}});a.a.e=new function(){function a(b,g){var h=b[d];if(!h||"null"===h||!e[h]){if(!g)return n;h=b[d]="ko"+c++;e[h]={}}return e[h]}var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===n?n:e[d]},set:function(c,d,e){if(e!==n||a(c,!1)!==n)a(c,!0)[d]=
+e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},J:function(){return c++ +d}}};a.b("utils.domData",a.a.e);a.b("utils.domData.clear",a.a.e.clear);a.a.G=new function(){function b(b,c){var e=a.a.e.get(b,d);e===n&&c&&(e=[],a.a.e.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),l=0;l<e.length;l++)e[l](d);a.a.e.clear(d);a.a.G.cleanExternalData(d);if(f[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.e.J(),e={1:!0,8:!0,9:!0},
+f={1:!0,9:!0};return{qa:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},tc:function(c,e){var f=b(c,!1);f&&(a.a.Na(f,e),0==f.length&&a.a.e.set(c,d,n))},ba:function(b){if(e[b.nodeType]&&(c(b),f[b.nodeType])){var d=[];a.a.ta(d,b.getElementsByTagName("*"));for(var l=0,m=d.length;l<m;l++)c(d[l])}return b},removeNode:function(b){a.ba(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){u&&"function"==typeof u.cleanData&&u.cleanData([a])}}};
+a.ba=a.a.G.ba;a.removeNode=a.a.G.removeNode;a.b("cleanNode",a.ba);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.G);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.G.qa);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.G.tc);(function(){var b=[0,"",""],c=[1,"<table>","</table>"],d=[3,"<table><tbody><tr>","</tr></tbody></table>"],e=[1,"<select multiple='multiple'>","</select>"],f={thead:c,tbody:c,tfoot:c,tr:[2,"<table><tbody>","</tbody></table>"],td:d,th:d,option:e,optgroup:e},
+g=8>=a.a.C;a.a.na=function(c,d){var e;if(u)if(u.parseHTML)e=u.parseHTML(c,d)||[];else{if((e=u.clean([c],d))&&e[0]){for(var k=e[0];k.parentNode&&11!==k.parentNode.nodeType;)k=k.parentNode;k.parentNode&&k.parentNode.removeChild(k)}}else{(e=d)||(e=t);var k=e.parentWindow||e.defaultView||x,r=a.a.cb(c).toLowerCase(),q=e.createElement("div"),p;p=(r=r.match(/^<([a-z]+)[ >]/))&&f[r[1]]||b;r=p[0];p="ignored<div>"+p[1]+c+p[2]+"</div>";"function"==typeof k.innerShiv?q.appendChild(k.innerShiv(p)):(g&&e.appendChild(q),
+q.innerHTML=p,g&&q.parentNode.removeChild(q));for(;r--;)q=q.lastChild;e=a.a.W(q.lastChild.childNodes)}return e};a.a.Eb=function(b,c){a.a.rb(b);c=a.a.c(c);if(null!==c&&c!==n)if("string"!=typeof c&&(c=c.toString()),u)u(b).html(c);else for(var d=a.a.na(c,b.ownerDocument),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.na);a.b("utils.setHtml",a.a.Eb);a.N=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.N.pc(c.nodeValue);null!=f&&e.push({Qc:c,hd:f})}else if(1==c.nodeType)for(var f=
+0,g=c.childNodes,h=g.length;f<h;f++)b(g[f],e)}var c={};return{yb:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},Bc:function(a,b){var f=c[a];if(f===n)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),
+!0}finally{delete c[a]}},Cc:function(c,e){var f=[];b(c,f);for(var g=0,h=f.length;g<h;g++){var l=f[g].Qc,m=[l];e&&a.a.ta(m,e);a.N.Bc(f[g].hd,m);l.nodeValue="";l.parentNode&&l.parentNode.removeChild(l)}},pc:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.N);a.b("memoization.memoize",a.N.yb);a.b("memoization.unmemoize",a.N.Bc);a.b("memoization.parseMemoText",a.N.pc);a.b("memoization.unmemoizeDomNodeAndDescendants",a.N.Cc);a.Z=function(){function b(){if(e)for(var b=
+e,c=0,m;g<e;)if(m=d[g++]){if(g>b){if(5E3<=++c){g=e;a.a.dc(Error("'Too much recursion' after processing "+c+" task groups."));break}b=e}try{m()}catch(k){a.a.dc(k)}}}function c(){b();g=e=d.length=0}var d=[],e=0,f=1,g=0;return{scheduler:x.MutationObserver?function(a){var b=t.createElement("div");(new MutationObserver(a)).observe(b,{attributes:!0});return function(){b.classList.toggle("foo")}}(c):t&&"onreadystatechange"in t.createElement("script")?function(a){var b=t.createElement("script");b.onreadystatechange=
+function(){b.onreadystatechange=null;t.documentElement.removeChild(b);b=null;a()};t.documentElement.appendChild(b)}:function(a){setTimeout(a,0)},Za:function(b){e||a.Z.scheduler(c);d[e++]=b;return f++},cancel:function(a){a-=f-e;a>=g&&a<e&&(d[a]=null)},resetForTesting:function(){var a=e-g;g=e=d.length=0;return a},rd:b}}();a.b("tasks",a.Z);a.b("tasks.schedule",a.Z.Za);a.b("tasks.runEarly",a.Z.rd);a.Aa={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.B({read:b,write:function(e){clearTimeout(d);
+d=a.a.setTimeout(function(){b(e)},c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);a.gb=!1;f="notifyWhenChangesStop"==e?T:S;a.Wa(function(a){return f(a,d)})},deferred:function(b,c){if(!0!==c)throw Error("The 'deferred' extender only accepts the value 'true', because it is not supported to turn deferral off once enabled.");b.gb||(b.gb=!0,b.Wa(function(c){var e,f=!1;return function(){if(!f){a.Z.cancel(e);e=a.Z.Za(c);try{f=!0,b.notifySubscribers(n,"dirty")}finally{f=
+!1}}}}))},notify:function(a,c){a.equalityComparer="always"==c?null:J}};var R={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.Aa);a.zc=function(b,c,d){this.$=b;this.jb=c;this.Pc=d;this.T=!1;a.H(this,"dispose",this.k)};a.zc.prototype.k=function(){this.T=!0;this.Pc()};a.K=function(){a.a.ab(this,D);D.ub(this)};var E="change",D={ub:function(a){a.F={change:[]};a.Qb=1},Y:function(b,c,d){var e=this;d=d||E;var f=new a.zc(e,c?b.bind(c):b,function(){a.a.Na(e.F[d],f);e.Ka&&e.Ka(d)});e.ua&&e.ua(d);
+e.F[d]||(e.F[d]=[]);e.F[d].push(f);return f},notifySubscribers:function(b,c){c=c||E;c===E&&this.Kb();if(this.Ra(c)){var d=c===E&&this.Fc||this.F[c].slice(0);try{a.l.Xb();for(var e=0,f;f=d[e];++e)f.T||f.jb(b)}finally{a.l.end()}}},Pa:function(){return this.Qb},Zc:function(a){return this.Pa()!==a},Kb:function(){++this.Qb},Wa:function(b){var c=this,d=a.I(c),e,f,g,h;c.Ja||(c.Ja=c.notifySubscribers,c.notifySubscribers=U);var l=b(function(){c.Ha=!1;d&&h===c&&(h=c.Mb?c.Mb():c());var a=f||c.Ua(g,h);f=e=!1;
+a&&c.Ja(g=h)});c.Pb=function(a){c.Fc=c.F[E].slice(0);c.Ha=e=!0;h=a;l()};c.Ob=function(a){e||(g=a,c.Ja(a,"beforeChange"))};c.Hc=function(){c.Ua(g,c.p(!0))&&(f=!0)}},Ra:function(a){return this.F[a]&&this.F[a].length},Xc:function(b){if(b)return this.F[b]&&this.F[b].length||0;var c=0;a.a.D(this.F,function(a,b){"dirty"!==a&&(c+=b.length)});return c},Ua:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},extend:function(b){var c=this;b&&a.a.D(b,function(b,e){var f=a.Aa[b];"function"==
+typeof f&&(c=f(c,e)||c)});return c}};a.H(D,"subscribe",D.Y);a.H(D,"extend",D.extend);a.H(D,"getSubscriptionsCount",D.Xc);a.a.la&&a.a.$a(D,Function.prototype);a.K.fn=D;a.lc=function(a){return null!=a&&"function"==typeof a.Y&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.K);a.b("isSubscribable",a.lc);a.xa=a.l=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{Xb:b,end:c,sc:function(b){if(e){if(!a.lc(b))throw Error("Only subscribable things can act as dependencies");
+e.jb.call(e.Lc,b,b.Gc||(b.Gc=++f))}},w:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},Ca:function(){if(e)return e.m.Ca()},Va:function(){if(e)return e.Va}}}();a.b("computedContext",a.xa);a.b("computedContext.getDependenciesCount",a.xa.Ca);a.b("computedContext.isInitial",a.xa.Va);a.b("ignoreDependencies",a.wd=a.l.w);var F=a.a.bc("_latestValue");a.O=function(b){function c(){if(0<arguments.length)return c.Ua(c[F],arguments[0])&&(c.ia(),c[F]=arguments[0],c.ha()),this;a.l.sc(c);return c[F]}
+c[F]=b;a.a.la||a.a.extend(c,a.K.fn);a.K.fn.ub(c);a.a.ab(c,B);a.options.deferUpdates&&a.Aa.deferred(c,!0);return c};var B={equalityComparer:J,p:function(){return this[F]},ha:function(){this.notifySubscribers(this[F])},ia:function(){this.notifySubscribers(this[F],"beforeChange")}};a.a.la&&a.a.$a(B,a.K.fn);var I=a.O.md="__ko_proto__";B[I]=a.O;a.Qa=function(b,c){return null===b||b===n||b[I]===n?!1:b[I]===c?!0:a.Qa(b[I],c)};a.I=function(b){return a.Qa(b,a.O)};a.Da=function(b){return"function"==typeof b&&
+b[I]===a.O||"function"==typeof b&&b[I]===a.B&&b.$c?!0:!1};a.b("observable",a.O);a.b("isObservable",a.I);a.b("isWriteableObservable",a.Da);a.b("isWritableObservable",a.Da);a.b("observable.fn",B);a.H(B,"peek",B.p);a.H(B,"valueHasMutated",B.ha);a.H(B,"valueWillMutate",B.ia);a.ma=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.O(b);a.a.ab(b,a.ma.fn);return b.extend({trackArrayChanges:!0})};
+a.ma.fn={remove:function(b){for(var c=this.p(),d=[],e="function"!=typeof b||a.I(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var g=c[f];e(g)&&(0===d.length&&this.ia(),d.push(g),c.splice(f,1),f--)}d.length&&this.ha();return d},removeAll:function(b){if(b===n){var c=this.p(),d=c.slice(0);this.ia();c.splice(0,c.length);this.ha();return d}return b?this.remove(function(c){return 0<=a.a.o(b,c)}):[]},destroy:function(b){var c=this.p(),d="function"!=typeof b||a.I(b)?function(a){return a===b}:b;this.ia();
+for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.ha()},destroyAll:function(b){return b===n?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.o(b,c)}):[]},indexOf:function(b){var c=this();return a.a.o(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.ia(),this.p()[d]=c,this.ha())}};a.a.la&&a.a.$a(a.ma.fn,a.O.fn);a.a.r("pop push reverse shift sort splice unshift".split(" "),function(b){a.ma.fn[b]=function(){var a=this.p();this.ia();this.Yb(a,b,arguments);
+var d=a[b].apply(a,arguments);this.ha();return d===a?this:d}});a.a.r(["slice"],function(b){a.ma.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.ma);a.Aa.trackArrayChanges=function(b,c){function d(){if(!e){e=!0;l=b.notifySubscribers;b.notifySubscribers=function(a,b){b&&b!==E||++h;return l.apply(this,arguments)};var c=[].concat(b.p()||[]);f=null;g=b.Y(function(d){d=[].concat(d||[]);if(b.Ra("arrayChange")){var e;if(!f||1<h)f=a.a.lb(c,d,b.kb);e=f}c=d;f=null;h=0;
+e&&e.length&&b.notifySubscribers(e,"arrayChange")})}}b.kb={};c&&"object"==typeof c&&a.a.extend(b.kb,c);b.kb.sparse=!0;if(!b.Yb){var e=!1,f=null,g,h=0,l,m=b.ua,k=b.Ka;b.ua=function(a){m&&m.call(b,a);"arrayChange"===a&&d()};b.Ka=function(a){k&&k.call(b,a);"arrayChange"!==a||b.Ra("arrayChange")||(l&&(b.notifySubscribers=l,l=n),g.k(),e=!1)};b.Yb=function(b,c,d){function k(a,b,c){return m[m.length]={status:a,value:b,index:c}}if(e&&!h){var m=[],l=b.length,g=d.length,G=0;switch(c){case "push":G=l;case "unshift":for(c=
+0;c<g;c++)k("added",d[c],G+c);break;case "pop":G=l-1;case "shift":l&&k("deleted",b[G],G);break;case "splice":c=Math.min(Math.max(0,0>d[0]?l+d[0]:d[0]),l);for(var l=1===g?l:Math.min(c+(d[1]||0),l),g=c+g-2,G=Math.max(l,g),n=[],s=[],w=2;c<G;++c,++w)c<l&&s.push(k("deleted",b[c],c)),c<g&&n.push(k("added",d[w],c));a.a.hc(s,n);break;default:return}f=m}}}};var s=a.a.bc("_state");a.m=a.B=function(b,c,d){function e(){if(0<arguments.length){if("function"===typeof f)f.apply(g.sb,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
+return this}a.l.sc(e);(g.V||g.t&&e.Sa())&&e.U();return g.M}"object"===typeof b?d=b:(d=d||{},b&&(d.read=b));if("function"!=typeof d.read)throw Error("Pass a function that returns the value of the ko.computed");var f=d.write,g={M:n,da:!0,V:!0,Ta:!1,Hb:!1,T:!1,Ya:!1,t:!1,od:d.read,sb:c||d.owner,i:d.disposeWhenNodeIsRemoved||d.i||null,ya:d.disposeWhen||d.ya,pb:null,s:{},L:0,fc:null};e[s]=g;e.$c="function"===typeof f;a.a.la||a.a.extend(e,a.K.fn);a.K.fn.ub(e);a.a.ab(e,z);d.pure?(g.Ya=!0,g.t=!0,a.a.extend(e,
+Y)):d.deferEvaluation&&a.a.extend(e,Z);a.options.deferUpdates&&a.Aa.deferred(e,!0);g.i&&(g.Hb=!0,g.i.nodeType||(g.i=null));g.t||d.deferEvaluation||e.U();g.i&&e.ca()&&a.a.G.qa(g.i,g.pb=function(){e.k()});return e};var z={equalityComparer:J,Ca:function(){return this[s].L},Sb:function(a,c,d){if(this[s].Ya&&c===this)throw Error("A 'pure' computed must not be called recursively");this[s].s[a]=d;d.Ia=this[s].L++;d.pa=c.Pa()},Sa:function(){var a,c,d=this[s].s;for(a in d)if(d.hasOwnProperty(a)&&(c=d[a],this.oa&&
+c.$.Ha||c.$.Zc(c.pa)))return!0},gd:function(){this.oa&&!this[s].Ta&&this.oa(!1)},ca:function(){var a=this[s];return a.V||0<a.L},qd:function(){this.Ha?this[s].V&&(this[s].da=!0):this.ec()},yc:function(a){if(a.gb&&!this[s].i){var c=a.Y(this.gd,this,"dirty"),d=a.Y(this.qd,this);return{$:a,k:function(){c.k();d.k()}}}return a.Y(this.ec,this)},ec:function(){var b=this,c=b.throttleEvaluation;c&&0<=c?(clearTimeout(this[s].fc),this[s].fc=a.a.setTimeout(function(){b.U(!0)},c)):b.oa?b.oa(!0):b.U(!0)},U:function(b){var c=
+this[s],d=c.ya,e=!1;if(!c.Ta&&!c.T){if(c.i&&!a.a.qb(c.i)||d&&d()){if(!c.Hb){this.k();return}}else c.Hb=!1;c.Ta=!0;try{e=this.Vc(b)}finally{c.Ta=!1}c.L||this.k();return e}},Vc:function(b){var c=this[s],d=!1,e=c.Ya?n:!c.L,f={Mc:this,Oa:c.s,ob:c.L};a.l.Xb({Lc:f,jb:W,m:this,Va:e});c.s={};c.L=0;f=this.Uc(c,f);this.Ua(c.M,f)&&(c.t||this.notifySubscribers(c.M,"beforeChange"),c.M=f,c.t?this.Kb():b&&this.notifySubscribers(c.M),d=!0);e&&this.notifySubscribers(c.M,"awake");return d},Uc:function(b,c){try{var d=
+b.od;return b.sb?d.call(b.sb):d()}finally{a.l.end(),c.ob&&!b.t&&a.a.D(c.Oa,V),b.da=b.V=!1}},p:function(a){var c=this[s];(c.V&&(a||!c.L)||c.t&&this.Sa())&&this.U();return c.M},Wa:function(b){a.K.fn.Wa.call(this,b);this.Mb=function(){this[s].da?this.U():this[s].V=!1;return this[s].M};this.oa=function(a){this.Ob(this[s].M);this[s].V=!0;a&&(this[s].da=!0);this.Pb(this)}},k:function(){var b=this[s];!b.t&&b.s&&a.a.D(b.s,function(a,b){b.k&&b.k()});b.i&&b.pb&&a.a.G.tc(b.i,b.pb);b.s=null;b.L=0;b.T=!0;b.da=
+!1;b.V=!1;b.t=!1;b.i=null}},Y={ua:function(b){var c=this,d=c[s];if(!d.T&&d.t&&"change"==b){d.t=!1;if(d.da||c.Sa())d.s=null,d.L=0,c.U()&&c.Kb();else{var e=[];a.a.D(d.s,function(a,b){e[b.Ia]=a});a.a.r(e,function(a,b){var e=d.s[a],l=c.yc(e.$);l.Ia=b;l.pa=e.pa;d.s[a]=l})}d.T||c.notifySubscribers(d.M,"awake")}},Ka:function(b){var c=this[s];c.T||"change"!=b||this.Ra("change")||(a.a.D(c.s,function(a,b){b.k&&(c.s[a]={$:b.$,Ia:b.Ia,pa:b.pa},b.k())}),c.t=!0,this.notifySubscribers(n,"asleep"))},Pa:function(){var b=
+this[s];b.t&&(b.da||this.Sa())&&this.U();return a.K.fn.Pa.call(this)}},Z={ua:function(a){"change"!=a&&"beforeChange"!=a||this.p()}};a.a.la&&a.a.$a(z,a.K.fn);var P=a.O.md;a.m[P]=a.O;z[P]=a.m;a.bd=function(b){return a.Qa(b,a.m)};a.cd=function(b){return a.Qa(b,a.m)&&b[s]&&b[s].Ya};a.b("computed",a.m);a.b("dependentObservable",a.m);a.b("isComputed",a.bd);a.b("isPureComputed",a.cd);a.b("computed.fn",z);a.H(z,"peek",z.p);a.H(z,"dispose",z.k);a.H(z,"isActive",z.ca);a.H(z,"getDependenciesCount",z.Ca);a.rc=
+function(b,c){if("function"===typeof b)return a.m(b,c,{pure:!0});b=a.a.extend({},b);b.pure=!0;return a.m(b,c)};a.b("pureComputed",a.rc);(function(){function b(a,f,g){g=g||new d;a=f(a);if("object"!=typeof a||null===a||a===n||a instanceof RegExp||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var h=a instanceof Array?[]:{};g.save(a,h);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":h[c]=d;break;case "object":case "undefined":var k=
+g.get(d);h[c]=k!==n?k:b(d,f,g)}});return h}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.Lb=[]}a.Ac=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.I(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.Ac(b);return a.a.Gb(b,c,d)};d.prototype={save:function(b,c){var d=a.a.o(this.keys,
+b);0<=d?this.Lb[d]=c:(this.keys.push(b),this.Lb.push(c))},get:function(b){b=a.a.o(this.keys,b);return 0<=b?this.Lb[b]:n}}})();a.b("toJS",a.Ac);a.b("toJSON",a.toJSON);(function(){a.j={u:function(b){switch(a.a.A(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.e.get(b,a.d.options.zb):7>=a.a.C?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex]):n;default:return b.value}},ja:function(b,
+c,d){switch(a.a.A(b)){case "option":switch(typeof c){case "string":a.a.e.set(b,a.d.options.zb,n);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.e.set(b,a.d.options.zb,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":if(""===c||null===c)c=n;for(var e=-1,f=0,g=b.options.length,h;f<g;++f)if(h=a.j.u(b.options[f]),h==c||""==h&&c===n){e=f;break}if(d||0<=e||c===n&&1<b.size)b.selectedIndex=e;break;default:if(null===
+c||c===n)c="";b.value=c}}}})();a.b("selectExtensions",a.j);a.b("selectExtensions.readValue",a.j.u);a.b("selectExtensions.writeValue",a.j.ja);a.h=function(){function b(b){b=a.a.cb(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=[],d=b.match(e),r,h=[],p=0;if(d){d.push(",");for(var A=0,y;y=d[A];++A){var v=y.charCodeAt(0);if(44===v){if(0>=p){c.push(r&&h.length?{key:r,value:h.join("")}:{unknown:r||h.join("")});r=p=0;h=[];continue}}else if(58===v){if(!p&&!r&&1===h.length){r=h.pop();continue}}else 47===
+v&&A&&1<y.length?(v=d[A-1].match(f))&&!g[v[0]]&&(b=b.substr(b.indexOf(y)+1),d=b.match(e),d.push(","),A=-1,y="/"):40===v||123===v||91===v?++p:41===v||125===v||93===v?--p:r||h.length||34!==v&&39!==v||(y=y.slice(1,-1));h.push(y)}}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,
+g={"in":1,"return":1,"typeof":1},h={};return{va:[],ga:h,Ab:b,Xa:function(e,m){function k(b,e){var m;if(!A){var l=a.getBindingHandler(b);if(l&&l.preprocess&&!(e=l.preprocess(e,b,k)))return;if(l=h[b])m=e,0<=a.a.o(c,m)?m=!1:(l=m.match(d),m=null===l?!1:l[1]?"Object("+l[1]+")"+l[2]:m),l=m;l&&g.push("'"+b+"':function(_z){"+m+"=_z}")}p&&(e="function(){return "+e+" }");f.push("'"+b+"':"+e)}m=m||{};var f=[],g=[],p=m.valueAccessors,A=m.bindingParams,y="string"===typeof e?b(e):e;a.a.r(y,function(a){k(a.key||
+a.unknown,a.value)});g.length&&k("_ko_property_writers","{"+g.join(",")+" }");return f.join(",")},fd:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},Ga:function(b,c,d,e,f){if(b&&a.I(b))!a.Da(b)||f&&b.p()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.h);a.b("expressionRewriting.bindingRewriteValidators",a.h.va);a.b("expressionRewriting.parseObjectLiteral",a.h.Ab);a.b("expressionRewriting.preProcessBindings",a.h.Xa);a.b("expressionRewriting._twoWayBindings",
+a.h.ga);a.b("jsonExpressionRewriting",a.h);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.h.Xa);(function(){function b(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&h.test(f?a.text:a.nodeValue)}function d(a,d){for(var e=a,f=1,l=[];e=e.nextSibling;){if(c(e)&&(f--,0===f))return l;l.push(e);b(e)&&f++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-
+1].nextSibling:a.nextSibling:null}var f=t&&"\x3c!--test--\x3e"===t.createComment("test").text,g=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,h=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,l={ul:!0,ol:!0};a.f={aa:{},childNodes:function(a){return b(a)?d(a):a.childNodes},za:function(c){if(b(c)){c=a.f.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.rb(c)},fa:function(c,d){if(b(c)){a.f.za(c);for(var e=c.nextSibling,f=0,l=d.length;f<l;f++)e.parentNode.insertBefore(d[f],
+e)}else a.a.fa(c,d)},qc:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},kc:function(c,d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):c.appendChild(d):a.f.qc(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Yc:b,vd:function(a){return(a=
+(f?a.text:a.nodeValue).match(g))?a[1]:null},oc:function(d){if(l[a.a.A(d)]){var k=d.firstChild;if(k){do if(1===k.nodeType){var f;f=k.firstChild;var g=null;if(f){do if(g)g.push(f);else if(b(f)){var h=e(f,!0);h?f=h:g=[f]}else c(f)&&(g=[f]);while(f=f.nextSibling)}if(f=g)for(g=k.nextSibling,h=0;h<f.length;h++)g?d.insertBefore(f[h],g):d.appendChild(f[h])}while(k=k.nextSibling)}}}}})();a.b("virtualElements",a.f);a.b("virtualElements.allowedBindings",a.f.aa);a.b("virtualElements.emptyNode",a.f.za);a.b("virtualElements.insertAfter",
+a.f.kc);a.b("virtualElements.prepend",a.f.qc);a.b("virtualElements.setDomNodeChildren",a.f.fa);(function(){a.S=function(){this.Kc={}};a.a.extend(a.S.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=b.getAttribute("data-bind")||a.g.getComponentNameForNode(b);case 8:return a.f.Yc(b);default:return!1}},getBindings:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b):null;return a.g.Rb(d,b,c,!1)},getBindingAccessors:function(b,c){var d=this.getBindingsString(b,
+c),d=d?this.parseBindingsString(d,c,b,{valueAccessors:!0}):null;return a.g.Rb(d,b,c,!0)},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.f.vd(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var f=this.Kc,g=b+(e&&e.valueAccessors||""),h;if(!(h=f[g])){var l,m="with($context){with($data||{}){return{"+a.h.Xa(b,e)+"}}}";l=new Function("$context","$element",m);h=f[g]=l}return h(c,d)}catch(k){throw k.message="Unable to parse bindings.\nBindings value: "+
+b+"\nMessage: "+k.message,k;}}});a.S.instance=new a.S})();a.b("bindingProvider",a.S);(function(){function b(a){return function(){return a}}function c(a){return a()}function d(b){return a.a.Ea(a.l.w(b),function(a,c){return function(){return b()[c]}})}function e(c,e,k){return"function"===typeof c?d(c.bind(null,e,k)):a.a.Ea(c,b)}function f(a,b){return d(this.getBindings.bind(this,a,b))}function g(b,c,d){var e,k=a.f.firstChild(c),f=a.S.instance,m=f.preprocessNode;if(m){for(;e=k;)k=a.f.nextSibling(e),
+m.call(f,e);k=a.f.firstChild(c)}for(;e=k;)k=a.f.nextSibling(e),h(b,e,d)}function h(b,c,d){var e=!0,k=1===c.nodeType;k&&a.f.oc(c);if(k&&d||a.S.instance.nodeHasBindings(c))e=m(c,null,b,d).shouldBindDescendants;e&&!r[a.a.A(c)]&&g(b,c,!k)}function l(b){var c=[],d={},e=[];a.a.D(b,function X(k){if(!d[k]){var f=a.getBindingHandler(k);f&&(f.after&&(e.push(k),a.a.r(f.after,function(c){if(b[c]){if(-1!==a.a.o(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));
+X(c)}}),e.length--),c.push({key:k,jc:f}));d[k]=!0}});return c}function m(b,d,e,k){var m=a.a.e.get(b,q);if(!d){if(m)throw Error("You cannot apply bindings multiple times to the same element.");a.a.e.set(b,q,!0)}!m&&k&&a.xc(b,e);var g;if(d&&"function"!==typeof d)g=d;else{var h=a.S.instance,r=h.getBindingAccessors||f,p=a.B(function(){(g=d?d(e,b):r.call(h,b,e))&&e.Q&&e.Q();return g},null,{i:b});g&&p.ca()||(p=null)}var s;if(g){var t=p?function(a){return function(){return c(p()[a])}}:function(a){return g[a]},
+u=function(){return a.a.Ea(p?p():g,c)};u.get=function(a){return g[a]&&c(t(a))};u.has=function(a){return a in g};k=l(g);a.a.r(k,function(c){var d=c.jc.init,k=c.jc.update,f=c.key;if(8===b.nodeType&&!a.f.aa[f])throw Error("The binding '"+f+"' cannot be used with virtual elements");try{"function"==typeof d&&a.l.w(function(){var a=d(b,t(f),u,e.$data,e);if(a&&a.controlsDescendantBindings){if(s!==n)throw Error("Multiple bindings ("+s+" and "+f+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
+s=f}}),"function"==typeof k&&a.B(function(){k(b,t(f),u,e.$data,e)},null,{i:b})}catch(m){throw m.message='Unable to process binding "'+f+": "+g[f]+'"\nMessage: '+m.message,m;}})}return{shouldBindDescendants:s===n}}function k(b){return b&&b instanceof a.R?b:new a.R(b)}a.d={};var r={script:!0,textarea:!0,template:!0};a.getBindingHandler=function(b){return a.d[b]};a.R=function(b,c,d,e,k){function f(){var k=g?b():b,m=a.a.c(k);c?(c.Q&&c.Q(),a.a.extend(l,c),l.Q=r):(l.$parents=[],l.$root=m,l.ko=a);l.$rawData=
+k;l.$data=m;d&&(l[d]=m);e&&e(l,c,m);return l.$data}function m(){return h&&!a.a.Tb(h)}var l=this,g="function"==typeof b&&!a.I(b),h,r;k&&k.exportDependencies?f():(r=a.B(f,null,{ya:m,i:!0}),r.ca()&&(l.Q=r,r.equalityComparer=null,h=[],r.Dc=function(b){h.push(b);a.a.G.qa(b,function(b){a.a.Na(h,b);h.length||(r.k(),l.Q=r=n)})}))};a.R.prototype.createChildContext=function(b,c,d,e){return new a.R(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);
+d&&d(a)},e)};a.R.prototype.extend=function(b){return new a.R(this.Q||this.$data,this,null,function(c,d){c.$rawData=d.$rawData;a.a.extend(c,"function"==typeof b?b():b)})};a.R.prototype.ac=function(a,b){return this.createChildContext(a,b,null,{exportDependencies:!0})};var q=a.a.e.J(),p=a.a.e.J();a.xc=function(b,c){if(2==arguments.length)a.a.e.set(b,p,c),c.Q&&c.Q.Dc(b);else return a.a.e.get(b,p)};a.La=function(b,c,d){1===b.nodeType&&a.f.oc(b);return m(b,c,k(d),!0)};a.Ic=function(b,c,d){d=k(d);return a.La(b,
+e(c,d,b),d)};a.hb=function(a,b){1!==b.nodeType&&8!==b.nodeType||g(k(a),b,!0)};a.Ub=function(a,b){!u&&x.jQuery&&(u=x.jQuery);if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||x.document.body;h(k(a),b,!0)};a.nb=function(b){switch(b.nodeType){case 1:case 8:var c=a.xc(b);if(c)return c;if(b.parentNode)return a.nb(b.parentNode)}return n};a.Oc=function(b){return(b=a.nb(b))?b.$data:n};a.b("bindingHandlers",
+a.d);a.b("applyBindings",a.Ub);a.b("applyBindingsToDescendants",a.hb);a.b("applyBindingAccessorsToNode",a.La);a.b("applyBindingsToNode",a.Ic);a.b("contextFor",a.nb);a.b("dataFor",a.Oc)})();(function(b){function c(c,e){var m=f.hasOwnProperty(c)?f[c]:b,k;m?m.Y(e):(m=f[c]=new a.K,m.Y(e),d(c,function(b,d){var e=!(!d||!d.synchronous);g[c]={definition:b,dd:e};delete f[c];k||e?m.notifySubscribers(b):a.Z.Za(function(){m.notifySubscribers(b)})}),k=!0)}function d(a,b){e("getConfig",[a],function(c){c?e("loadComponent",
+[a,c],function(a){b(a,c)}):b(null,null)})}function e(c,d,f,k){k||(k=a.g.loaders.slice(0));var g=k.shift();if(g){var q=g[c];if(q){var p=!1;if(q.apply(g,d.concat(function(a){p?f(null):null!==a?f(a):e(c,d,f,k)}))!==b&&(p=!0,!g.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.");}else e(c,d,f,k)}else f(null)}var f={},g={};a.g={get:function(d,e){var f=g.hasOwnProperty(d)?g[d]:b;f?f.dd?a.l.w(function(){e(f.definition)}):
+a.Z.Za(function(){e(f.definition)}):c(d,e)},$b:function(a){delete g[a]},Nb:e};a.g.loaders=[];a.b("components",a.g);a.b("components.get",a.g.get);a.b("components.clearCachedDefinition",a.g.$b)})();(function(){function b(b,c,d,e){function g(){0===--y&&e(h)}var h={},y=2,v=d.template;d=d.viewModel;v?f(c,v,function(c){a.g.Nb("loadTemplate",[b,c],function(a){h.template=a;g()})}):g();d?f(c,d,function(c){a.g.Nb("loadViewModel",[b,c],function(a){h[l]=a;g()})}):g()}function c(a,b,d){if("function"===typeof b)d(function(a){return new b(a)});
+else if("function"===typeof b[l])d(b[l]);else if("instance"in b){var e=b.instance;d(function(){return e})}else"viewModel"in b?c(a,b.viewModel,d):a("Unknown viewModel value: "+b)}function d(b){switch(a.a.A(b)){case "script":return a.a.na(b.text);case "textarea":return a.a.na(b.value);case "template":if(e(b.content))return a.a.wa(b.content.childNodes)}return a.a.wa(b.childNodes)}function e(a){return x.DocumentFragment?a instanceof DocumentFragment:a&&11===a.nodeType}function f(a,b,c){"string"===typeof b.require?
+O||x.require?(O||x.require)([b.require],c):a("Uses require, but no AMD loader is present"):c(b)}function g(a){return function(b){throw Error("Component '"+a+"': "+b);}}var h={};a.g.register=function(b,c){if(!c)throw Error("Invalid configuration for "+b);if(a.g.wb(b))throw Error("Component "+b+" is already registered");h[b]=c};a.g.wb=function(a){return h.hasOwnProperty(a)};a.g.ud=function(b){delete h[b];a.g.$b(b)};a.g.cc={getConfig:function(a,b){b(h.hasOwnProperty(a)?h[a]:null)},loadComponent:function(a,
+c,d){var e=g(a);f(e,c,function(c){b(a,e,c,d)})},loadTemplate:function(b,c,f){b=g(b);if("string"===typeof c)f(a.a.na(c));else if(c instanceof Array)f(c);else if(e(c))f(a.a.W(c.childNodes));else if(c.element)if(c=c.element,x.HTMLElement?c instanceof HTMLElement:c&&c.tagName&&1===c.nodeType)f(d(c));else if("string"===typeof c){var l=t.getElementById(c);l?f(d(l)):b("Cannot find element with ID "+c)}else b("Unknown element type: "+c);else b("Unknown template value: "+c)},loadViewModel:function(a,b,d){c(g(a),
+b,d)}};var l="createViewModel";a.b("components.register",a.g.register);a.b("components.isRegistered",a.g.wb);a.b("components.unregister",a.g.ud);a.b("components.defaultLoader",a.g.cc);a.g.loaders.push(a.g.cc);a.g.Ec=h})();(function(){function b(b,e){var f=b.getAttribute("params");if(f){var f=c.parseBindingsString(f,e,b,{valueAccessors:!0,bindingParams:!0}),f=a.a.Ea(f,function(c){return a.m(c,null,{i:b})}),g=a.a.Ea(f,function(c){var e=c.p();return c.ca()?a.m({read:function(){return a.a.c(c())},write:a.Da(e)&&
+function(a){c()(a)},i:b}):e});g.hasOwnProperty("$raw")||(g.$raw=f);return g}return{$raw:{}}}a.g.getComponentNameForNode=function(b){var c=a.a.A(b);if(a.g.wb(c)&&(-1!=c.indexOf("-")||"[object HTMLUnknownElement]"==""+b||8>=a.a.C&&b.tagName===c))return c};a.g.Rb=function(c,e,f,g){if(1===e.nodeType){var h=a.g.getComponentNameForNode(e);if(h){c=c||{};if(c.component)throw Error('Cannot use the "component" binding on a custom element matching a component');var l={name:h,params:b(e,f)};c.component=g?function(){return l}:
+l}}return c};var c=new a.S;9>a.a.C&&(a.g.register=function(a){return function(b){t.createElement(b);return a.apply(this,arguments)}}(a.g.register),t.createDocumentFragment=function(b){return function(){var c=b(),f=a.g.Ec,g;for(g in f)f.hasOwnProperty(g)&&c.createElement(g);return c}}(t.createDocumentFragment))})();(function(b){function c(b,c,d){c=c.template;if(!c)throw Error("Component '"+b+"' has no template");b=a.a.wa(c);a.f.fa(d,b)}function d(a,b,c,d){var e=a.createViewModel;return e?e.call(a,
+d,{element:b,templateNodes:c}):d}var e=0;a.d.component={init:function(f,g,h,l,m){function k(){var a=r&&r.dispose;"function"===typeof a&&a.call(r);q=r=null}var r,q,p=a.a.W(a.f.childNodes(f));a.a.G.qa(f,k);a.m(function(){var l=a.a.c(g()),h,v;"string"===typeof l?h=l:(h=a.a.c(l.name),v=a.a.c(l.params));if(!h)throw Error("No component name specified");var n=q=++e;a.g.get(h,function(e){if(q===n){k();if(!e)throw Error("Unknown component '"+h+"'");c(h,e,f);var l=d(e,f,p,v);e=m.createChildContext(l,b,function(a){a.$component=
+l;a.$componentTemplateNodes=p});r=l;a.hb(e,f)}})},null,{i:f});return{controlsDescendantBindings:!0}}};a.f.aa.component=!0})();var Q={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.D(d,function(c,d){d=a.a.c(d);var g=!1===d||null===d||d===n;g&&b.removeAttribute(c);8>=a.a.C&&c in Q?(c=Q[c],g?b.removeAttribute(c):b[c]=d):g||b.setAttribute(c,d.toString());"name"===c&&a.a.vc(b,g?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,
+c,d){function e(){var e=b.checked,f=p?g():e;if(!a.xa.Va()&&(!l||e)){var h=a.l.w(c);if(k){var m=r?h.p():h;q!==f?(e&&(a.a.ra(m,f,!0),a.a.ra(m,q,!1)),q=f):a.a.ra(m,f,e);r&&a.Da(h)&&h(m)}else a.h.Ga(h,d,"checked",f,!0)}}function f(){var d=a.a.c(c());b.checked=k?0<=a.a.o(d,g()):h?d:g()===d}var g=a.rc(function(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):d.has("value")?a.a.c(d.get("value")):b.value}),h="checkbox"==b.type,l="radio"==b.type;if(h||l){var m=c(),k=h&&a.a.c(m)instanceof Array,
+r=!(k&&m.push&&m.splice),q=k?g():n,p=l||k;l&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.m(e,null,{i:b});a.a.q(b,"click",e);a.m(f,null,{i:b});m=n}}};a.h.ga.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());null!==d&&"object"==typeof d?a.a.D(d,function(c,d){d=a.a.c(d);a.a.fb(b,c,d)}):(d=a.a.cb(String(d||"")),a.a.fb(b,b.__ko__cssValue,!1),b.__ko__cssValue=d,a.a.fb(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());
+d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,f){var g=c()||{};a.a.D(g,function(g){"string"==typeof g&&a.a.q(b,g,function(b){var m,k=c()[g];if(k){try{var r=a.a.W(arguments);e=f.$data;r.unshift(e);m=k.apply(e,r)}finally{!0!==m&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};
+a.d.foreach={mc:function(b){return function(){var c=b(),d=a.a.Bb(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.X.vb};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.X.vb}}},init:function(b,c){return a.d.template.init(b,a.d.foreach.mc(c))},update:function(b,c,d,e,f){return a.d.template.update(b,a.d.foreach.mc(c),
+d,e,f)}};a.h.va.foreach=!1;a.f.aa.foreach=!0;a.d.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(k){g=f.body}e=g===b}f=c();a.h.Ga(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),g=e.bind(null,!1);a.a.q(b,"focus",f);a.a.q(b,"focusin",f);a.a.q(b,"blur",g);a.a.q(b,"focusout",g)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===
+d||(d?b.focus():b.blur(),!d&&b.__ko_hasfocusLastValue&&b.ownerDocument.body.focus(),a.l.w(a.a.Fa,null,[b,d?"focusin":"focusout"]))}};a.h.ga.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.h.ga.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Eb(b,c())}};K("if");K("ifnot",!1,!0);K("with",!0,!1,function(a,c){return a.ac(c)});var L={};a.d.options={init:function(b){if("select"!==a.a.A(b))throw Error("options binding applies only to SELECT elements");for(;0<
+b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.Ma(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(c,e){if(A&&k)a.j.ja(b,a.a.c(d.get("value")),!0);else if(p.length){var f=0<=a.a.o(p,a.j.u(e[0]));a.a.wc(e[0],f);A&&!f&&a.l.w(a.a.Fa,null,[b,"change"])}}var h=b.multiple,l=0!=b.length&&h?b.scrollTop:null,m=a.a.c(c()),k=d.get("valueAllowUnset")&&d.has("value"),r=
+d.get("optionsIncludeDestroyed");c={};var q,p=[];k||(h?p=a.a.ib(e(),a.j.u):0<=b.selectedIndex&&p.push(a.j.u(b.options[b.selectedIndex])));m&&("undefined"==typeof m.length&&(m=[m]),q=a.a.Ma(m,function(b){return r||b===n||null===b||!a.a.c(b._destroy)}),d.has("optionsCaption")&&(m=a.a.c(d.get("optionsCaption")),null!==m&&m!==n&&q.unshift(L)));var A=!1;c.beforeRemove=function(a){b.removeChild(a)};m=g;d.has("optionsAfterRender")&&"function"==typeof d.get("optionsAfterRender")&&(m=function(b,c){g(0,c);
+a.l.w(d.get("optionsAfterRender"),null,[c[0],b!==L?b:n])});a.a.Db(b,q,function(c,e,g){g.length&&(p=!k&&g[0].selected?[a.j.u(g[0])]:[],A=!0);e=b.ownerDocument.createElement("option");c===L?(a.a.bb(e,d.get("optionsCaption")),a.j.ja(e,n)):(g=f(c,d.get("optionsValue"),c),a.j.ja(e,a.a.c(g)),c=f(c,d.get("optionsText"),g),a.a.bb(e,c));return[e]},c,m);a.l.w(function(){k?a.j.ja(b,a.a.c(d.get("value")),!0):(h?p.length&&e().length<p.length:p.length&&0<=b.selectedIndex?a.j.u(b.options[b.selectedIndex])!==p[0]:
+p.length||0<=b.selectedIndex)&&a.a.Fa(b,"change")});a.a.Sc(b);l&&20<Math.abs(l-b.scrollTop)&&(b.scrollTop=l)}};a.d.options.zb=a.a.e.J();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.q(b,"change",function(){var e=c(),f=[];a.a.r(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.j.u(b))});a.h.Ga(e,d,"selectedOptions",f)})},update:function(b,c){if("select"!=a.a.A(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c()),e=b.scrollTop;
+d&&"number"==typeof d.length&&a.a.r(b.getElementsByTagName("option"),function(b){var c=0<=a.a.o(d,a.j.u(b));b.selected!=c&&a.a.wc(b,c)});b.scrollTop=e}};a.h.ga.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.D(d,function(c,d){d=a.a.c(d);if(null===d||d===n||!1===d)d="";b.style[c]=d})}};a.d.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.q(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,
+b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.bb(b,c())}};a.f.aa.text=!0;(function(){if(x&&x.navigator)var b=function(a){if(a)return parseFloat(a[1])},c=x.opera&&x.opera.version&&parseInt(x.opera.version()),d=x.navigator.userAgent,e=b(d.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),f=b(d.match(/Firefox\/([^ ]*)/));if(10>a.a.C)var g=a.a.e.J(),h=a.a.e.J(),l=function(b){var c=
+this.activeElement;(c=c&&a.a.e.get(c,h))&&c(b)},m=function(b,c){var d=b.ownerDocument;a.a.e.get(d,g)||(a.a.e.set(d,g,!0),a.a.q(d,"selectionchange",l));a.a.e.set(b,h,c)};a.d.textInput={init:function(b,d,g){function l(c,d){a.a.q(b,c,d)}function h(){var c=a.a.c(d());if(null===c||c===n)c="";u!==n&&c===u?a.a.setTimeout(h,4):b.value!==c&&(s=c,b.value=c)}function y(){t||(u=b.value,t=a.a.setTimeout(v,4))}function v(){clearTimeout(t);u=t=n;var c=b.value;s!==c&&(s=c,a.h.Ga(d(),g,"textInput",c))}var s=b.value,
+t,u,x=9==a.a.C?y:v;10>a.a.C?(l("propertychange",function(a){"value"===a.propertyName&&x(a)}),8==a.a.C&&(l("keyup",v),l("keydown",v)),8<=a.a.C&&(m(b,x),l("dragend",y))):(l("input",v),5>e&&"textarea"===a.a.A(b)?(l("keydown",y),l("paste",y),l("cut",y)):11>c?l("keydown",y):4>f&&(l("DOMAutoComplete",v),l("dragdrop",v),l("drop",v)));l("change",v);a.m(h,null,{i:b})}};a.h.ga.textInput=!0;a.d.textinput={preprocess:function(a,b,c){c("textInput",a)}}})();a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+
+++a.d.uniqueName.Nc;a.a.vc(b,d)}}};a.d.uniqueName.Nc=0;a.d.value={after:["options","foreach"],init:function(b,c,d){if("input"!=b.tagName.toLowerCase()||"checkbox"!=b.type&&"radio"!=b.type){var e=["change"],f=d.get("valueUpdate"),g=!1,h=null;f&&("string"==typeof f&&(f=[f]),a.a.ta(e,f),e=a.a.Wb(e));var l=function(){h=null;g=!1;var e=c(),f=a.j.u(b);a.h.Ga(e,d,"value",f)};!a.a.C||"input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.o(e,"propertychange")||
+(a.a.q(b,"propertychange",function(){g=!0}),a.a.q(b,"focus",function(){g=!1}),a.a.q(b,"blur",function(){g&&l()}));a.a.r(e,function(c){var d=l;a.a.sd(c,"after")&&(d=function(){h=a.j.u(b);a.a.setTimeout(l,0)},c=c.substring(5));a.a.q(b,c,d)});var m=function(){var e=a.a.c(c()),f=a.j.u(b);if(null!==h&&e===h)a.a.setTimeout(m,0);else if(e!==f)if("select"===a.a.A(b)){var g=d.get("valueAllowUnset"),f=function(){a.j.ja(b,e,g)};f();g||e===a.j.u(b)?a.a.setTimeout(f,0):a.l.w(a.a.Fa,null,[b,"change"])}else a.j.ja(b,
+e)};a.m(m,null,{i:b})}else a.La(b,{checkedValue:c})},update:function(){}};a.h.ga.value=!0;a.d.visible={update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,f,g){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,g)}}})("click");a.P=function(){};a.P.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.P.prototype.createJavaScriptEvaluatorBlock=
+function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.P.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||t;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.v.n(d)}if(1==b.nodeType||8==b.nodeType)return new a.v.sa(b);throw Error("Unknown template type: "+b);};a.P.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,d,e)};a.P.prototype.isTemplateRewritten=function(a,
+c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.P.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.P);a.Ib=function(){function b(b,c,d,h){b=a.h.Ab(b);for(var l=a.h.va,m=0;m<b.length;m++){var k=b[m].key;if(l.hasOwnProperty(k)){var r=l[k];if("function"===typeof r){if(k=r(b[m].value))throw Error(k);}else if(!r)throw Error("This template engine does not support the '"+
+k+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.h.Xa(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return h.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Tc:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Ib.jd(b,
+c)},d)},jd:function(a,f){return a.replace(c,function(a,c,d,e,k){return b(k,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",f)})},Jc:function(b,c){return a.N.yb(function(d,h){var l=d.nextSibling;l&&l.nodeName.toLowerCase()===c&&a.La(l,b,h)})}}}();a.b("__tr_ambtns",a.Ib.Jc);(function(){a.v={};a.v.n=function(b){if(this.n=b){var c=a.a.A(b);this.eb="script"===c?1:"textarea"===c?2:"template"==c&&b.content&&11===b.content.nodeType?3:4}};a.v.n.prototype.text=function(){var b=1===
+this.eb?"text":2===this.eb?"value":"innerHTML";if(0==arguments.length)return this.n[b];var c=arguments[0];"innerHTML"===b?a.a.Eb(this.n,c):this.n[b]=c};var b=a.a.e.J()+"_";a.v.n.prototype.data=function(c){if(1===arguments.length)return a.a.e.get(this.n,b+c);a.a.e.set(this.n,b+c,arguments[1])};var c=a.a.e.J();a.v.n.prototype.nodes=function(){var b=this.n;if(0==arguments.length)return(a.a.e.get(b,c)||{}).mb||(3===this.eb?b.content:4===this.eb?b:n);a.a.e.set(b,c,{mb:arguments[0]})};a.v.sa=function(a){this.n=
+a};a.v.sa.prototype=new a.v.n;a.v.sa.prototype.text=function(){if(0==arguments.length){var b=a.a.e.get(this.n,c)||{};b.Jb===n&&b.mb&&(b.Jb=b.mb.innerHTML);return b.Jb}a.a.e.set(this.n,c,{Jb:arguments[0]})};a.b("templateSources",a.v);a.b("templateSources.domElement",a.v.n);a.b("templateSources.anonymousTemplate",a.v.sa)})();(function(){function b(b,c,d){var e;for(c=a.f.nextSibling(c);b&&(e=b)!==c;)b=a.f.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],g=e.parentNode,h=
+a.S.instance,n=h.preprocessNode;if(n){b(e,f,function(a,b){var c=a.previousSibling,d=n.call(h,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):(c.push(e,f),a.a.Ba(c,g))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.Ub(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.N.Cc(b,[d])});a.a.Ba(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,f,h,q){q=q||{};var p=(b&&d(b)||f||{}).ownerDocument,n=q.templateEngine||g;
+a.Ib.Tc(f,n,p);f=n.renderTemplate(f,h,q,p);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");p=!1;switch(e){case "replaceChildren":a.f.fa(b,f);p=!0;break;case "replaceNode":a.a.uc(b,f);p=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}p&&(c(f,h),q.afterRender&&a.l.w(q.afterRender,null,[f,h.$data]));return f}function f(b,c,d){return a.I(b)?b():"function"===typeof b?b(c,d):b}
+var g;a.Fb=function(b){if(b!=n&&!(b instanceof a.P))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.Cb=function(b,c,k,h,q){k=k||{};if((k.templateEngine||g)==n)throw Error("Set a template engine before calling renderTemplate");q=q||"replaceChildren";if(h){var p=d(h);return a.B(function(){var g=c&&c instanceof a.R?c:new a.R(c,null,null,null,{exportDependencies:!0}),n=f(b,g.$data,g),g=e(h,q,n,g,k);"replaceNode"==q&&(h=g,p=d(h))},null,{ya:function(){return!p||!a.a.qb(p)},i:p&&
+"replaceNode"==q?p.parentNode:p})}return a.N.yb(function(d){a.Cb(b,c,k,d,"replaceNode")})};a.pd=function(b,d,g,h,q){function p(a,b){c(b,t);g.afterRender&&g.afterRender(b,a);t=null}function s(a,c){t=q.createChildContext(a,g.as,function(a){a.$index=c});var d=f(b,a,t);return e(null,"ignoreTargetNode",d,t,g)}var t;return a.B(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.Ma(b,function(b){return g.includeDestroyed||b===n||null===b||!a.a.c(b._destroy)});a.l.w(a.a.Db,null,[h,b,
+s,g,p])},null,{i:h})};var h=a.a.e.J();a.d.template={init:function(b,c){var d=a.a.c(c());if("string"==typeof d||d.name)a.f.za(b);else{if("nodes"in d){if(d=d.nodes||[],a.I(d))throw Error('The "nodes" option must be a plain, non-observable array.');}else d=a.f.childNodes(b);d=a.a.nc(d);(new a.v.sa(b)).nodes(d)}return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var g=c();c=a.a.c(g);d=!0;e=null;"string"==typeof c?c={}:(g=c.name,"if"in c&&(d=a.a.c(c["if"])),d&&"ifnot"in c&&(d=!a.a.c(c.ifnot)));
+"foreach"in c?e=a.pd(g||b,d&&c.foreach||[],c,b,f):d?(f="data"in c?f.ac(c.data,c.as):f,e=a.Cb(g||b,f,c,b)):a.f.za(b);f=e;(c=a.a.e.get(b,h))&&"function"==typeof c.k&&c.k();a.a.e.set(b,h,f&&f.ca()?f:n)}};a.h.va.template=function(b){b=a.h.Ab(b);return 1==b.length&&b[0].unknown||a.h.fd(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.f.aa.template=!0})();a.b("setTemplateEngine",a.Fb);a.b("renderTemplate",a.Cb);a.a.hc=function(a,c,d){if(a.length&&
+c.length){var e,f,g,h,l;for(e=f=0;(!d||e<d)&&(h=a[f]);++f){for(g=0;l=c[g];++g)if(h.value===l.value){h.moved=l.index;l.moved=h.index;c.splice(g,1);e=g=0;break}e+=g}}};a.a.lb=function(){function b(b,d,e,f,g){var h=Math.min,l=Math.max,m=[],k,n=b.length,q,p=d.length,s=p-n||1,t=n+p+1,v,u,x;for(k=0;k<=n;k++)for(u=v,m.push(v=[]),x=h(p,k+s),q=l(0,k-1);q<=x;q++)v[q]=q?k?b[k-1]===d[q-1]?u[q-1]:h(u[q]||t,v[q-1]||t)+1:q+1:k+1;h=[];l=[];s=[];k=n;for(q=p;k||q;)p=m[k][q]-1,q&&p===m[k][q-1]?l.push(h[h.length]={status:e,
+value:d[--q],index:q}):k&&p===m[k-1][q]?s.push(h[h.length]={status:f,value:b[--k],index:k}):(--q,--k,g.sparse||h.push({status:"retained",value:d[q]}));a.a.hc(s,l,!g.dontLimitMoves&&10*n);return h.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.lb);(function(){function b(b,c,d,h,l){var m=[],k=a.B(function(){var k=c(d,l,a.a.Ba(m,b))||[];0<
+m.length&&(a.a.uc(m,k),h&&a.l.w(h,null,[d,k,l]));m.length=0;a.a.ta(m,k)},null,{i:b,ya:function(){return!a.a.Tb(m)}});return{ea:m,B:k.ca()?k:n}}var c=a.a.e.J(),d=a.a.e.J();a.a.Db=function(e,f,g,h,l){function m(b,c){w=q[c];u!==c&&(D[b]=w);w.tb(u++);a.a.Ba(w.ea,e);t.push(w);z.push(w)}function k(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.r(c[d].ea,function(a){b(a,d,c[d].ka)})}f=f||[];h=h||{};var r=a.a.e.get(e,c)===n,q=a.a.e.get(e,c)||[],p=a.a.ib(q,function(a){return a.ka}),s=a.a.lb(p,f,h.dontLimitMoves),
+t=[],v=0,u=0,x=[],z=[];f=[];for(var D=[],p=[],w,C=0,B,E;B=s[C];C++)switch(E=B.moved,B.status){case "deleted":E===n&&(w=q[v],w.B&&(w.B.k(),w.B=n),a.a.Ba(w.ea,e).length&&(h.beforeRemove&&(t.push(w),z.push(w),w.ka===d?w=null:f[C]=w),w&&x.push.apply(x,w.ea)));v++;break;case "retained":m(C,v++);break;case "added":E!==n?m(C,E):(w={ka:B.value,tb:a.O(u++)},t.push(w),z.push(w),r||(p[C]=w))}a.a.e.set(e,c,t);k(h.beforeMove,D);a.a.r(x,h.beforeRemove?a.ba:a.removeNode);for(var C=0,r=a.f.firstChild(e),F;w=z[C];C++){w.ea||
+a.a.extend(w,b(e,g,w.ka,l,w.tb));for(v=0;s=w.ea[v];r=s.nextSibling,F=s,v++)s!==r&&a.f.kc(e,s,F);!w.ad&&l&&(l(w.ka,w.ea,w.tb),w.ad=!0)}k(h.beforeRemove,f);for(C=0;C<f.length;++C)f[C]&&(f[C].ka=d);k(h.afterMove,D);k(h.afterAdd,p)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Db);a.X=function(){this.allowTemplateRewriting=!1};a.X.prototype=new a.P;a.X.prototype.renderTemplateSource=function(b,c,d,e){if(c=(9>a.a.C?0:b.nodes)?b.nodes():null)return a.a.W(c.cloneNode(!0).childNodes);b=b.text();
+return a.a.na(b,e)};a.X.vb=new a.X;a.Fb(a.X.vb);a.b("nativeTemplateEngine",a.X);(function(){a.xb=function(){var a=this.ed=function(){if(!u||!u.tmpl)return 0;try{if(0<=u.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,f,g){g=g||t;f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=u.template(null,"{{ko_with $item.koBindingContext}}"+
+h+"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=u.extend({koBindingContext:e},f.templateOptions);e=u.tmpl(h,b,e);e.appendTo(g.createElement("div"));u.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){t.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(u.tmpl.tag.ko_code={open:"__.push($1 || '');"},u.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.xb.prototype=
+new a.P;var b=new a.xb;0<b.ed&&a.Fb(b);a.b("jqueryTmplTemplateEngine",a.xb)})()})})();})();
diff --git a/ap/app/zte_webui/js/3rd/knockout.js b/ap/app/zte_webui/js/3rd/knockout.js
new file mode 100755
index 0000000..7301dca
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/knockout.js
@@ -0,0 +1,12 @@
+define(["knockoutbase"], function (a) {

+    a.bindingHandlers.slide = {

+        update: function (b, e) {

+            var c = a.utils.unwrapObservable(e()),

+            d = "none" != b.style.display;

+            c && !d ? $(b).slideDown() : !c && d && $(b).slideUp()

+        }

+    };

+    window.ko = a;

+    require(["3rd/knockout.simpleGrid"]);

+    return a

+});

diff --git a/ap/app/zte_webui/js/3rd/knockout.simpleGrid.js b/ap/app/zte_webui/js/3rd/knockout.simpleGrid.js
new file mode 100755
index 0000000..2053f39
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/knockout.simpleGrid.js
@@ -0,0 +1,493 @@
+(function () {
+    // Private function
+    function getColumnsForScaffolding(data) {
+        if ((typeof data.length !== 'number') || data.length === 0) {
+            return [];
+        }
+        var columns = [];
+        for (var propertyName in data[0]) {
+            columns.push({ headerText:propertyName, headerTextTrans:propertyName, rowText:propertyName, columnType:propertyName, width:propertyName, sortable:propertyName });
+        }
+        return columns;
+    }
+
+    ko.simpleGrid = {
+        // Defines a view model class you can use to populate a grid
+        viewModel:function (configuration) {
+            var self = this;
+            self.sideNumber = 3; //当前页面左右页码数
+            self.midNumber = 1 + 2 * self.sideNumber; //中间要显示的页码
+            self.allNumber = self.midNumber + 2; //显示完整页码的最大页码
+
+            self.showMenu = false;
+
+            self.className = "table table-striped table-hover ko-grid colorHoverTable " + (configuration.tableClass ? configuration.tableClass : "");
+
+            self.ellipsisLength = 16;
+            self.searchInitStatus = ko.observable();
+            self.searchKey = ko.observable();
+            self.searchColumns = configuration.searchColumns;
+            self.primaryColumn = configuration.primaryColumn;
+            self.showPager = !!configuration.showPager;
+            self.sortField = ko.observable(configuration.defaultSortField);
+            self.sortDirection = ko.observable(configuration.defaultSortDirection);
+            self.data = ko.observableArray(configuration.data);
+			self.pageToGo = ko.observable();
+            self.sortedData = ko.computed(function () {
+                var exp = self.sortField();
+                var dir = self.sortDirection();
+                if (exp && dir) {
+                    return self.data().sort(function (a, b) {
+                        return dir == "ASC" ? a[exp].localeCompare(b[exp]) : b[exp].localeCompare(a[exp]);
+                    });
+                } else {
+                    return self.data();
+                }
+            });
+            self.checkedCount = ko.observable(0);
+            self.translate = function () {
+                $(".ko-grid").translate();
+                if ($("#pblist tr").length >0 ){
+                    $("#pblist-checkall").removeClass("disable");
+                }else{
+                    $("#pblist-checkall").addClass("disable");
+                }
+            };
+
+            self.clearCheck = function () {
+                $("#ko_grid_checkAll").removeAttr("checked");
+                $("#pblist-checkall").removeClass("checkbox_selected");
+                $("p:checkbox[target='pblist-checkall']").removeAttr("checked");
+                $("p[id^='chk__'] ").removeClass("checkbox_selected");
+                $("p[id^='chk__'] :checkbox").removeAttr("checked");
+                self.checkedCount(0);
+                self.translate();
+            };
+
+            self.searchText = ko.computed(function () {
+                self.clearCheck();
+                var text = "";
+                if (!self.searchInitStatus()) {
+                    text = $.trim(self.searchKey());
+                }
+                return text;
+            });
+
+            self.afterSearchData = ko.computed(function () {
+                var key = $.trim(self.searchText()).toLowerCase();
+                if (key == "") {
+                    return self.sortedData();
+                }
+                else {
+                    return _.filter(self.sortedData(), function (item) {
+                        for (var i = 0; i < self.searchColumns.length; i++) {
+                            var col = self.searchColumns[i];
+                            if (item[col].toLowerCase().indexOf(key) != -1) {
+                                return true;
+                            }
+                        }
+                        return false;
+                    });
+                }
+            });
+            self.currentPageIndex = ko.observable(0);
+            self.pageSize = configuration.pageSize || 5;
+            // If you don't specify columns configuration, we'll use scaffolding
+            self.columns = configuration.columns || getColumnsForScaffolding(ko.utils.unwrapObservable(self.afterSearchData()));
+            self.rowClickHandler = configuration.rowClickHandler;
+            self.hasRowClickHandler = !!configuration.rowClickHandler;
+            self.deleteHandler = configuration.deleteHandler;
+            self.idName = configuration.idName;
+            self.tmplType = configuration.tmplType;
+            self.changeTemplateHandler = configuration.changeTemplateHandler;
+            self.maxPageIndex = ko.computed(function () {
+                return Math.ceil(ko.utils.unwrapObservable(self.afterSearchData()).length / self.pageSize) - 1;
+            });
+            self.radioClickExtend = configuration.radioClickHandler;
+            self.radioChecked4Column = configuration.radioChecked4Column;
+            self.radioChecked4Value = configuration.radioChecked4Value;
+
+            self.fixCurrentPageIndex = function (oldIndex) {
+                if (oldIndex < 0) return 0;
+                var maxIndex = self.maxPageIndex();
+                return oldIndex > maxIndex ? maxIndex : oldIndex;
+            };
+
+            self.pagerStart = ko.computed(function () {
+                var index = self.fixCurrentPageIndex(self.currentPageIndex());
+                var maxIndex = self.maxPageIndex();
+                var retIndex = 0;
+                if (index < self.midNumber || maxIndex <= self.allNumber) {
+                    retIndex = 1;
+                } else if (index + self.sideNumber >= maxIndex) {
+                    retIndex = maxIndex - self.midNumber;
+                } else {
+                    retIndex = index - self.sideNumber;
+                }
+                return retIndex;
+            });
+
+            self.pagerEnd = ko.computed(function () {
+                var index = self.fixCurrentPageIndex(self.currentPageIndex());
+                var maxIndex = self.maxPageIndex();
+                var retIndex = 0;
+                if (index + self.sideNumber >= maxIndex || maxIndex <= self.allNumber) {
+                    retIndex = maxIndex - 1;
+                } else if (index < self.midNumber) {
+                    retIndex = self.midNumber;
+                } else {
+                    retIndex = index + self.sideNumber;
+                }
+                if (maxIndex - retIndex == 2) {
+                    retIndex = maxIndex -1;
+                }
+                return retIndex;
+            });
+
+            self.itemsOnCurrentPage = ko.computed(function () {
+                self.translate();
+                var pageIndex = self.fixCurrentPageIndex(self.currentPageIndex());
+                var startIndex = self.pageSize * pageIndex;
+                return self.afterSearchData().slice(startIndex, startIndex + self.pageSize);
+            });
+
+            self.changePage = function (pageIndex) {
+                var pageIndex = self.fixCurrentPageIndex(pageIndex);
+                self.currentPageIndex(pageIndex);
+                self.clearCheck();
+            };
+
+            self.nextPage = function () {
+                var pageIndex = self.fixCurrentPageIndex(self.currentPageIndex() + 1);
+                self.currentPageIndex(pageIndex);
+                self.clearCheck();
+            };
+
+            self.previousPage = function () {
+                var pageIndex = self.fixCurrentPageIndex(self.currentPageIndex() - 1);
+                self.currentPageIndex(pageIndex);
+                self.clearCheck();
+            };
+
+            self.clearAllChecked = function () {
+                $("#pblist-checkall").trigger("click");
+                if ($("#pblist-checkall").hasClass("checkbox_selected")) {
+                    $("#pblist-checkall").trigger("click");
+                }
+            }
+
+            self.clickCheckAll = function () {
+                if ($("#pblist-checkall").hasClass("checkbox_selected")) {
+                    self.checkedCount(0);
+                } else {
+                    var checked = $("#pblist :checkbox").length;
+                    self.checkedCount(checked);
+                }
+            };
+
+            self.clickCheck = function (index) {
+                var checkbox = $("#chk__" + index+" :checkbox");
+                if (checkbox.attr("checked")) {
+                    checkbox.removeAttr("checked");
+                } else {
+                    checkbox.attr("checked", "checked");
+                }
+                checkCheckbox(checkbox);
+
+                var checked = $("#pblist p.checkbox_selected :checkbox").length;
+                self.checkedCount(checked);
+            };
+
+            self.selectedItems = function (type) {
+                var checks;
+                /*if (self.tmplType == 'card') { cov_2
+                    checks = $("#pblist :checkbox[checked='checked']");
+                }
+                else {
+                    checks = $("#pblist :checkbox[checked='checked']");
+                }*/
+                checks = $("#pblist :checkbox[checked='checked']");
+                var items = [];
+                if (type == "primary") {
+                    checks.each(function () {
+                        items.push($(this).attr("primaryValue"));
+                    });
+                } else {
+                    checks.each(function () {
+                        items.push($(this).val());
+                    });
+                }
+                return items;
+            };
+
+            self.selectedIds = function () {
+                return  self.selectedItems("id");
+            };
+
+            self.selectedPrimaryValue = function () {
+                return  self.selectedItems("primary");
+            };
+
+            self.radioSelectValue = function () {
+                if ($.browser.msie && event && event.srcElement && event.srcElement.type == "radio") {
+                    return event.srcElement.value;
+                }
+                return $("#pblist [name='ko_grid_radio']:checked").val();
+            }
+
+            self.radioSelectedPrimaryValue = function () {
+                if ($.browser.msie && event && event.srcElement && event.srcElement.type == "radio") {
+                    return event.srcElement.attribute("primaryValue");
+                }
+                return $("#pblist [name='ko_grid_radio']:checked").attr("primaryValue");
+            }
+
+            self.radioClick = function () {
+                self.checkedCount(self.checkedCount() + 1);
+            }
+
+            self.clearRadioSelect = function () {
+                $("#pblist [name='ko_grid_radio']:checked").removeAttr("checked");
+                self.checkedCount(0);
+            }
+
+            self.setRadioSelect = function (val) {
+                $("#pblist [name='ko_grid_radio'][value='" + val + "']").attr("checked", "checked");
+                self.checkedCount(1);
+            }
+
+            self.sort = function (exp) {
+                if (exp == undefined) {
+                    return;
+                }
+                var sortExp = self.sortField();
+                var dir = "ASC";
+                if (exp == sortExp) {
+                    dir = (self.sortDirection() == "ASC") ? "DESC" : "ASC";
+                }
+                self.sortField(exp);
+                self.sortDirection(dir);
+
+                self.data(self.data().sort(function (a, b) {
+                    return dir == "ASC" ? a[exp].localeCompare(b[exp]) : b[exp].localeCompare(a[exp]);
+                }));
+
+                self.currentPageIndex(0);
+                self.clearCheck();
+
+                $(".ko-grid thead th.ko-grid-th-asc").removeClass("ko-grid-th-asc").addClass("ko-grid-th-sortable");
+                $(".ko-grid thead th.ko-grid-th-desc").removeClass("ko-grid-th-desc").addClass("ko-grid-th-sortable");
+                if (dir == "ASC") {
+                    $("#ko_grid_th_" + exp).removeClass().addClass("ko-grid-th-asc");
+                } else {
+                    $("#ko_grid_th_" + exp).removeClass().addClass("ko-grid-th-desc");
+                }
+            };
+
+            self.ellipsisText = function (txt) {
+                if (!txt) return "";
+                if ((txt.length * 2) < self.ellipsisLength) {
+                    return txt;
+                }
+                var len = 0;
+                for (var i = 0; i < txt.length; i++) {
+                    if (txt.charCodeAt(i) > 256) {
+                        len += 2;
+                    } else {
+                        len++;
+                    }
+                    if (len >= self.ellipsisLength) {
+                        return txt.substring(0, i) + "...";
+                    }
+                }
+                return txt;
+            };
+        }
+    };
+
+    // Templates used to render the grid
+    var templateEngine = new ko.nativeTemplateEngine();
+
+    templateEngine.addTemplate = function (templateName, templateMarkup) {
+        if ($('#' + templateName)[0]) {
+            $('#' + templateName).remove();
+        }
+        $('#container').append("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
+    };
+
+    // The "simpleGrid" binding
+    ko.bindingHandlers.simpleGrid = {
+        init:function (element, viewModelAccessor) {
+
+            var viewModel = viewModelAccessor();
+            if (viewModel.rowClickHandler == undefined) {
+                viewModel.rowClickHandler = function () {
+                };
+            }
+            if (viewModel.deleteHandler == undefined) {
+                viewModel.deleteHandler = function () {
+                };
+            }
+            if (viewModel.radioClickExtend == undefined) {
+                viewModel.radioClickHandler = function(){
+                    viewModel.radioClick();
+                    return true;
+                }
+            } else {
+                viewModel.radioClickHandler = function () {
+                    viewModel.radioClick();
+                    viewModel.radioClickExtend();
+                    return true;
+                }
+            }
+
+
+            ko.utils.arrayMap(viewModel.columns, function (item) {
+                if (item.columnType == undefined) {
+                    item.columnType = 'text';
+                }
+                if (item.sortable == undefined) {
+                    item.sortable = false;
+                }
+                if (item.headerTextTrans == undefined) {
+                    item.headerTextTrans = '';
+                }
+                if (item.display == undefined) {
+                    item.display = true;
+                }
+                if (item.needTrans == undefined) {
+                    item.needTrans = false;
+                }
+            });
+
+            if (viewModel.tmplType == 'card') {
+                templateEngine.addTemplate("ko_simpleGrid_grid", "\
+                <div class='ko-grid-container'>\
+                    <div class='ko-grid-menu' data-bind='visible:showMenu'>\
+                        <div class='ko-grid-option'>\
+                            <img id='ko_grid_layout' class='cursor-pointer' src='pic/res_list.png' data-bind='click:changeTemplateHandler'/>\
+                            <p id=\"pblist-checkall\" target=\"pblist\" class=\"checkbox checkboxToggle\">\
+                                <input type='checkbox' id='ko_grid_checkAll' data-bind='visible: tmplType==\"card\"&&data().length>0,click: clickCheckAll' />\
+                            </p>\
+                        </div>\
+                        <div class='clean'></div>\
+                    </div>\
+                    <div id=\"pblist\" class=\"ko-grid\" data-bind=\"foreach: itemsOnCurrentPage\">\
+                        <div class=\"ko-grid-card\" >\
+                            <div class=\"ko-grid-card-content\" data-bind=\"foreach: $parent.columns ,click:function(){$root.rowClickHandler($data[$root.idName])}\">\
+                                <!-- ko if: display==true -->\
+                                <p data-bind=\"attr:{title:typeof rowText == 'function' ? rowText($parent) : $parent[rowText]},text: $root.ellipsisText(typeof rowText == 'function' ? rowText($parent) : $parent[rowText])\"></p>\
+                                <!-- /ko -->\
+                            </div>\
+                            <div class=\"ko-grid-card-delete\" data-bind=\"click:function(){$root.deleteHandler($data[$root.idName]);}\" >×</div>\
+                            <div class=\"ko-grid-card-check\" ><p class=\"checkbox\"><input type='checkbox' data-bind='value: $data[$root.idName],attr:{primaryValue:$data[$root.primaryColumn]}' target=\"pblist-checkall\"/></p></div>\
+                        </div>\
+                     <div>\
+                </div>");
+            } else {
+                templateEngine.addTemplate("ko_simpleGrid_grid", "\
+                <div class='ko-grid-container'>\
+                    <div class='ko-grid-menu' data-bind='visible:showMenu'>\
+                        <div class='ko-grid-option'>\
+                            <img id='ko_grid_layout' class='cursor-pointer' src='pic/res_card.png'  data-bind='click:changeTemplateHandler'/>\
+                        </div>\
+                        <div class='clean'></div>\
+                    </div>\
+                    <table data-bind=\"attr:{'class':className}\" cellspacing=\"0\" cellspadding='0'>\
+                    <thead>\
+                        <tr data-bind=\"foreach: columns\" >\
+                           <!-- ko if: columnType=='checkbox' -->\
+                               <th data-bind='attr:{width:width}, visible: display'>\
+                                   <p id=\"pblist-checkall\" target=\"pblist\" class=\"checkbox checkboxToggle\" data-bind='click:$root.clickCheckAll'>\
+                                       <input type='checkbox' id='ko_grid_checkAll'/>\
+                                   </p>\
+                               </th>\
+                           <!-- /ko --> \
+                           <!-- ko if: columnType=='text' || columnType=='image' -->\
+                               <!-- ko if: sortable==true -->\
+                               <th data-bind=\"visible: display, css: {'ko-grid-th-sortable':rowText!=$root.sortField(),'ko-grid-th-desc':(rowText==$root.sortField() && 'DESC'==$root.sortDirection()),'ko-grid-th-asc': (rowText==$root.sortField() && 'ASC'==$root.sortDirection())},attr:{id:'ko_grid_th_'+rowText,width:width},click:function(event,data){$root.sort(rowText)}\"><a href='#' data-bind=\"attr:{\'data-trans\': headerTextTrans}\"></a></th>\
+                               <!-- /ko --> \
+                               <!-- ko if: sortable==false -->\
+                               <th nowrap='nowrap' data-bind=\"visible: display, attr:{width:width,\'data-trans\': headerTextTrans}\"></th>\
+                               <!-- /ko --> \
+                           <!-- /ko --> \
+                           <!-- ko if: columnType=='radio' -->\
+                               <th nowrap='nowrap' data-bind=\"visible: display, attr:{width:width,\'data-trans\': headerTextTrans}\"></th>\
+                           <!-- /ko --> \
+						   <!-- ko if: columnType=='button' -->\
+                               <th nowrap='nowrap' data-bind=\"visible: display, attr:{width:width,\'data-trans\': headerTextTrans}\"></th>\
+                           <!-- /ko --> \
+                        </tr>\
+                    </thead>\
+                    <tbody id=\"pblist\" data-bind=\"foreach: itemsOnCurrentPage\">\
+                        <tr data-bind=\"foreach: $parent.columns,css:{'odd': $index() % 2==1,'even':$index()%2==0 } \">\
+                            <!-- ko if: columnType=='checkbox' -->\
+                            <td class = 'ko-grid-center'><p class=\"checkbox\" manualControl='true' data-bind='attr:{id:\"chk__\"+ $parent[rowText]},click:function(){$root.clickCheck($parent[rowText])}'><input type='checkbox' data-bind='value: $parent[rowText],attr:{primaryValue:$parent[$root.primaryColumn]}' target=\"pblist-checkall\"/></p></td>\
+                            <!-- /ko --> \
+                            <!-- ko if: columnType=='radio' -->\
+                            <td class = 'ko-grid-center'><input type='radio' name='ko_grid_radio' data-bind='click:$root.radioClickHandler,value: $parent[rowText],attr:{primaryValue:$parent[$root.primaryColumn]}'/></td>\
+                            <!-- /ko --> \
+                            <!-- ko if: columnType=='text' && !needTrans -->\
+                            <td class = 'ko-grid-center' data-bind=\"visible: display, css:{'cursor-pointer':$root.hasRowClickHandler },text: typeof rowText == 'function' ? rowText($parent) : $parent[rowText], click:function(){$root.rowClickHandler($parent[$root.idName])}\"></td>\
+                            <!-- /ko --> \
+                            <!-- ko if: columnType=='text' && needTrans -->\
+                            <td class = 'ko-grid-center' data-bind=\"visible: display, css:{'cursor-pointer':$root.hasRowClickHandler },click:function(){$root.rowClickHandler($parent[$root.idName])}\">\
+                                <span data-bind=\"attr: {\'data-trans\': $parent[rowText]}\"></span>\
+                            </td>\
+                            <!-- /ko -->\
+                            <!-- ko if: columnType=='image' -->\
+                            <td class = 'ko-grid-center' data-bind=\"visible: display, css:{'cursor-pointer':$root.hasRowClickHandler },click:function(){$root.rowClickHandler($parent[$root.idName])}\">\
+                                <img data-bind=\"attr: {src: $parent[rowText]}\"/>\
+                            </td>\
+                            <!-- /ko --> \
+							<!-- ko if: columnType=='button' -->\
+                            <td class = 'ko-grid-center' data-bind=\"visible: display\"><input type=\"button\" class=\"btn-1 btn-ex\" data-bind=\"visible:$parent[\'btnDisplay\'],enable:$parent[\'enabled\'],attr:{\'data-trans\':$parent[\'actionTrans\']},click:$parent['action']\"/></td>\
+                            <!-- /ko --> \
+                        </tr>\
+                    </tbody>\
+                </table>\
+                </div>");
+            }
+            templateEngine.addTemplate("ko_simpleGrid_pageLinks", "\
+                    <div class=\"ko-grid-pageLinks\">\
+                        <a class='ko-grid-pager' href='javascript:void(0)' data-bind=\"click:previousPage,enable:$root.fixCurrentPageIndex($root.currentPageIndex())>0,visible:$root.afterSearchData().length>0,css:{'ko-grid-pager-disabled': $root.fixCurrentPageIndex($root.currentPageIndex())==0}\">&lt;&lt;</a>\
+                        <a href='javascript:void(0)' data-bind=\"visible:$root.afterSearchData().length>0,text: 1, click: function() { $root.changePage(0); }, css: {'ko-grid-pager-selected': 0 == $root.fixCurrentPageIndex($root.currentPageIndex()),'ko-grid-pager':0 != $root.fixCurrentPageIndex($root.currentPageIndex()) }\"></a>\
+                        <span data-bind='visible:pagerStart()>2'>...</span>\
+                        <!-- ko foreach: ko.utils.range(pagerStart,pagerEnd) -->\
+                            <a href='javascript:void(0)' data-bind=\"text: $data + 1, click: function() { $root.changePage($data); }, disable:$data == $root.fixCurrentPageIndex($root.currentPageIndex()) ,css: {'ko-grid-pager-selected': $data == $root.fixCurrentPageIndex($root.currentPageIndex()),'ko-grid-pager':$data != $root.fixCurrentPageIndex($root.currentPageIndex()) }\"></a>\
+                        <!-- /ko -->\
+                        <span data-bind='visible:pagerEnd()<maxPageIndex()-2'>...</span>\
+                        <a href='javascript:void(0)' data-bind=\"visible:maxPageIndex()>0,text: maxPageIndex()+1, click: function() { $root.changePage(maxPageIndex());}, css: {'ko-grid-pager-selected':  maxPageIndex() == $root.fixCurrentPageIndex($root.currentPageIndex()),'ko-grid-pager': maxPageIndex() != $root.fixCurrentPageIndex($root.currentPageIndex()) }\"></a>\
+                        <a class='ko-grid-pager' href='javascript:void(0)' data-bind=\"click:nextPage,enable:$root.fixCurrentPageIndex($root.currentPageIndex())<maxPageIndex(),visible:$root.afterSearchData().length>0,css:{'ko-grid-pager-disabled': $root.fixCurrentPageIndex($root.currentPageIndex())==maxPageIndex()}\">&gt;&gt;</a>\
+                        <span style='display:none;'><span>(</span><span id='ko_simpleGrid_recordCount' data-bind='text:$root.afterSearchData().length'></span><span>)</span></span>\
+						<div class=\"input-group margin-left-10\" data-bind=\"visible:$root.afterSearchData().length>0\" style='width: 170px;'><label class=\"input-group-addon\" data-trans=\"page\"></label>\
+						<input id=\"ko-grid-input-page\" type=\"text\" data-bind=\"value:pageToGo,valueUpdate: 'afterkeydown'\" class=\"form-control\"/>\
+						<label class=\"input-group-addon cursorhand\" data-trans=\"go\" data-bind=\"click:function() { if(/^[0-9]+$/.test(pageToGo()) && (parseInt(pageToGo())-1) <= maxPageIndex() && (parseInt(pageToGo())-1) >= 0){$root.changePage(parseInt(pageToGo())-1); pageToGo(''); }} \"></label></div>\
+                    </div>");
+
+            return { 'controlsDescendantBindings':true };
+        },
+        // This method is called to initialize the node, and will also be called again if you change what the grid is bound to
+        update:function (element, viewModelAccessor, allBindingsAccessor) {
+            var viewModel = viewModelAccessor(), allBindings = allBindingsAccessor();
+
+            // Empty the element
+            while (element.firstChild)
+                ko.removeNode(element.firstChild);
+
+            // Allow the default templates to be overridden
+            var gridTemplateName = allBindings.simpleGridTemplate || "ko_simpleGrid_grid",
+                pageLinksTemplateName = allBindings.simpleGridPagerTemplate || "ko_simpleGrid_pageLinks";
+
+            // Render the main grid
+            var gridContainer = element.appendChild(document.createElement("DIV"));
+            ko.renderTemplate(gridTemplateName, viewModel, { templateEngine:templateEngine }, gridContainer, "replaceNode");
+
+            // Render the page links
+            if (viewModel.showPager) {
+                var pageLinksContainer = element.appendChild(document.createElement("DIV"));
+                ko.renderTemplate(pageLinksTemplateName, viewModel, { templateEngine:templateEngine }, pageLinksContainer, "replaceNode");
+            }
+        }
+    };
+})();
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/require-jquery.js b/ap/app/zte_webui/js/3rd/require-jquery.js
new file mode 100755
index 0000000..4167af3
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/require-jquery.js
@@ -0,0 +1,11441 @@
+/** vim: et:ts=4:sw=4:sts=4
+ * @license RequireJS 2.0.2 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/requirejs for details
+ */
+/*jslint regexp: true, nomen: true */
+/*global window, navigator, document, importScripts, jQuery, setTimeout, opera */
+
+var requirejs, require, define;
+(function (global) {
+    'use strict';
+
+    var version = '0.0.0',
+        commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
+        cjsRequireRegExp = /require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
+        jsSuffixRegExp = /\.js$/,
+        currDirRegExp = /^\.\//,
+        ostring = Object.prototype.toString,
+        ap = Array.prototype,
+        aps = ap.slice,
+        apsp = ap.splice,
+        isBrowser = !!(typeof window !== 'undefined' && navigator && document),
+        isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
+        //PS3 indicates loaded and complete, but need to wait for complete
+        //specifically. Sequence is 'loading', 'loaded', execution,
+        // then 'complete'. The UA check is unfortunate, but not sure how
+        //to feature test w/o causing perf issues.
+        readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
+                      /^complete$/ : /^(complete|loaded)$/,
+        defContextName = '_',
+        //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
+        isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
+        contexts = {},
+        cfg = {},
+        globalDefQueue = [],
+        useInteractive = false,
+        req, s, head, baseElement, dataMain, src,
+        interactiveScript, currentlyAddingScript, mainScript, subPath;
+
+    function isFunction(it) {
+        return ostring.call(it) === '[object Function]';
+    }
+
+    function isArray(it) {
+        return ostring.call(it) === '[object Array]';
+    }
+
+    /**
+     * Helper function for iterating over an array. If the func returns
+     * a true value, it will break out of the loop.
+     */
+    function each(ary, func) {
+        if (ary) {
+            var i;
+            for (i = 0; i < ary.length; i += 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function for iterating over an array backwards. If the func
+     * returns a true value, it will break out of the loop.
+     */
+    function eachReverse(ary, func) {
+        if (ary) {
+            var i;
+            for (i = ary.length - 1; i > -1; i -= 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    function hasProp(obj, prop) {
+        return obj.hasOwnProperty(prop);
+    }
+
+    /**
+     * Cycles over properties in an object and calls a function for each
+     * property value. If the function returns a truthy value, then the
+     * iteration is stopped.
+     */
+    function eachProp(obj, func) {
+        var prop;
+        for (prop in obj) {
+            if (obj.hasOwnProperty(prop)) {
+                if (func(obj[prop], prop)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Simple function to mix in properties from source into target,
+     * but only if target does not already have a property of the same name.
+     * This is not robust in IE for transferring methods that match
+     * Object.prototype names, but the uses of mixin here seem unlikely to
+     * trigger a problem related to that.
+     */
+    function mixin(target, source, force, deepStringMixin) {
+        if (source) {
+            eachProp(source, function (value, prop) {
+                if (force || !hasProp(target, prop)) {
+                    if (deepStringMixin && typeof value !== 'string') {
+                        if (!target[prop]) {
+                            target[prop] = {};
+                        }
+                        mixin(target[prop], value, force, deepStringMixin);
+                    } else {
+                        target[prop] = value;
+                    }
+                }
+            });
+        }
+        return target;
+    }
+
+    //Similar to Function.prototype.bind, but the 'this' object is specified
+    //first, since it is easier to read/figure out what 'this' will be.
+    function bind(obj, fn) {
+        return function () {
+            return fn.apply(obj, arguments);
+        };
+    }
+
+    function scripts() {
+        return document.getElementsByTagName('script');
+    }
+
+    //Allow getting a global that expressed in
+    //dot notation, like 'a.b.c'.
+    function getGlobal(value) {
+        if (!value) {
+            return value;
+        }
+        var g = global;
+        each(value.split('.'), function (part) {
+            g = g[part];
+        });
+        return g;
+    }
+
+    function makeContextModuleFunc(func, relMap, enableBuildCallback) {
+        return function () {
+            //A version of a require function that passes a moduleName
+            //value for items that may need to
+            //look up paths relative to the moduleName
+            var args = aps.call(arguments, 0), lastArg;
+            if (enableBuildCallback &&
+                isFunction((lastArg = args[args.length - 1]))) {
+                lastArg.__requireJsBuild = true;
+            }
+            args.push(relMap);
+            return func.apply(null, args);
+        };
+    }
+
+    function addRequireMethods(req, context, relMap) {
+        each([
+            ['toUrl'],
+            ['undef'],
+            ['defined', 'requireDefined'],
+            ['specified', 'requireSpecified']
+        ], function (item) {
+            var prop = item[1] || item[0];
+            req[item[0]] = context ? makeContextModuleFunc(context[prop], relMap) :
+                //If no context, then use default context. Reference from
+                //contexts instead of early binding to default context, so
+                //that during builds, the latest instance of the default
+                //context with its config gets used.
+                function () {
+                    var ctx = contexts[defContextName];
+                    return ctx[prop].apply(ctx, arguments);
+                };
+        });
+    }
+
+    /**
+     * Constructs an error with a pointer to an URL with more information.
+     * @param {String} id the error ID that maps to an ID on a web page.
+     * @param {String} message human readable error.
+     * @param {Error} [err] the original error, if there is one.
+     *
+     * @returns {Error}
+     */
+    function makeError(id, msg, err, requireModules) {
+        var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
+        e.requireType = id;
+        e.requireModules = requireModules;
+        if (err) {
+            e.originalError = err;
+        }
+        return e;
+    }
+
+    if (typeof define !== 'undefined') {
+        //If a define is already in play via another AMD loader,
+        //do not overwrite.
+        return;
+    }
+
+    if (typeof requirejs !== 'undefined') {
+        if (isFunction(requirejs)) {
+            //Do not overwrite and existing requirejs instance.
+            return;
+        }
+        cfg = requirejs;
+        requirejs = undefined;
+    }
+
+    //Allow for a require config object
+    if (typeof require !== 'undefined' && !isFunction(require)) {
+        //assume it is a config object.
+        cfg = require;
+        require = undefined;
+    }
+
+    function newContext(contextName) {
+        var config = {
+                waitSeconds: 7,
+                baseUrl: './',
+                paths: {},
+                pkgs: {},
+                shim: {}
+            },
+            registry = {},
+            undefEvents = {},
+            defQueue = [],
+            defined = {},
+            urlFetched = {},
+            requireCounter = 1,
+            unnormalizedCounter = 1,
+            //Used to track the order in which modules
+            //should be executed, by the order they
+            //load. Important for consistent cycle resolution
+            //behavior.
+            waitAry = [],
+            inCheckLoaded, Module, context, handlers,
+            checkLoadedTimeoutId;
+
+        /**
+         * Trims the . and .. from an array of path segments.
+         * It will keep a leading path segment if a .. will become
+         * the first path segment, to help with module name lookups,
+         * which act like paths, but can be remapped. But the end result,
+         * all paths that use this function should look normalized.
+         * NOTE: this method MODIFIES the input array.
+         * @param {Array} ary the array of path segments.
+         */
+        function trimDots(ary) {
+            var i, part;
+            for (i = 0; ary[i]; i+= 1) {
+                part = ary[i];
+                if (part === '.') {
+                    ary.splice(i, 1);
+                    i -= 1;
+                } else if (part === '..') {
+                    if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
+                        //End of the line. Keep at least one non-dot
+                        //path segment at the front so it can be mapped
+                        //correctly to disk. Otherwise, there is likely
+                        //no path mapping for a path starting with '..'.
+                        //This can still fail, but catches the most reasonable
+                        //uses of ..
+                        break;
+                    } else if (i > 0) {
+                        ary.splice(i - 1, 2);
+                        i -= 2;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Given a relative module name, like ./something, normalize it to
+         * a real name that can be mapped to a path.
+         * @param {String} name the relative name
+         * @param {String} baseName a real name that the name arg is relative
+         * to.
+         * @param {Boolean} applyMap apply the map config to the value. Should
+         * only be done if this normalization is for a dependency ID.
+         * @returns {String} normalized name
+         */
+        function normalize(name, baseName, applyMap) {
+            var baseParts = baseName && baseName.split('/'),
+                map = config.map,
+                starMap = map && map['*'],
+                pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment,
+                foundMap;
+
+            //Adjust any relative paths.
+            if (name && name.charAt(0) === '.') {
+                //If have a base name, try to normalize against it,
+                //otherwise, assume it is a top-level require that will
+                //be relative to baseUrl in the end.
+                if (baseName) {
+                    if (config.pkgs[baseName]) {
+                        //If the baseName is a package name, then just treat it as one
+                        //name to concat the name with.
+                        baseParts = [baseName];
+                    } else {
+                        //Convert baseName to array, and lop off the last part,
+                        //so that . matches that 'directory' and not name of the baseName's
+                        //module. For instance, baseName of 'one/two/three', maps to
+                        //'one/two/three.js', but we want the directory, 'one/two' for
+                        //this normalization.
+                        baseParts = baseParts.slice(0, baseParts.length - 1);
+                    }
+
+                    name = baseParts.concat(name.split('/'));
+                    trimDots(name);
+
+                    //Some use of packages may use a . path to reference the
+                    //'main' module name, so normalize for that.
+                    pkgConfig = config.pkgs[(pkgName = name[0])];
+                    name = name.join('/');
+                    if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
+                        name = pkgName;
+                    }
+                } else if (name.indexOf('./') === 0) {
+                    // No baseName, so this is ID is resolved relative
+                    // to baseUrl, pull off the leading dot.
+                    name = name.substring(2);
+                }
+            }
+
+            //Apply map config if available.
+            if (applyMap && (baseParts || starMap) && map) {
+                nameParts = name.split('/');
+
+                for (i = nameParts.length; i > 0; i -= 1) {
+                    nameSegment = nameParts.slice(0, i).join('/');
+
+                    if (baseParts) {
+                        //Find the longest baseName segment match in the config.
+                        //So, do joins on the biggest to smallest lengths of baseParts.
+                        for (j = baseParts.length; j > 0; j -= 1) {
+                            mapValue = map[baseParts.slice(0, j).join('/')];
+
+                            //baseName segment has  config, find if it has one for
+                            //this name.
+                            if (mapValue) {
+                                mapValue = mapValue[nameSegment];
+                                if (mapValue) {
+                                    //Match, update name to the new value.
+                                    foundMap = mapValue;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+
+                    if (!foundMap && starMap && starMap[nameSegment]) {
+                        foundMap = starMap[nameSegment];
+                    }
+
+                    if (foundMap) {
+                        nameParts.splice(0, i, foundMap);
+                        name = nameParts.join('/');
+                        break;
+                    }
+                }
+            }
+
+            return name;
+        }
+
+        function removeScript(name) {
+            if (isBrowser) {
+                each(scripts(), function (scriptNode) {
+                    if (scriptNode.getAttribute('data-requiremodule') === name &&
+                        scriptNode.getAttribute('data-requirecontext') === context.contextName) {
+                        scriptNode.parentNode.removeChild(scriptNode);
+                        return true;
+                    }
+                });
+            }
+        }
+
+        function hasPathFallback(id) {
+            var pathConfig = config.paths[id];
+            if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
+                removeScript(id);
+                //Pop off the first array value, since it failed, and
+                //retry
+                pathConfig.shift();
+                context.undef(id);
+                context.require([id]);
+                return true;
+            }
+        }
+
+        /**
+         * Creates a module mapping that includes plugin prefix, module
+         * name, and path. If parentModuleMap is provided it will
+         * also normalize the name via require.normalize()
+         *
+         * @param {String} name the module name
+         * @param {String} [parentModuleMap] parent module map
+         * for the module name, used to resolve relative names.
+         * @param {Boolean} isNormalized: is the ID already normalized.
+         * This is true if this call is done for a define() module ID.
+         * @param {Boolean} applyMap: apply the map config to the ID.
+         * Should only be true if this map is for a dependency.
+         *
+         * @returns {Object}
+         */
+        function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
+            var index = name ? name.indexOf('!') : -1,
+                prefix = null,
+                parentName = parentModuleMap ? parentModuleMap.name : null,
+                originalName = name,
+                isDefine = true,
+                normalizedName = '',
+                url, pluginModule, suffix;
+
+            //If no name, then it means it is a require call, generate an
+            //internal name.
+            if (!name) {
+                isDefine = false;
+                name = '_@r' + (requireCounter += 1);
+            }
+
+            if (index !== -1) {
+                prefix = name.substring(0, index);
+                name = name.substring(index + 1, name.length);
+            }
+
+            if (prefix) {
+                prefix = normalize(prefix, parentName, applyMap);
+                pluginModule = defined[prefix];
+            }
+
+            //Account for relative paths if there is a base name.
+            if (name) {
+                if (prefix) {
+                    if (pluginModule && pluginModule.normalize) {
+                        //Plugin is loaded, use its normalize method.
+                        normalizedName = pluginModule.normalize(name, function (name) {
+                            return normalize(name, parentName, applyMap);
+                        });
+                    } else {
+                        normalizedName = normalize(name, parentName, applyMap);
+                    }
+                } else {
+                    //A regular module.
+                    normalizedName = normalize(name, parentName, applyMap);
+
+                    //Calculate url for the module, if it has a name.
+                    //Use name here since nameToUrl also calls normalize,
+                    //and for relative names that are outside the baseUrl
+                    //this causes havoc. Was thinking of just removing
+                    //parentModuleMap to avoid extra normalization, but
+                    //normalize() still does a dot removal because of
+                    //issue #142, so just pass in name here and redo
+                    //the normalization. Paths outside baseUrl are just
+                    //messy to support.
+                    url = context.nameToUrl(name, null, parentModuleMap);
+                }
+            }
+
+            //If the id is a plugin id that cannot be determined if it needs
+            //normalization, stamp it with a unique ID so two matching relative
+            //ids that may conflict can be separate.
+            suffix = prefix && !pluginModule && !isNormalized ?
+                     '_unnormalized' + (unnormalizedCounter += 1) :
+                     '';
+
+            return {
+                prefix: prefix,
+                name: normalizedName,
+                parentMap: parentModuleMap,
+                unnormalized: !!suffix,
+                url: url,
+                originalName: originalName,
+                isDefine: isDefine,
+                id: (prefix ?
+                    prefix + '!' + normalizedName :
+                    normalizedName) + suffix
+            };
+        }
+
+        function getModule(depMap) {
+            var id = depMap.id,
+                mod = registry[id];
+
+            if (!mod) {
+                mod = registry[id] = new context.Module(depMap);
+            }
+
+            return mod;
+        }
+
+        function on(depMap, name, fn) {
+            var id = depMap.id,
+                mod = registry[id];
+
+            if (hasProp(defined, id) &&
+                (!mod || mod.defineEmitComplete)) {
+                if (name === 'defined') {
+                    fn(defined[id]);
+                }
+            } else {
+                getModule(depMap).on(name, fn);
+            }
+        }
+
+        function onError(err, errback) {
+            var ids = err.requireModules,
+                notified = false;
+
+            if (errback) {
+                errback(err);
+            } else {
+                each(ids, function (id) {
+                    var mod = registry[id];
+                    if (mod) {
+                        //Set error on module, so it skips timeout checks.
+                        mod.error = err;
+                        if (mod.events.error) {
+                            notified = true;
+                            mod.emit('error', err);
+                        }
+                    }
+                });
+
+                if (!notified) {
+                    req.onError(err);
+                }
+            }
+        }
+
+        /**
+         * Internal method to transfer globalQueue items to this context's
+         * defQueue.
+         */
+        function takeGlobalQueue() {
+            //Push all the globalDefQueue items into the context's defQueue
+            if (globalDefQueue.length) {
+                //Array splice in the values since the context code has a
+                //local var ref to defQueue, so cannot just reassign the one
+                //on context.
+                apsp.apply(defQueue,
+                           [defQueue.length - 1, 0].concat(globalDefQueue));
+                globalDefQueue = [];
+            }
+        }
+
+        /**
+         * Helper function that creates a require function object to give to
+         * modules that ask for it as a dependency. It needs to be specific
+         * per module because of the implication of path mappings that may
+         * need to be relative to the module name.
+         */
+        function makeRequire(mod, enableBuildCallback, altRequire) {
+            var relMap = mod && mod.map,
+                modRequire = makeContextModuleFunc(altRequire || context.require,
+                                                   relMap,
+                                                   enableBuildCallback);
+
+            addRequireMethods(modRequire, context, relMap);
+            modRequire.isBrowser = isBrowser;
+
+            return modRequire;
+        }
+
+        handlers = {
+            'require': function (mod) {
+                return makeRequire(mod);
+            },
+            'exports': function (mod) {
+                mod.usingExports = true;
+                if (mod.map.isDefine) {
+                    return (mod.exports = defined[mod.map.id] = {});
+                }
+            },
+            'module': function (mod) {
+                return (mod.module = {
+                    id: mod.map.id,
+                    uri: mod.map.url,
+                    config: function () {
+                        return (config.config && config.config[mod.map.id]) || {};
+                    },
+                    exports: defined[mod.map.id]
+                });
+            }
+        };
+
+        function removeWaiting(id) {
+            //Clean up machinery used for waiting modules.
+            delete registry[id];
+
+            each(waitAry, function (mod, i) {
+                if (mod.map.id === id) {
+                    waitAry.splice(i, 1);
+                    if (!mod.defined) {
+                        context.waitCount -= 1;
+                    }
+                    return true;
+                }
+            });
+        }
+
+        function findCycle(mod, traced) {
+            var id = mod.map.id,
+                depArray = mod.depMaps,
+                foundModule;
+
+            //Do not bother with unitialized modules or not yet enabled
+            //modules.
+            if (!mod.inited) {
+                return;
+            }
+
+            //Found the cycle.
+            if (traced[id]) {
+                return mod;
+            }
+
+            traced[id] = true;
+
+            //Trace through the dependencies.
+            each(depArray, function (depMap) {
+                var depId = depMap.id,
+                    depMod = registry[depId];
+
+                if (!depMod) {
+                    return;
+                }
+
+                if (!depMod.inited || !depMod.enabled) {
+                    //Dependency is not inited, so this cannot
+                    //be used to determine a cycle.
+                    foundModule = null;
+                    delete traced[id];
+                    return true;
+                }
+
+                //mixin traced to a new object for each dependency, so that
+                //sibling dependencies in this object to not generate a
+                //false positive match on a cycle. Ideally an Object.create
+                //type of prototype delegation would be used here, but
+                //optimizing for file size vs. execution speed since hopefully
+                //the trees are small for circular dependency scans relative
+                //to the full app perf.
+                return (foundModule = findCycle(depMod, mixin({}, traced)));
+            });
+
+            return foundModule;
+        }
+
+        function forceExec(mod, traced, uninited) {
+            var id = mod.map.id,
+                depArray = mod.depMaps;
+
+            if (!mod.inited || !mod.map.isDefine) {
+                return;
+            }
+
+            if (traced[id]) {
+                return defined[id];
+            }
+
+            traced[id] = mod;
+
+            each(depArray, function(depMap) {
+                var depId = depMap.id,
+                    depMod = registry[depId],
+                    value;
+
+                if (handlers[depId]) {
+                    return;
+                }
+
+                if (depMod) {
+                    if (!depMod.inited || !depMod.enabled) {
+                        //Dependency is not inited,
+                        //so this module cannot be
+                        //given a forced value yet.
+                        uninited[id] = true;
+                        return;
+                    }
+
+                    //Get the value for the current dependency
+                    value = forceExec(depMod, traced, uninited);
+
+                    //Even with forcing it may not be done,
+                    //in particular if the module is waiting
+                    //on a plugin resource.
+                    if (!uninited[depId]) {
+                        mod.defineDepById(depId, value);
+                    }
+                }
+            });
+
+            mod.check(true);
+
+            return defined[id];
+        }
+
+        function modCheck(mod) {
+            mod.check();
+        }
+
+        function checkLoaded() {
+            var waitInterval = config.waitSeconds * 1000,
+                //It is possible to disable the wait interval by using waitSeconds of 0.
+                expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
+                noLoads = [],
+                stillLoading = false,
+                needCycleCheck = true,
+                map, modId, err, usingPathFallback;
+
+            //Do not bother if this call was a result of a cycle break.
+            if (inCheckLoaded) {
+                return;
+            }
+
+            inCheckLoaded = true;
+
+            //Figure out the state of all the modules.
+            eachProp(registry, function (mod) {
+                map = mod.map;
+                modId = map.id;
+
+                //Skip things that are not enabled or in error state.
+                if (!mod.enabled) {
+                    return;
+                }
+
+                if (!mod.error) {
+                    //If the module should be executed, and it has not
+                    //been inited and time is up, remember it.
+                    if (!mod.inited && expired) {
+                        if (hasPathFallback(modId)) {
+                            usingPathFallback = true;
+                            stillLoading = true;
+                        } else {
+                            noLoads.push(modId);
+                            removeScript(modId);
+                        }
+                    } else if (!mod.inited && mod.fetched && map.isDefine) {
+                        stillLoading = true;
+                        if (!map.prefix) {
+                            //No reason to keep looking for unfinished
+                            //loading. If the only stillLoading is a
+                            //plugin resource though, keep going,
+                            //because it may be that a plugin resource
+                            //is waiting on a non-plugin cycle.
+                            return (needCycleCheck = false);
+                        }
+                    }
+                }
+            });
+
+            if (expired && noLoads.length) {
+                //If wait time expired, throw error of unloaded modules.
+                err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
+                err.contextName = context.contextName;
+                return onError(err);
+            }
+
+            //Not expired, check for a cycle.
+            if (needCycleCheck) {
+
+                each(waitAry, function (mod) {
+                    if (mod.defined) {
+                        return;
+                    }
+
+                    var cycleMod = findCycle(mod, {}),
+                        traced = {};
+
+                    if (cycleMod) {
+                        forceExec(cycleMod, traced, {});
+
+                        //traced modules may have been
+                        //removed from the registry, but
+                        //their listeners still need to
+                        //be called.
+                        eachProp(traced, modCheck);
+                    }
+                });
+
+                //Now that dependencies have
+                //been satisfied, trigger the
+                //completion check that then
+                //notifies listeners.
+                eachProp(registry, modCheck);
+            }
+
+            //If still waiting on loads, and the waiting load is something
+            //other than a plugin resource, or there are still outstanding
+            //scripts, then just try back later.
+            if ((!expired || usingPathFallback) && stillLoading) {
+                //Something is still waiting to load. Wait for it, but only
+                //if a timeout is not already in effect.
+                if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
+                    checkLoadedTimeoutId = setTimeout(function () {
+                        checkLoadedTimeoutId = 0;
+                        checkLoaded();
+                    }, 50);
+                }
+            }
+
+            inCheckLoaded = false;
+        }
+
+        Module = function (map) {
+            this.events = undefEvents[map.id] || {};
+            this.map = map;
+            this.shim = config.shim[map.id];
+            this.depExports = [];
+            this.depMaps = [];
+            this.depMatched = [];
+            this.pluginMaps = {};
+            this.depCount = 0;
+
+            /* this.exports this.factory
+               this.depMaps = [],
+               this.enabled, this.fetched
+            */
+        };
+
+        Module.prototype = {
+            init: function(depMaps, factory, errback, options) {
+                options = options || {};
+
+                //Do not do more inits if already done. Can happen if there
+                //are multiple define calls for the same module. That is not
+                //a normal, common case, but it is also not unexpected.
+                if (this.inited) {
+                    return;
+                }
+
+                this.factory = factory;
+
+                if (errback) {
+                    //Register for errors on this module.
+                    this.on('error', errback);
+                } else if (this.events.error) {
+                    //If no errback already, but there are error listeners
+                    //on this module, set up an errback to pass to the deps.
+                    errback = bind(this, function (err) {
+                        this.emit('error', err);
+                    });
+                }
+
+                //Do a copy of the dependency array, so that
+                //source inputs are not modified. For example
+                //"shim" deps are passed in here directly, and
+                //doing a direct modification of the depMaps array
+                //would affect that config.
+                this.depMaps = depMaps && depMaps.slice(0);
+                this.depMaps.rjsSkipMap = depMaps.rjsSkipMap;
+
+                this.errback = errback;
+
+                //Indicate this module has be initialized
+                this.inited = true;
+
+                this.ignore = options.ignore;
+
+                //Could have option to init this module in enabled mode,
+                //or could have been previously marked as enabled. However,
+                //the dependencies are not known until init is called. So
+                //if enabled previously, now trigger dependencies as enabled.
+                if (options.enabled || this.enabled) {
+                    //Enable this module and dependencies.
+                    //Will call this.check()
+                    this.enable();
+                } else {
+                    this.check();
+                }
+            },
+
+            defineDepById: function (id, depExports) {
+                var i;
+
+                //Find the index for this dependency.
+                each(this.depMaps, function (map, index) {
+                    if (map.id === id) {
+                        i = index;
+                        return true;
+                    }
+                });
+
+                return this.defineDep(i, depExports);
+            },
+
+            defineDep: function (i, depExports) {
+                //Because of cycles, defined callback for a given
+                //export can be called more than once.
+                if (!this.depMatched[i]) {
+                    this.depMatched[i] = true;
+                    this.depCount -= 1;
+                    this.depExports[i] = depExports;
+                }
+            },
+
+            fetch: function () {
+                if (this.fetched) {
+                    return;
+                }
+                this.fetched = true;
+
+                context.startTime = (new Date()).getTime();
+
+                var map = this.map;
+
+                //If the manager is for a plugin managed resource,
+                //ask the plugin to load it now.
+                if (this.shim) {
+                    makeRequire(this, true)(this.shim.deps || [], bind(this, function () {
+                        return map.prefix ? this.callPlugin() : this.load();
+                    }));
+                } else {
+                    //Regular dependency.
+                    return map.prefix ? this.callPlugin() : this.load();
+                }
+            },
+
+            load: function() {
+                var url = this.map.url;
+
+                //Regular dependency.
+                if (!urlFetched[url]) {
+                    urlFetched[url] = true;
+                    context.load(this.map.id, url);
+                }
+            },
+
+            /**
+             * Checks is the module is ready to define itself, and if so,
+             * define it. If the silent argument is true, then it will just
+             * define, but not notify listeners, and not ask for a context-wide
+             * check of all loaded modules. That is useful for cycle breaking.
+             */
+            check: function (silent) {
+                if (!this.enabled || this.enabling) {
+                    return;
+                }
+
+                var id = this.map.id,
+                    depExports = this.depExports,
+                    exports = this.exports,
+                    factory = this.factory,
+                    err, cjsModule;
+
+                if (!this.inited) {
+                    this.fetch();
+                } else if (this.error) {
+                    this.emit('error', this.error);
+                } else if (!this.defining) {
+                    //The factory could trigger another require call
+                    //that would result in checking this module to
+                    //define itself again. If already in the process
+                    //of doing that, skip this work.
+                    this.defining = true;
+
+                    if (this.depCount < 1 && !this.defined) {
+                        if (isFunction(factory)) {
+                            //If there is an error listener, favor passing
+                            //to that instead of throwing an error.
+                            if (this.events.error) {
+                                try {
+                                    exports = context.execCb(id, factory, depExports, exports);
+                                } catch (e) {
+                                    err = e;
+                                }
+                            } else {
+                                exports = context.execCb(id, factory, depExports, exports);
+                            }
+
+                            if (this.map.isDefine) {
+                                //If setting exports via 'module' is in play,
+                                //favor that over return value and exports. After that,
+                                //favor a non-undefined return value over exports use.
+                                cjsModule = this.module;
+                                if (cjsModule &&
+                                    cjsModule.exports !== undefined &&
+                                    //Make sure it is not already the exports value
+                                    cjsModule.exports !== this.exports) {
+                                    exports = cjsModule.exports;
+                                } else if (exports === undefined && this.usingExports) {
+                                    //exports already set the defined value.
+                                    exports = this.exports;
+                                }
+                            }
+
+                            if (err) {
+                                err.requireMap = this.map;
+                                err.requireModules = [this.map.id];
+                                err.requireType = 'define';
+                                return onError((this.error = err));
+                            }
+
+                        } else {
+                            //Just a literal value
+                            exports = factory;
+                        }
+
+                        this.exports = exports;
+
+                        if (this.map.isDefine && !this.ignore) {
+                            defined[id] = exports;
+
+                            if (req.onResourceLoad) {
+                                req.onResourceLoad(context, this.map, this.depMaps);
+                            }
+                        }
+
+                        //Clean up
+                        delete registry[id];
+
+                        this.defined = true;
+                        context.waitCount -= 1;
+                        if (context.waitCount === 0) {
+                            //Clear the wait array used for cycles.
+                            waitAry = [];
+                        }
+                    }
+
+                    //Finished the define stage. Allow calling check again
+                    //to allow define notifications below in the case of a
+                    //cycle.
+                    this.defining = false;
+
+                    if (!silent) {
+                        if (this.defined && !this.defineEmitted) {
+                            this.defineEmitted = true;
+                            this.emit('defined', this.exports);
+                            this.defineEmitComplete = true;
+                        }
+                    }
+                }
+            },
+
+            callPlugin: function() {
+                var map = this.map,
+                    id = map.id,
+                    pluginMap = makeModuleMap(map.prefix, null, false, true);
+
+                on(pluginMap, 'defined', bind(this, function (plugin) {
+                    var name = this.map.name,
+                        parentName = this.map.parentMap ? this.map.parentMap.name : null,
+                        load, normalizedMap, normalizedMod;
+
+                    //If current map is not normalized, wait for that
+                    //normalized name to load instead of continuing.
+                    if (this.map.unnormalized) {
+                        //Normalize the ID if the plugin allows it.
+                        if (plugin.normalize) {
+                            name = plugin.normalize(name, function (name) {
+                                return normalize(name, parentName, true);
+                            }) || '';
+                        }
+
+                        normalizedMap = makeModuleMap(map.prefix + '!' + name,
+                                                      this.map.parentMap,
+                                                      false,
+                                                      true);
+                        on(normalizedMap,
+                           'defined', bind(this, function (value) {
+                            this.init([], function () { return value; }, null, {
+                                enabled: true,
+                                ignore: true
+                            });
+                        }));
+                        normalizedMod = registry[normalizedMap.id];
+                        if (normalizedMod) {
+                            if (this.events.error) {
+                                normalizedMod.on('error', bind(this, function (err) {
+                                    this.emit('error', err);
+                                }));
+                            }
+                            normalizedMod.enable();
+                        }
+
+                        return;
+                    }
+
+                    load = bind(this, function (value) {
+                        this.init([], function () { return value; }, null, {
+                            enabled: true
+                        });
+                    });
+
+                    load.error = bind(this, function (err) {
+                        this.inited = true;
+                        this.error = err;
+                        err.requireModules = [id];
+
+                        //Remove temp unnormalized modules for this module,
+                        //since they will never be resolved otherwise now.
+                        eachProp(registry, function (mod) {
+                            if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
+                                removeWaiting(mod.map.id);
+                            }
+                        });
+
+                        onError(err);
+                    });
+
+                    //Allow plugins to load other code without having to know the
+                    //context or how to 'complete' the load.
+                    load.fromText = function (moduleName, text) {
+                        /*jslint evil: true */
+                        var hasInteractive = useInteractive;
+
+                        //Turn off interactive script matching for IE for any define
+                        //calls in the text, then turn it back on at the end.
+                        if (hasInteractive) {
+                            useInteractive = false;
+                        }
+
+                        //Prime the system by creating a module instance for
+                        //it.
+                        getModule(makeModuleMap(moduleName));
+
+                        req.exec(text);
+
+                        if (hasInteractive) {
+                            useInteractive = true;
+                        }
+
+                        //Support anonymous modules.
+                        context.completeLoad(moduleName);
+                    };
+
+                    //Use parentName here since the plugin's name is not reliable,
+                    //could be some weird string with no path that actually wants to
+                    //reference the parentName's path.
+                    plugin.load(map.name, makeRequire(map.parentMap, true, function (deps, cb) {
+                        deps.rjsSkipMap = true;
+                        return context.require(deps, cb);
+                    }), load, config);
+                }));
+
+                context.enable(pluginMap, this);
+                this.pluginMaps[pluginMap.id] = pluginMap;
+            },
+
+            enable: function () {
+                this.enabled = true;
+
+                if (!this.waitPushed) {
+                    waitAry.push(this);
+                    context.waitCount += 1;
+                    this.waitPushed = true;
+                }
+
+                //Set flag mentioning that the module is enabling,
+                //so that immediate calls to the defined callbacks
+                //for dependencies do not trigger inadvertent load
+                //with the depCount still being zero.
+                this.enabling = true;
+
+                //Enable each dependency
+                each(this.depMaps, bind(this, function (depMap, i) {
+                    var id, mod, handler;
+
+                    if (typeof depMap === 'string') {
+                        //Dependency needs to be converted to a depMap
+                        //and wired up to this module.
+                        depMap = makeModuleMap(depMap,
+                                               (this.map.isDefine ? this.map : this.map.parentMap),
+                                               false,
+                                               !this.depMaps.rjsSkipMap);
+                        this.depMaps[i] = depMap;
+
+                        handler = handlers[depMap.id];
+
+                        if (handler) {
+                            this.depExports[i] = handler(this);
+                            return;
+                        }
+
+                        this.depCount += 1;
+
+                        on(depMap, 'defined', bind(this, function (depExports) {
+                            this.defineDep(i, depExports);
+                            this.check();
+                        }));
+
+                        if (this.errback) {
+                            on(depMap, 'error', this.errback);
+                        }
+                    }
+
+                    id = depMap.id;
+                    mod = registry[id];
+
+                    //Skip special modules like 'require', 'exports', 'module'
+                    //Also, don't call enable if it is already enabled,
+                    //important in circular dependency cases.
+                    if (!handlers[id] && mod && !mod.enabled) {
+                        context.enable(depMap, this);
+                    }
+                }));
+
+                //Enable each plugin that is used in
+                //a dependency
+                eachProp(this.pluginMaps, bind(this, function (pluginMap) {
+                    var mod = registry[pluginMap.id];
+                    if (mod && !mod.enabled) {
+                        context.enable(pluginMap, this);
+                    }
+                }));
+
+                this.enabling = false;
+
+                this.check();
+            },
+
+            on: function(name, cb) {
+                var cbs = this.events[name];
+                if (!cbs) {
+                    cbs = this.events[name] = [];
+                }
+                cbs.push(cb);
+            },
+
+            emit: function (name, evt) {
+                each(this.events[name], function (cb) {
+                    cb(evt);
+                });
+                if (name === 'error') {
+                    //Now that the error handler was triggered, remove
+                    //the listeners, since this broken Module instance
+                    //can stay around for a while in the registry/waitAry.
+                    delete this.events[name];
+                }
+            }
+        };
+
+        function callGetModule(args) {
+            getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
+        }
+
+        function removeListener(node, func, name, ieName) {
+            //Favor detachEvent because of IE9
+            //issue, see attachEvent/addEventListener comment elsewhere
+            //in this file.
+            if (node.detachEvent && !isOpera) {
+                //Probably IE. If not it will throw an error, which will be
+                //useful to know.
+                if (ieName) {
+                    node.detachEvent(ieName, func);
+                }
+            } else {
+                node.removeEventListener(name, func, false);
+            }
+        }
+
+        /**
+         * Given an event from a script node, get the requirejs info from it,
+         * and then removes the event listeners on the node.
+         * @param {Event} evt
+         * @returns {Object}
+         */
+        function getScriptData(evt) {
+            //Using currentTarget instead of target for Firefox 2.0's sake. Not
+            //all old browsers will be supported, but this one was easy enough
+            //to support and still makes sense.
+            var node = evt.currentTarget || evt.srcElement;
+
+            //Remove the listeners once here.
+            removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
+            removeListener(node, context.onScriptError, 'error');
+
+            return {
+                node: node,
+                id: node && node.getAttribute('data-requiremodule')
+            };
+        }
+
+        return (context = {
+            config: config,
+            contextName: contextName,
+            registry: registry,
+            defined: defined,
+            urlFetched: urlFetched,
+            waitCount: 0,
+            defQueue: defQueue,
+            Module: Module,
+            makeModuleMap: makeModuleMap,
+
+            /**
+             * Set a configuration for the context.
+             * @param {Object} cfg config object to integrate.
+             */
+            configure: function (cfg) {
+                //Make sure the baseUrl ends in a slash.
+                if (cfg.baseUrl) {
+                    if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
+                        cfg.baseUrl += '/';
+                    }
+                }
+
+                //Save off the paths and packages since they require special processing,
+                //they are additive.
+                var pkgs = config.pkgs,
+                    shim = config.shim,
+                    paths = config.paths,
+                    map = config.map;
+
+                //Mix in the config values, favoring the new values over
+                //existing ones in context.config.
+                mixin(config, cfg, true);
+
+                //Merge paths.
+                config.paths = mixin(paths, cfg.paths, true);
+
+                //Merge map
+                if (cfg.map) {
+                    config.map = mixin(map || {}, cfg.map, true, true);
+                }
+
+                //Merge shim
+                if (cfg.shim) {
+                    eachProp(cfg.shim, function (value, id) {
+                        //Normalize the structure
+                        if (isArray(value)) {
+                            value = {
+                                deps: value
+                            };
+                        }
+                        if (value.exports && !value.exports.__buildReady) {
+                            value.exports = context.makeShimExports(value.exports);
+                        }
+                        shim[id] = value;
+                    });
+                    config.shim = shim;
+                }
+
+                //Adjust packages if necessary.
+                if (cfg.packages) {
+                    each(cfg.packages, function (pkgObj) {
+                        var location;
+
+                        pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
+                        location = pkgObj.location;
+
+                        //Create a brand new object on pkgs, since currentPackages can
+                        //be passed in again, and config.pkgs is the internal transformed
+                        //state for all package configs.
+                        pkgs[pkgObj.name] = {
+                            name: pkgObj.name,
+                            location: location || pkgObj.name,
+                            //Remove leading dot in main, so main paths are normalized,
+                            //and remove any trailing .js, since different package
+                            //envs have different conventions: some use a module name,
+                            //some use a file name.
+                            main: (pkgObj.main || 'main')
+                                  .replace(currDirRegExp, '')
+                                  .replace(jsSuffixRegExp, '')
+                        };
+                    });
+
+                    //Done with modifications, assing packages back to context config
+                    config.pkgs = pkgs;
+                }
+
+                //If there are any "waiting to execute" modules in the registry,
+                //update the maps for them, since their info, like URLs to load,
+                //may have changed.
+                eachProp(registry, function (mod, id) {
+                    mod.map = makeModuleMap(id);
+                });
+
+                //If a deps array or a config callback is specified, then call
+                //require with those args. This is useful when require is defined as a
+                //config object before require.js is loaded.
+                if (cfg.deps || cfg.callback) {
+                    context.require(cfg.deps || [], cfg.callback);
+                }
+            },
+
+            makeShimExports: function (exports) {
+                var func;
+                if (typeof exports === 'string') {
+                    func = function () {
+                        return getGlobal(exports);
+                    };
+                    //Save the exports for use in nodefine checking.
+                    func.exports = exports;
+                    return func;
+                } else {
+                    return function () {
+                        return exports.apply(global, arguments);
+                    };
+                }
+            },
+
+            requireDefined: function (id, relMap) {
+                return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
+            },
+
+            requireSpecified: function (id, relMap) {
+                id = makeModuleMap(id, relMap, false, true).id;
+                return hasProp(defined, id) || hasProp(registry, id);
+            },
+
+            require: function (deps, callback, errback, relMap) {
+                var moduleName, id, map, requireMod, args;
+                if (typeof deps === 'string') {
+                    if (isFunction(callback)) {
+                        //Invalid call
+                        return onError(makeError('requireargs', 'Invalid require call'), errback);
+                    }
+
+                    //Synchronous access to one module. If require.get is
+                    //available (as in the Node adapter), prefer that.
+                    //In this case deps is the moduleName and callback is
+                    //the relMap
+                    if (req.get) {
+                        return req.get(context, deps, callback);
+                    }
+
+                    //Just return the module wanted. In this scenario, the
+                    //second arg (if passed) is just the relMap.
+                    moduleName = deps;
+                    relMap = callback;
+
+                    //Normalize module name, if it contains . or ..
+                    map = makeModuleMap(moduleName, relMap, false, true);
+                    id = map.id;
+
+                    if (!hasProp(defined, id)) {
+                        return onError(makeError('notloaded', 'Module name "' +
+                                    id +
+                                    '" has not been loaded yet for context: ' +
+                                    contextName));
+                    }
+                    return defined[id];
+                }
+
+                //Callback require. Normalize args. if callback or errback is
+                //not a function, it means it is a relMap. Test errback first.
+                if (errback && !isFunction(errback)) {
+                    relMap = errback;
+                    errback = undefined;
+                }
+                if (callback && !isFunction(callback)) {
+                    relMap = callback;
+                    callback = undefined;
+                }
+
+                //Any defined modules in the global queue, intake them now.
+                takeGlobalQueue();
+
+                //Make sure any remaining defQueue items get properly processed.
+                while (defQueue.length) {
+                    args = defQueue.shift();
+                    if (args[0] === null) {
+                        return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
+                    } else {
+                        //args are id, deps, factory. Should be normalized by the
+                        //define() function.
+                        callGetModule(args);
+                    }
+                }
+
+                //Mark all the dependencies as needing to be loaded.
+                requireMod = getModule(makeModuleMap(null, relMap));
+
+                requireMod.init(deps, callback, errback, {
+                    enabled: true
+                });
+
+                checkLoaded();
+
+                return context.require;
+            },
+
+            undef: function (id) {
+                var map = makeModuleMap(id, null, true),
+                    mod = registry[id];
+
+                delete defined[id];
+                delete urlFetched[map.url];
+                delete undefEvents[id];
+
+                if (mod) {
+                    //Hold on to listeners in case the
+                    //module will be attempted to be reloaded
+                    //using a different config.
+                    if (mod.events.defined) {
+                        undefEvents[id] = mod.events;
+                    }
+
+                    removeWaiting(id);
+                }
+            },
+
+            /**
+             * Called to enable a module if it is still in the registry
+             * awaiting enablement. parent module is passed in for context,
+             * used by the optimizer.
+             */
+            enable: function (depMap, parent) {
+                var mod = registry[depMap.id];
+                if (mod) {
+                    getModule(depMap).enable();
+                }
+            },
+
+            /**
+             * Internal method used by environment adapters to complete a load event.
+             * A load event could be a script load or just a load pass from a synchronous
+             * load call.
+             * @param {String} moduleName the name of the module to potentially complete.
+             */
+            completeLoad: function (moduleName) {
+                var shim = config.shim[moduleName] || {},
+                shExports = shim.exports && shim.exports.exports,
+                found, args, mod;
+
+                takeGlobalQueue();
+
+                while (defQueue.length) {
+                    args = defQueue.shift();
+                    if (args[0] === null) {
+                        args[0] = moduleName;
+                        //If already found an anonymous module and bound it
+                        //to this name, then this is some other anon module
+                        //waiting for its completeLoad to fire.
+                        if (found) {
+                            break;
+                        }
+                        found = true;
+                    } else if (args[0] === moduleName) {
+                        //Found matching define call for this script!
+                        found = true;
+                    }
+
+                    callGetModule(args);
+                }
+
+                //Do this after the cycle of callGetModule in case the result
+                //of those calls/init calls changes the registry.
+                mod = registry[moduleName];
+
+                if (!found &&
+                    !defined[moduleName] &&
+                    mod && !mod.inited) {
+                    if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
+                        if (hasPathFallback(moduleName)) {
+                            return;
+                        } else {
+                            return onError(makeError('nodefine',
+                                             'No define call for ' + moduleName,
+                                             null,
+                                             [moduleName]));
+                        }
+                    } else {
+                        //A script that does not call define(), so just simulate
+                        //the call for it.
+                        callGetModule([moduleName, (shim.deps || []), shim.exports]);
+                    }
+                }
+
+                checkLoaded();
+            },
+
+            /**
+             * Converts a module name + .extension into an URL path.
+             * *Requires* the use of a module name. It does not support using
+             * plain URLs like nameToUrl.
+             */
+            toUrl: function (moduleNamePlusExt, relModuleMap) {
+                var index = moduleNamePlusExt.lastIndexOf('.'),
+                    ext = null;
+
+                if (index !== -1) {
+                    ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
+                    moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
+                }
+
+                return context.nameToUrl(moduleNamePlusExt, ext, relModuleMap);
+            },
+
+            /**
+             * Converts a module name to a file path. Supports cases where
+             * moduleName may actually be just an URL.
+             */
+            nameToUrl: function (moduleName, ext, relModuleMap) {
+                var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
+                    parentPath;
+
+                //Normalize module name if have a base relative module name to work from.
+                moduleName = normalize(moduleName, relModuleMap && relModuleMap.id, true);
+
+                //If a colon is in the URL, it indicates a protocol is used and it is just
+                //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
+                //or ends with .js, then assume the user meant to use an url and not a module id.
+                //The slash is important for protocol-less URLs as well as full paths.
+                if (req.jsExtRegExp.test(moduleName)) {
+                    //Just a plain path, not module name lookup, so just return it.
+                    //Add extension if it is included. This is a bit wonky, only non-.js things pass
+                    //an extension, this method probably needs to be reworked.
+                    url = moduleName + (ext || '');
+                } else {
+                    //A module that needs to be converted to a path.
+                    paths = config.paths;
+                    pkgs = config.pkgs;
+
+                    syms = moduleName.split('/');
+                    //For each module name segment, see if there is a path
+                    //registered for it. Start with most specific name
+                    //and work up from it.
+                    for (i = syms.length; i > 0; i -= 1) {
+                        parentModule = syms.slice(0, i).join('/');
+                        pkg = pkgs[parentModule];
+                        parentPath = paths[parentModule];
+                        if (parentPath) {
+                            //If an array, it means there are a few choices,
+                            //Choose the one that is desired
+                            if (isArray(parentPath)) {
+                                parentPath = parentPath[0];
+                            }
+                            syms.splice(0, i, parentPath);
+                            break;
+                        } else if (pkg) {
+                            //If module name is just the package name, then looking
+                            //for the main module.
+                            if (moduleName === pkg.name) {
+                                pkgPath = pkg.location + '/' + pkg.main;
+                            } else {
+                                pkgPath = pkg.location;
+                            }
+                            syms.splice(0, i, pkgPath);
+                            break;
+                        }
+                    }
+
+                    //Join the path parts together, then figure out if baseUrl is needed.
+                    url = syms.join('/') + (ext || '.js')+'?random='+Math.random();
+                    url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
+                }
+
+                return config.urlArgs ? url +
+                                        ((url.indexOf('?') === -1 ? '?' : '&') +
+                                         config.urlArgs) : url;
+            },
+
+            //Delegates to req.load. Broken out as a separate function to
+            //allow overriding in the optimizer.
+            load: function (id, url) {
+                req.load(context, id, url);
+            },
+
+            /**
+             * Executes a module callack function. Broken out as a separate function
+             * solely to allow the build system to sequence the files in the built
+             * layer in the right sequence.
+             *
+             * @private
+             */
+            execCb: function (name, callback, args, exports) {
+                return callback.apply(exports, args);
+            },
+
+            /**
+             * callback for script loads, used to check status of loading.
+             *
+             * @param {Event} evt the event from the browser for the script
+             * that was loaded.
+             */
+            onScriptLoad: function (evt) {
+                //Using currentTarget instead of target for Firefox 2.0's sake. Not
+                //all old browsers will be supported, but this one was easy enough
+                //to support and still makes sense.
+                if (evt.type === 'load' ||
+                    (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
+                    //Reset interactive script so a script node is not held onto for
+                    //to long.
+                    interactiveScript = null;
+
+                    //Pull out the name of the module and the context.
+                    var data = getScriptData(evt);
+                    context.completeLoad(data.id);
+                }
+            },
+
+            /**
+             * Callback for script errors.
+             */
+            onScriptError: function (evt) {
+                var data = getScriptData(evt);
+                if (!hasPathFallback(data.id)) {
+                    return onError(makeError('scripterror', 'Script error', evt, [data.id]));
+                }
+            }
+        });
+    }
+
+    /**
+     * Main entry point.
+     *
+     * If the only argument to require is a string, then the module that
+     * is represented by that string is fetched for the appropriate context.
+     *
+     * If the first argument is an array, then it will be treated as an array
+     * of dependency string names to fetch. An optional function callback can
+     * be specified to execute when all of those dependencies are available.
+     *
+     * Make a local req variable to help Caja compliance (it assumes things
+     * on a require that are not standardized), and to give a short
+     * name for minification/local scope use.
+     */
+    req = requirejs = function (deps, callback, errback, optional) {
+
+        //Find the right context, use default
+        var contextName = defContextName,
+            context, config;
+
+        // Determine if have config object in the call.
+        if (!isArray(deps) && typeof deps !== 'string') {
+            // deps is a config object
+            config = deps;
+            if (isArray(callback)) {
+                // Adjust args if there are dependencies
+                deps = callback;
+                callback = errback;
+                errback = optional;
+            } else {
+                deps = [];
+            }
+        }
+
+        if (config && config.context) {
+            contextName = config.context;
+        }
+
+        context = contexts[contextName];
+        if (!context) {
+            context = contexts[contextName] = req.s.newContext(contextName);
+        }
+
+        if (config) {
+            context.configure(config);
+        }
+
+        return context.require(deps, callback, errback);
+    };
+
+    /**
+     * Support require.config() to make it easier to cooperate with other
+     * AMD loaders on globally agreed names.
+     */
+    req.config = function (config) {
+        return req(config);
+    };
+
+    /**
+     * Export require as a global, but only if it does not already exist.
+     */
+    if (!require) {
+        require = req;
+    }
+
+    req.version = version;
+
+    //Used to filter out dependencies that are already paths.
+    req.jsExtRegExp = /^\/|:|\?|\.js$/;
+    req.isBrowser = isBrowser;
+    s = req.s = {
+        contexts: contexts,
+        newContext: newContext
+    };
+
+    //Create default context.
+    req({});
+
+    //Exports some context-sensitive methods on global require, using
+    //default context if no context specified.
+    addRequireMethods(req);
+
+    if (isBrowser) {
+        head = s.head = document.getElementsByTagName('head')[0];
+        //If BASE tag is in play, using appendChild is a problem for IE6.
+        //When that browser dies, this can be removed. Details in this jQuery bug:
+        //http://dev.jquery.com/ticket/2709
+        baseElement = document.getElementsByTagName('base')[0];
+        if (baseElement) {
+            head = s.head = baseElement.parentNode;
+        }
+    }
+
+    /**
+     * Any errors that require explicitly generates will be passed to this
+     * function. Intercept/override it if you want custom error handling.
+     * @param {Error} err the error object.
+     */
+    req.onError = function (err) {
+        throw err;
+    };
+
+    /**
+     * Does the request to load a module for the browser case.
+     * Make this a separate function to allow other environments
+     * to override it.
+     *
+     * @param {Object} context the require context to find state.
+     * @param {String} moduleName the name of the module.
+     * @param {Object} url the URL to the module.
+     */
+    req.load = function (context, moduleName, url) {
+        var config = (context && context.config) || {},
+            node;
+        if (isBrowser) {
+            //In the browser so use a script tag
+            node = config.xhtml ?
+                   document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
+                   document.createElement('script');
+            node.type = config.scriptType || 'text/javascript';
+            node.charset = 'utf-8';
+
+            node.setAttribute('data-requirecontext', context.contextName);
+            node.setAttribute('data-requiremodule', moduleName);
+
+            //Set up load listener. Test attachEvent first because IE9 has
+            //a subtle issue in its addEventListener and script onload firings
+            //that do not match the behavior of all other browsers with
+            //addEventListener support, which fire the onload event for a
+            //script right after the script execution. See:
+            //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
+            //UNFORTUNATELY Opera implements attachEvent but does not follow the script
+            //script execution mode.
+            if (node.attachEvent &&
+                //Check if node.attachEvent is artificially added by custom script or
+                //natively supported by browser
+                //read https://github.com/jrburke/requirejs/issues/187
+                //if we can NOT find [native code] then it must NOT natively supported.
+                //in IE8, node.attachEvent does not have toString()
+                //Note the test for "[native code" with no closing brace, see:
+                //https://github.com/jrburke/requirejs/issues/273
+                !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
+                !isOpera) {
+                //Probably IE. IE (at least 6-8) do not fire
+                //script onload right after executing the script, so
+                //we cannot tie the anonymous define call to a name.
+                //However, IE reports the script as being in 'interactive'
+                //readyState at the time of the define call.
+                useInteractive = true;
+
+                node.attachEvent('onreadystatechange', context.onScriptLoad);
+                //It would be great to add an error handler here to catch
+                //404s in IE9+. However, onreadystatechange will fire before
+                //the error handler, so that does not help. If addEvenListener
+                //is used, then IE will fire error before load, but we cannot
+                //use that pathway given the connect.microsoft.com issue
+                //mentioned above about not doing the 'script execute,
+                //then fire the script load event listener before execute
+                //next script' that other browsers do.
+                //Best hope: IE10 fixes the issues,
+                //and then destroys all installs of IE 6-9.
+                //node.attachEvent('onerror', context.onScriptError);
+            } else {
+                node.addEventListener('load', context.onScriptLoad, false);
+                node.addEventListener('error', context.onScriptError, false);
+            }
+            node.src = url;
+
+            //For some cache cases in IE 6-8, the script executes before the end
+            //of the appendChild execution, so to tie an anonymous define
+            //call to the module name (which is stored on the node), hold on
+            //to a reference to this node, but clear after the DOM insertion.
+            currentlyAddingScript = node;
+            if (baseElement) {
+                head.insertBefore(node, baseElement);
+            } else {
+                head.appendChild(node);
+            }
+            currentlyAddingScript = null;
+
+            return node;
+        } else if (isWebWorker) {
+            //In a web worker, use importScripts. This is not a very
+            //efficient use of importScripts, importScripts will block until
+            //its script is downloaded and evaluated. However, if web workers
+            //are in play, the expectation that a build has been done so that
+            //only one script needs to be loaded anyway. This may need to be
+            //reevaluated if other use cases become common.
+            importScripts(url);
+
+            //Account for anonymous modules
+            context.completeLoad(moduleName);
+        }
+    };
+
+    function getInteractiveScript() {
+        if (interactiveScript && interactiveScript.readyState === 'interactive') {
+            return interactiveScript;
+        }
+
+        eachReverse(scripts(), function (script) {
+            if (script.readyState === 'interactive') {
+                return (interactiveScript = script);
+            }
+        });
+        return interactiveScript;
+    }
+
+    //Look for a data-main script attribute, which could also adjust the baseUrl.
+    if (isBrowser) {
+        //Figure out baseUrl. Get it from the script tag with require.js in it.
+        eachReverse(scripts(), function (script) {
+            //Set the 'head' where we can append children by
+            //using the script's parent.
+            if (!head) {
+                head = script.parentNode;
+            }
+
+            //Look for a data-main attribute to set main script for the page
+            //to load. If it is there, the path to data main becomes the
+            //baseUrl, if it is not already set.
+            dataMain = script.getAttribute('data-main');
+            if (dataMain) {
+
+                //Pull off the directory of data-main for use as the
+                //baseUrl.
+                src = dataMain.split('/');
+                mainScript = src.pop();
+                subPath = src.length ? src.join('/')  + '/' : './';
+
+                //Set final baseUrl if there is not already an explicit one.
+                if (!cfg.baseUrl) {
+                    cfg.baseUrl = subPath;
+                }
+
+                //Strip off any trailing .js since dataMain is now
+                //like a module name.
+                dataMain = mainScript.replace(jsSuffixRegExp, '');
+
+                //Put the data-main script in the files to load.
+                cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
+
+                return true;
+            }
+        });
+    }
+
+    /**
+     * The function that handles definitions of modules. Differs from
+     * require() in that a string for the module should be the first argument,
+     * and the function to execute after dependencies are loaded should
+     * return a value to define the module corresponding to the first argument's
+     * name.
+     */
+    define = function (name, deps, callback) {
+        var node, context;
+
+        //Allow for anonymous functions
+        if (typeof name !== 'string') {
+            //Adjust args appropriately
+            callback = deps;
+            deps = name;
+            name = null;
+        }
+
+        //This module may not have dependencies
+        if (!isArray(deps)) {
+            callback = deps;
+            deps = [];
+        }
+
+        //If no name, and callback is a function, then figure out if it a
+        //CommonJS thing with dependencies.
+        if (!deps.length && isFunction(callback)) {
+            //Remove comments from the callback string,
+            //look for require calls, and pull them into the dependencies,
+            //but only if there are function args.
+            if (callback.length) {
+                callback
+                    .toString()
+                    .replace(commentRegExp, '')
+                    .replace(cjsRequireRegExp, function (match, dep) {
+                        deps.push(dep);
+                    });
+
+                //May be a CommonJS thing even without require calls, but still
+                //could use exports, and module. Avoid doing exports and module
+                //work though if it just needs require.
+                //REQUIRES the function to expect the CommonJS variables in the
+                //order listed below.
+                deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
+            }
+        }
+
+        //If in IE 6-8 and hit an anonymous define() call, do the interactive
+        //work.
+        if (useInteractive) {
+            node = currentlyAddingScript || getInteractiveScript();
+            if (node) {
+                if (!name) {
+                    name = node.getAttribute('data-requiremodule');
+                }
+                context = contexts[node.getAttribute('data-requirecontext')];
+            }
+        }
+
+        //Always save off evaluating the def call until the script onload handler.
+        //This allows multiple modules to be in a file without prematurely
+        //tracing dependencies, and allows for anonymous module support,
+        //where the module name is not known until the script onload event
+        //occurs. If no context, use the global queue, and get it processed
+        //in the onscript load callback.
+        (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
+    };
+
+    define.amd = {
+        jQuery: true
+    };
+
+
+    /**
+     * Executes the text. Normally just uses eval, but can be modified
+     * to use a better, environment-specific call. Only used for transpiling
+     * loader plugins, not for plain JS modules.
+     * @param {String} text the text to execute/evaluate.
+     */
+    req.exec = function (text) {
+        /*jslint evil: true */
+        return eval(text);
+    };
+
+    //Set up with config info.
+    req(cfg);
+}(this));
+/*
+ * jQuery JavaScript Library
+ * http://jquery.com/
+ *
+ * Copyright, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: NULL
+ */
+(function( window, undefined ) {
+
+// Use the correct document accordingly with window argument (sandbox)
+var document = window.document,
+	navigator = window.navigator,
+	location = window.location;
+var jQuery = (function() {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+		// The jQuery object is actually just the init constructor 'enhanced'
+		return new jQuery.fn.init( selector, context, rootjQuery );
+	},
+
+	// Map over jQuery in case of overwrite
+	_jQuery = window.jQuery,
+
+	// Map over the $ in case of overwrite
+	_$ = window.$,
+
+	// A central reference to the root jQuery(document)
+	rootjQuery,
+
+	// A simple way to check for HTML strings or ID strings
+	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+	quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+	// Check if a string has a non-whitespace character in it
+	rnotwhite = /\S/,
+
+	// Used for trimming whitespace
+	trimLeft = /^\s+/,
+	trimRight = /\s+$/,
+
+	// Match a standalone tag
+	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+	// JSON RegExp
+	rvalidchars = /^[\],:{}\s]*$/,
+	rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+	rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+	// Useragent RegExp
+	rwebkit = /(webkit)[ \/]([\w.]+)/,
+	ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+	rmsie = /(msie) ([\w.]+)/,
+	rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
+	// Matches dashed string for camelizing
+	rdashAlpha = /-([a-z]|[0-9])/ig,
+	rmsPrefix = /^-ms-/,
+
+	// Used by jQuery.camelCase as callback to replace()
+	fcamelCase = function( all, letter ) {
+		return ( letter + "" ).toUpperCase();
+	},
+
+	// Keep a UserAgent string for use with jQuery.browser
+	userAgent = navigator.userAgent,
+
+	// For matching the engine and version of the browser
+	browserMatch,
+
+	// The deferred used on DOM ready
+	readyList,
+
+	// The ready event handler
+	DOMContentLoaded,
+
+	// Save a reference to some core methods
+	toString = Object.prototype.toString,
+	hasOwn = Object.prototype.hasOwnProperty,
+	push = Array.prototype.push,
+	slice = Array.prototype.slice,
+	trim = String.prototype.trim,
+	indexOf = Array.prototype.indexOf,
+
+	// [[Class]] -> type pairs
+	class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+	constructor: jQuery,
+	init: function( selector, context, rootjQuery ) {
+		var match, elem, ret, doc;
+
+		// Handle $(""), $(null), or $(undefined)
+		if ( !selector ) {
+			return this;
+		}
+
+		// Handle $(DOMElement)
+		if ( selector.nodeType ) {
+			this.context = this[0] = selector;
+			this.length = 1;
+			return this;
+		}
+
+		// The body element only exists once, optimize finding it
+		if ( selector === "body" && !context && document.body ) {
+			this.context = document;
+			this[0] = document.body;
+			this.selector = selector;
+			this.length = 1;
+			return this;
+		}
+
+		// Handle HTML strings
+		if ( typeof selector === "string" ) {
+			// Are we dealing with HTML string or an ID?
+			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+				// Assume that strings that start and end with <> are HTML and skip the regex check
+				match = [ null, selector, null ];
+
+			} else {
+				match = quickExpr.exec( selector );
+			}
+
+			// Verify a match, and that no context was specified for #id
+			if ( match && (match[1] || !context) ) {
+
+				// HANDLE: $(html) -> $(array)
+				if ( match[1] ) {
+					context = context instanceof jQuery ? context[0] : context;
+					doc = ( context ? context.ownerDocument || context : document );
+
+					// If a single string is passed in and it's a single tag
+					// just do a createElement and skip the rest
+					ret = rsingleTag.exec( selector );
+
+					if ( ret ) {
+						if ( jQuery.isPlainObject( context ) ) {
+							selector = [ document.createElement( ret[1] ) ];
+							jQuery.fn.attr.call( selector, context, true );
+
+						} else {
+							selector = [ doc.createElement( ret[1] ) ];
+						}
+
+					} else {
+						ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+						selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
+					}
+
+					return jQuery.merge( this, selector );
+
+				// HANDLE: $("#id")
+				} else {
+					elem = document.getElementById( match[2] );
+
+					// Check parentNode to catch when Blackberry 4.6 returns
+					// nodes that are no longer in the document #6963
+					if ( elem && elem.parentNode ) {
+						// Handle the case where IE and Opera return items
+						// by name instead of ID
+						if ( elem.id !== match[2] ) {
+							return rootjQuery.find( selector );
+						}
+
+						// Otherwise, we inject the element directly into the jQuery object
+						this.length = 1;
+						this[0] = elem;
+					}
+
+					this.context = document;
+					this.selector = selector;
+					return this;
+				}
+
+			// HANDLE: $(expr, $(...))
+			} else if ( !context || context.jquery ) {
+				return ( context || rootjQuery ).find( selector );
+
+			// HANDLE: $(expr, context)
+			// (which is just equivalent to: $(context).find(expr)
+			} else {
+				return this.constructor( context ).find( selector );
+			}
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) ) {
+			return rootjQuery.ready( selector );
+		}
+
+		if ( selector.selector !== undefined ) {
+			this.selector = selector.selector;
+			this.context = selector.context;
+		}
+
+		return jQuery.makeArray( selector, this );
+	},
+
+	// Start with an empty selector
+	selector: "",
+
+	// The current version of jQuery being used
+	jquery: "",
+
+	// The default length of a jQuery object is 0
+	length: 0,
+
+	// The number of elements contained in the matched element set
+	size: function() {
+		return this.length;
+	},
+
+	toArray: function() {
+		return slice.call( this, 0 );
+	},
+
+	// Get the Nth element in the matched element set OR
+	// Get the whole matched element set as a clean array
+	get: function( num ) {
+		return num == null ?
+
+			// Return a 'clean' array
+			this.toArray() :
+
+			// Return just the object
+			( num < 0 ? this[ this.length + num ] : this[ num ] );
+	},
+
+	// Take an array of elements and push it onto the stack
+	// (returning the new matched element set)
+	pushStack: function( elems, name, selector ) {
+		// Build a new jQuery matched element set
+		var ret = this.constructor();
+
+		if ( jQuery.isArray( elems ) ) {
+			push.apply( ret, elems );
+
+		} else {
+			jQuery.merge( ret, elems );
+		}
+
+		// Add the old object onto the stack (as a reference)
+		ret.prevObject = this;
+
+		ret.context = this.context;
+
+		if ( name === "find" ) {
+			ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
+		} else if ( name ) {
+			ret.selector = this.selector + "." + name + "(" + selector + ")";
+		}
+
+		// Return the newly-formed element set
+		return ret;
+	},
+
+	// Execute a callback for every element in the matched set.
+	// (You can seed the arguments with an array of args, but this is
+	// only used internally.)
+	each: function( callback, args ) {
+		return jQuery.each( this, callback, args );
+	},
+
+	ready: function( fn ) {
+		// Attach the listeners
+		jQuery.bindReady();
+
+		// Add the callback
+		readyList.add( fn );
+
+		return this;
+	},
+
+	eq: function( i ) {
+		i = +i;
+		return i === -1 ?
+			this.slice( i ) :
+			this.slice( i, i + 1 );
+	},
+
+	first: function() {
+		return this.eq( 0 );
+	},
+
+	last: function() {
+		return this.eq( -1 );
+	},
+
+	slice: function() {
+		return this.pushStack( slice.apply( this, arguments ),
+			"slice", slice.call(arguments).join(",") );
+	},
+
+	map: function( callback ) {
+		return this.pushStack( jQuery.map(this, function( elem, i ) {
+			return callback.call( elem, i, elem );
+		}));
+	},
+
+	end: function() {
+		return this.prevObject || this.constructor(null);
+	},
+
+	// For internal use only.
+	// Behaves like an Array's method, not like a jQuery method.
+	push: push,
+	sort: [].sort,
+	splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+	var options, name, src, copy, copyIsArray, clone,
+		target = arguments[0] || {},
+		i = 1,
+		length = arguments.length,
+		deep = false;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+		target = arguments[1] || {};
+		// skip the boolean and the target
+		i = 2;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+		target = {};
+	}
+
+	// extend jQuery itself if only one argument is passed
+	if ( length === i ) {
+		target = this;
+		--i;
+	}
+
+	for ( ; i < length; i++ ) {
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null ) {
+			// Extend the base object
+			for ( name in options ) {
+				src = target[ name ];
+				copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy ) {
+					continue;
+				}
+
+				// Recurse if we're merging plain objects or arrays
+				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+					if ( copyIsArray ) {
+						copyIsArray = false;
+						clone = src && jQuery.isArray(src) ? src : [];
+
+					} else {
+						clone = src && jQuery.isPlainObject(src) ? src : {};
+					}
+
+					// Never move original objects, clone them
+					target[ name ] = jQuery.extend( deep, clone, copy );
+
+				// Don't bring in undefined values
+				} else if ( copy !== undefined ) {
+					target[ name ] = copy;
+				}
+			}
+		}
+	}
+
+	// Return the modified object
+	return target;
+};
+
+jQuery.extend({
+	noConflict: function( deep ) {
+		if ( window.$ === jQuery ) {
+			window.$ = _$;
+		}
+
+		if ( deep && window.jQuery === jQuery ) {
+			window.jQuery = _jQuery;
+		}
+
+		return jQuery;
+	},
+
+	// Is the DOM ready to be used? Set to true once it occurs.
+	isReady: false,
+
+	// A counter to track how many items to wait for before
+	// the ready event fires. See #6781
+	readyWait: 1,
+
+	// Hold (or release) the ready event
+	holdReady: function( hold ) {
+		if ( hold ) {
+			jQuery.readyWait++;
+		} else {
+			jQuery.ready( true );
+		}
+	},
+
+	// Handle when the DOM is ready
+	ready: function( wait ) {
+		// Either a released hold or an DOMready/load event and not yet ready
+		if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
+			// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+			if ( !document.body ) {
+				return setTimeout( jQuery.ready, 1 );
+			}
+
+			// Remember that the DOM is ready
+			jQuery.isReady = true;
+
+			// If a normal DOM Ready event fired, decrement, and wait if need be
+			if ( wait !== true && --jQuery.readyWait > 0 ) {
+				return;
+			}
+
+			// If there are functions bound, to execute
+			readyList.fireWith( document, [ jQuery ] );
+
+			// Trigger any bound ready events
+			if ( jQuery.fn.trigger ) {
+				jQuery( document ).trigger( "ready" ).off( "ready" );
+			}
+		}
+	},
+
+	bindReady: function() {
+		if ( readyList ) {
+			return;
+		}
+
+		readyList = jQuery.Callbacks( "once memory" );
+
+		// Catch cases where $(document).ready() is called after the
+		// browser event has already occurred.
+		if ( document.readyState === "complete" ) {
+			// Handle it asynchronously to allow scripts the opportunity to delay ready
+			return setTimeout( jQuery.ready, 1 );
+		}
+
+		// Mozilla, Opera and webkit nightlies currently support this event
+		if ( document.addEventListener ) {
+			// Use the handy event callback
+			document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+			// A fallback to window.onload, that will always work
+			window.addEventListener( "load", jQuery.ready, false );
+
+		// If IE event model is used
+		} else if ( document.attachEvent ) {
+			// ensure firing before onload,
+			// maybe late but safe also for iframes
+			document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+			// A fallback to window.onload, that will always work
+			window.attachEvent( "onload", jQuery.ready );
+
+			// If IE and not a frame
+			// continually check to see if the document is ready
+			var toplevel = false;
+
+			try {
+				toplevel = window.frameElement == null;
+			} catch(e) {}
+
+			if ( document.documentElement.doScroll && toplevel ) {
+				doScrollCheck();
+			}
+		}
+	},
+
+	// See test/unit/core.js for details concerning isFunction.
+	// Since version 1.3, DOM methods and functions like alert
+	// aren't supported. They return false on IE (#2968).
+	isFunction: function( obj ) {
+		return jQuery.type(obj) === "function";
+	},
+
+	isArray: Array.isArray || function( obj ) {
+		return jQuery.type(obj) === "array";
+	},
+
+	isWindow: function( obj ) {
+		return obj != null && obj == obj.window;
+	},
+
+	isNumeric: function( obj ) {
+		return !isNaN( parseFloat(obj) ) && isFinite( obj );
+	},
+
+	type: function( obj ) {
+		return obj == null ?
+			String( obj ) :
+			class2type[ toString.call(obj) ] || "object";
+	},
+
+	isPlainObject: function( obj ) {
+		// Must be an Object.
+		// Because of IE, we also have to check the presence of the constructor property.
+		// Make sure that DOM nodes and window objects don't pass through, as well
+		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+			return false;
+		}
+
+		try {
+			// Not own constructor property must be Object
+			if ( obj.constructor &&
+				!hasOwn.call(obj, "constructor") &&
+				!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+				return false;
+			}
+		} catch ( e ) {
+			// IE8,9 Will throw exceptions on certain host objects #9897
+			return false;
+		}
+
+		// Own properties are enumerated firstly, so to speed up,
+		// if last one is own, then all properties are own.
+
+		var key;
+		for ( key in obj ) {}
+
+		return key === undefined || hasOwn.call( obj, key );
+	},
+
+	isEmptyObject: function( obj ) {
+		for ( var name in obj ) {
+			return false;
+		}
+		return true;
+	},
+
+	error: function( msg ) {
+		throw new Error( msg );
+	},
+
+	parseJSON: function( data ) {
+		if ( typeof data !== "string" || !data ) {
+			return null;
+		}
+
+		// Make sure leading/trailing whitespace is removed (IE can't handle it)
+		data = jQuery.trim( data );
+
+		// Attempt to parse using the native JSON parser first
+		if ( window.JSON && window.JSON.parse ) {
+			return window.JSON.parse( data );
+		}
+
+		// Make sure the incoming data is actual JSON
+		// Logic borrowed from http://json.org/json2.js
+		if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+			.replace( rvalidtokens, "]" )
+			.replace( rvalidbraces, "")) ) {
+
+			return ( new Function( "return " + data ) )();
+
+		}
+		jQuery.error( "Invalid JSON: " + data );
+	},
+
+	// Cross-browser xml parsing
+	parseXML: function( data ) {
+		if ( typeof data !== "string" || !data ) {
+			return null;
+		}
+		var xml, tmp;
+		try {
+			if ( window.DOMParser ) { // Standard
+				tmp = new DOMParser();
+				xml = tmp.parseFromString( data , "text/xml" );
+			} else { // IE
+				xml = new ActiveXObject( "Microsoft.XMLDOM" );
+				xml.async = "false";
+				xml.loadXML( data );
+			}
+		} catch( e ) {
+			xml = undefined;
+		}
+		if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+			jQuery.error( "Invalid XML: " + data );
+		}
+		return xml;
+	},
+
+	noop: function() {},
+
+	// Evaluates a script in a global context
+	// Workarounds based on findings by Jim Driscoll
+	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+	globalEval: function( data ) {
+		if ( data && rnotwhite.test( data ) ) {
+			// We use execScript on Internet Explorer
+			// We use an anonymous function so that context is window
+			// rather than jQuery in Firefox
+			( window.execScript || function( data ) {
+				window[ "eval" ].call( window, data );
+			} )( data );
+		}
+	},
+
+	// Convert dashed to camelCase; used by the css and data modules
+	// Microsoft forgot to hump their vendor prefix (#9572)
+	camelCase: function( string ) {
+		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+	},
+
+	nodeName: function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+	},
+
+	// args is for internal usage only
+	each: function( object, callback, args ) {
+		var name, i = 0,
+			length = object.length,
+			isObj = length === undefined || jQuery.isFunction( object );
+
+		if ( args ) {
+			if ( isObj ) {
+				for ( name in object ) {
+					if ( callback.apply( object[ name ], args ) === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( ; i < length; ) {
+					if ( callback.apply( object[ i++ ], args ) === false ) {
+						break;
+					}
+				}
+			}
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( isObj ) {
+				for ( name in object ) {
+					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+						break;
+					}
+				}
+			} else {
+				for ( ; i < length; ) {
+					if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
+						break;
+					}
+				}
+			}
+		}
+
+		return object;
+	},
+
+	// Use native String.trim function wherever possible
+	trim: trim ?
+		function( text ) {
+			return text == null ?
+				"" :
+				trim.call( text );
+		} :
+
+		// Otherwise use our own trimming functionality
+		function( text ) {
+			return text == null ?
+				"" :
+				text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+		},
+
+	// results is for internal usage only
+	makeArray: function( array, results ) {
+		var ret = results || [];
+
+		if ( array != null ) {
+			// The window, strings (and functions) also have 'length'
+			// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+			var type = jQuery.type( array );
+
+			if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
+				push.call( ret, array );
+			} else {
+				jQuery.merge( ret, array );
+			}
+		}
+
+		return ret;
+	},
+
+	inArray: function( elem, array, i ) {
+		var len;
+
+		if ( array ) {
+			if ( indexOf ) {
+				return indexOf.call( array, elem, i );
+			}
+
+			len = array.length;
+			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+			for ( ; i < len; i++ ) {
+				// Skip accessing in sparse arrays
+				if ( i in array && array[ i ] === elem ) {
+					return i;
+				}
+			}
+		}
+
+		return -1;
+	},
+
+	merge: function( first, second ) {
+		var i = first.length,
+			j = 0;
+
+		if ( typeof second.length === "number" ) {
+			for ( var l = second.length; j < l; j++ ) {
+				first[ i++ ] = second[ j ];
+			}
+
+		} else {
+			while ( second[j] !== undefined ) {
+				first[ i++ ] = second[ j++ ];
+			}
+		}
+
+		first.length = i;
+
+		return first;
+	},
+
+	grep: function( elems, callback, inv ) {
+		var ret = [], retVal;
+		inv = !!inv;
+
+		// Go through the array, only saving the items
+		// that pass the validator function
+		for ( var i = 0, length = elems.length; i < length; i++ ) {
+			retVal = !!callback( elems[ i ], i );
+			if ( inv !== retVal ) {
+				ret.push( elems[ i ] );
+			}
+		}
+
+		return ret;
+	},
+
+	// arg is for internal usage only
+	map: function( elems, callback, arg ) {
+		var value, key, ret = [],
+			i = 0,
+			length = elems.length,
+			// jquery objects are treated as arrays
+			isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+		// Go through the array, translating each of the items to their
+		if ( isArray ) {
+			for ( ; i < length; i++ ) {
+				value = callback( elems[ i ], i, arg );
+
+				if ( value != null ) {
+					ret[ ret.length ] = value;
+				}
+			}
+
+		// Go through every key on the object,
+		} else {
+			for ( key in elems ) {
+				value = callback( elems[ key ], key, arg );
+
+				if ( value != null ) {
+					ret[ ret.length ] = value;
+				}
+			}
+		}
+
+		// Flatten any nested arrays
+		return ret.concat.apply( [], ret );
+	},
+
+	// A global GUID counter for objects
+	guid: 1,
+
+	// Bind a function to a context, optionally partially applying any
+	// arguments.
+	proxy: function( fn, context ) {
+		if ( typeof context === "string" ) {
+			var tmp = fn[ context ];
+			context = fn;
+			fn = tmp;
+		}
+
+		// Quick check to determine if target is callable, in the spec
+		// this throws a TypeError, but we will just return undefined.
+		if ( !jQuery.isFunction( fn ) ) {
+			return undefined;
+		}
+
+		// Simulated bind
+		var args = slice.call( arguments, 2 ),
+			proxy = function() {
+				return fn.apply( context, args.concat( slice.call( arguments ) ) );
+			};
+
+		// Set the guid of unique handler to the same of original handler, so it can be removed
+		proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+
+		return proxy;
+	},
+
+	// Mutifunctional method to get and set values to a collection
+	// The value/s can optionally be executed if it's a function
+	access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
+		var exec,
+			bulk = key == null,
+			i = 0,
+			length = elems.length;
+
+		// Sets many values
+		if ( key && typeof key === "object" ) {
+			for ( i in key ) {
+				jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
+			}
+			chainable = 1;
+
+		// Sets one value
+		} else if ( value !== undefined ) {
+			// Optionally, function values get executed if exec is true
+			exec = pass === undefined && jQuery.isFunction( value );
+
+			if ( bulk ) {
+				// Bulk operations only iterate when executing function values
+				if ( exec ) {
+					exec = fn;
+					fn = function( elem, key, value ) {
+						return exec.call( jQuery( elem ), value );
+					};
+
+				// Otherwise they run against the entire set
+				} else {
+					fn.call( elems, value );
+					fn = null;
+				}
+			}
+
+			if ( fn ) {
+				for (; i < length; i++ ) {
+					fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+				}
+			}
+
+			chainable = 1;
+		}
+
+		return chainable ?
+			elems :
+
+			// Gets
+			bulk ?
+				fn.call( elems ) :
+				length ? fn( elems[0], key ) : emptyGet;
+	},
+
+	now: function() {
+		return ( new Date() ).getTime();
+	},
+
+	// Use of jQuery.browser is frowned upon.
+	// More details: http://docs.jquery.com/Utilities/jQuery.browser
+	uaMatch: function( ua ) {
+		ua = ua.toLowerCase();
+
+		var match = rwebkit.exec( ua ) ||
+			ropera.exec( ua ) ||
+			rmsie.exec( ua ) ||
+			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+			[];
+
+		return { browser: match[1] || "", version: match[2] || "0" };
+	},
+
+	sub: function() {
+		function jQuerySub( selector, context ) {
+			return new jQuerySub.fn.init( selector, context );
+		}
+		jQuery.extend( true, jQuerySub, this );
+		jQuerySub.superclass = this;
+		jQuerySub.fn = jQuerySub.prototype = this();
+		jQuerySub.fn.constructor = jQuerySub;
+		jQuerySub.sub = this.sub;
+		jQuerySub.fn.init = function init( selector, context ) {
+			if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+				context = jQuerySub( context );
+			}
+
+			return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+		};
+		jQuerySub.fn.init.prototype = jQuerySub.fn;
+		var rootjQuerySub = jQuerySub(document);
+		return jQuerySub;
+	},
+
+	browser: {}
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+	class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+	jQuery.browser[ browserMatch.browser ] = true;
+	jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+	jQuery.browser.safari = true;
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+	trimLeft = /^[\s\xA0]+/;
+	trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+	DOMContentLoaded = function() {
+		document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+		jQuery.ready();
+	};
+
+} else if ( document.attachEvent ) {
+	DOMContentLoaded = function() {
+		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+		if ( document.readyState === "complete" ) {
+			document.detachEvent( "onreadystatechange", DOMContentLoaded );
+			jQuery.ready();
+		}
+	};
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+	if ( jQuery.isReady ) {
+		return;
+	}
+
+	try {
+		// If IE is used, use the trick by Diego Perini
+		// http://javascript.nwbox.com/IEContentLoaded/
+		document.documentElement.doScroll("left");
+	} catch(e) {
+		setTimeout( doScrollCheck, 1 );
+		return;
+	}
+
+	// and execute any waiting functions
+	jQuery.ready();
+}
+
+return jQuery;
+
+})();
+
+
+// String to Object flags format cache
+var flagsCache = {};
+
+// Convert String-formatted flags into Object-formatted ones and store in cache
+function createFlags( flags ) {
+	var object = flagsCache[ flags ] = {},
+		i, length;
+	flags = flags.split( /\s+/ );
+	for ( i = 0, length = flags.length; i < length; i++ ) {
+		object[ flags[i] ] = true;
+	}
+	return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *	flags:	an optional list of space-separated flags that will change how
+ *			the callback list behaves
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible flags:
+ *
+ *	once:			will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *	memory:			will keep track of previous values and will call any callback added
+ *					after the list has been fired right away with the latest "memorized"
+ *					values (like a Deferred)
+ *
+ *	unique:			will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *	stopOnFalse:	interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( flags ) {
+
+	// Convert flags from String-formatted to Object-formatted
+	// (we check in cache first)
+	flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
+
+	var // Actual callback list
+		list = [],
+		// Stack of fire calls for repeatable lists
+		stack = [],
+		// Last fire value (for non-forgettable lists)
+		memory,
+		// Flag to know if list was already fired
+		fired,
+		// Flag to know if list is currently firing
+		firing,
+		// First callback to fire (used internally by add and fireWith)
+		firingStart,
+		// End of the loop when firing
+		firingLength,
+		// Index of currently firing callback (modified by remove if needed)
+		firingIndex,
+		// Add one or several callbacks to the list
+		add = function( args ) {
+			var i,
+				length,
+				elem,
+				type,
+				actual;
+			for ( i = 0, length = args.length; i < length; i++ ) {
+				elem = args[ i ];
+				type = jQuery.type( elem );
+				if ( type === "array" ) {
+					// Inspect recursively
+					add( elem );
+				} else if ( type === "function" ) {
+					// Add if not in unique mode and callback is not in
+					if ( !flags.unique || !self.has( elem ) ) {
+						list.push( elem );
+					}
+				}
+			}
+		},
+		// Fire callbacks
+		fire = function( context, args ) {
+			args = args || [];
+			memory = !flags.memory || [ context, args ];
+			fired = true;
+			firing = true;
+			firingIndex = firingStart || 0;
+			firingStart = 0;
+			firingLength = list.length;
+			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+				if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
+					memory = true; // Mark as halted
+					break;
+				}
+			}
+			firing = false;
+			if ( list ) {
+				if ( !flags.once ) {
+					if ( stack && stack.length ) {
+						memory = stack.shift();
+						self.fireWith( memory[ 0 ], memory[ 1 ] );
+					}
+				} else if ( memory === true ) {
+					self.disable();
+				} else {
+					list = [];
+				}
+			}
+		},
+		// Actual Callbacks object
+		self = {
+			// Add a callback or a collection of callbacks to the list
+			add: function() {
+				if ( list ) {
+					var length = list.length;
+					add( arguments );
+					// Do we need to add the callbacks to the
+					// current firing batch?
+					if ( firing ) {
+						firingLength = list.length;
+					// With memory, if we're not firing then
+					// we should call right away, unless previous
+					// firing was halted (stopOnFalse)
+					} else if ( memory && memory !== true ) {
+						firingStart = length;
+						fire( memory[ 0 ], memory[ 1 ] );
+					}
+				}
+				return this;
+			},
+			// Remove a callback from the list
+			remove: function() {
+				if ( list ) {
+					var args = arguments,
+						argIndex = 0,
+						argLength = args.length;
+					for ( ; argIndex < argLength ; argIndex++ ) {
+						for ( var i = 0; i < list.length; i++ ) {
+							if ( args[ argIndex ] === list[ i ] ) {
+								// Handle firingIndex and firingLength
+								if ( firing ) {
+									if ( i <= firingLength ) {
+										firingLength--;
+										if ( i <= firingIndex ) {
+											firingIndex--;
+										}
+									}
+								}
+								// Remove the element
+								list.splice( i--, 1 );
+								// If we have some unicity property then
+								// we only need to do this once
+								if ( flags.unique ) {
+									break;
+								}
+							}
+						}
+					}
+				}
+				return this;
+			},
+			// Control if a given callback is in the list
+			has: function( fn ) {
+				if ( list ) {
+					var i = 0,
+						length = list.length;
+					for ( ; i < length; i++ ) {
+						if ( fn === list[ i ] ) {
+							return true;
+						}
+					}
+				}
+				return false;
+			},
+			// Remove all callbacks from the list
+			empty: function() {
+				list = [];
+				return this;
+			},
+			// Have the list do nothing anymore
+			disable: function() {
+				list = stack = memory = undefined;
+				return this;
+			},
+			// Is it disabled?
+			disabled: function() {
+				return !list;
+			},
+			// Lock the list in its current state
+			lock: function() {
+				stack = undefined;
+				if ( !memory || memory === true ) {
+					self.disable();
+				}
+				return this;
+			},
+			// Is it locked?
+			locked: function() {
+				return !stack;
+			},
+			// Call all callbacks with the given context and arguments
+			fireWith: function( context, args ) {
+				if ( stack ) {
+					if ( firing ) {
+						if ( !flags.once ) {
+							stack.push( [ context, args ] );
+						}
+					} else if ( !( flags.once && memory ) ) {
+						fire( context, args );
+					}
+				}
+				return this;
+			},
+			// Call all the callbacks with the given arguments
+			fire: function() {
+				self.fireWith( this, arguments );
+				return this;
+			},
+			// To know if the callbacks have already been called at least once
+			fired: function() {
+				return !!fired;
+			}
+		};
+
+	return self;
+};
+
+
+
+
+var // Static reference to slice
+	sliceDeferred = [].slice;
+
+jQuery.extend({
+
+	Deferred: function( func ) {
+		var doneList = jQuery.Callbacks( "once memory" ),
+			failList = jQuery.Callbacks( "once memory" ),
+			progressList = jQuery.Callbacks( "memory" ),
+			state = "pending",
+			lists = {
+				resolve: doneList,
+				reject: failList,
+				notify: progressList
+			},
+			promise = {
+				done: doneList.add,
+				fail: failList.add,
+				progress: progressList.add,
+
+				state: function() {
+					return state;
+				},
+
+				// Deprecated
+				isResolved: doneList.fired,
+				isRejected: failList.fired,
+
+				then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
+					deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
+					return this;
+				},
+				always: function() {
+					deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
+					return this;
+				},
+				pipe: function( fnDone, fnFail, fnProgress ) {
+					return jQuery.Deferred(function( newDefer ) {
+						jQuery.each( {
+							done: [ fnDone, "resolve" ],
+							fail: [ fnFail, "reject" ],
+							progress: [ fnProgress, "notify" ]
+						}, function( handler, data ) {
+							var fn = data[ 0 ],
+								action = data[ 1 ],
+								returned;
+							if ( jQuery.isFunction( fn ) ) {
+								deferred[ handler ](function() {
+									returned = fn.apply( this, arguments );
+									if ( returned && jQuery.isFunction( returned.promise ) ) {
+										returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
+									} else {
+										newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+									}
+								});
+							} else {
+								deferred[ handler ]( newDefer[ action ] );
+							}
+						});
+					}).promise();
+				},
+				// Get a promise for this deferred
+				// If obj is provided, the promise aspect is added to the object
+				promise: function( obj ) {
+					if ( obj == null ) {
+						obj = promise;
+					} else {
+						for ( var key in promise ) {
+							obj[ key ] = promise[ key ];
+						}
+					}
+					return obj;
+				}
+			},
+			deferred = promise.promise({}),
+			key;
+
+		for ( key in lists ) {
+			deferred[ key ] = lists[ key ].fire;
+			deferred[ key + "With" ] = lists[ key ].fireWith;
+		}
+
+		// Handle state
+		deferred.done( function() {
+			state = "resolved";
+		}, failList.disable, progressList.lock ).fail( function() {
+			state = "rejected";
+		}, doneList.disable, progressList.lock );
+
+		// Call given func if any
+		if ( func ) {
+			func.call( deferred, deferred );
+		}
+
+		// All done!
+		return deferred;
+	},
+
+	// Deferred helper
+	when: function( firstParam ) {
+		var args = sliceDeferred.call( arguments, 0 ),
+			i = 0,
+			length = args.length,
+			pValues = new Array( length ),
+			count = length,
+			pCount = length,
+			deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+				firstParam :
+				jQuery.Deferred(),
+			promise = deferred.promise();
+		function resolveFunc( i ) {
+			return function( value ) {
+				args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+				if ( !( --count ) ) {
+					deferred.resolveWith( deferred, args );
+				}
+			};
+		}
+		function progressFunc( i ) {
+			return function( value ) {
+				pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+				deferred.notifyWith( promise, pValues );
+			};
+		}
+		if ( length > 1 ) {
+			for ( ; i < length; i++ ) {
+				if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
+					args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
+				} else {
+					--count;
+				}
+			}
+			if ( !count ) {
+				deferred.resolveWith( deferred, args );
+			}
+		} else if ( deferred !== firstParam ) {
+			deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+		}
+		return promise;
+	}
+});
+
+
+
+
+jQuery.support = (function() {
+
+	var support,
+		all,
+		a,
+		select,
+		opt,
+		input,
+		fragment,
+		tds,
+		events,
+		eventName,
+		i,
+		isSupported,
+		div = document.createElement( "div" ),
+		documentElement = document.documentElement;
+
+	// Preliminary tests
+	div.setAttribute("className", "t");
+	div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+	all = div.getElementsByTagName( "*" );
+	a = div.getElementsByTagName( "a" )[ 0 ];
+
+	// Can't get basic test support
+	if ( !all || !all.length || !a ) {
+		return {};
+	}
+
+	// First batch of supports tests
+	select = document.createElement( "select" );
+	opt = select.appendChild( document.createElement("option") );
+	input = div.getElementsByTagName( "input" )[ 0 ];
+
+	support = {
+		// IE strips leading whitespace when .innerHTML is used
+		leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+		// Make sure that tbody elements aren't automatically inserted
+		// IE will insert them into empty tables
+		tbody: !div.getElementsByTagName("tbody").length,
+
+		// Make sure that link elements get serialized correctly by innerHTML
+		// This requires a wrapper element in IE
+		htmlSerialize: !!div.getElementsByTagName("link").length,
+
+		// Get the style information from getAttribute
+		// (IE uses .cssText instead)
+		style: /top/.test( a.getAttribute("style") ),
+
+		// Make sure that URLs aren't manipulated
+		// (IE normalizes it by default)
+		hrefNormalized: ( a.getAttribute("href") === "/a" ),
+
+		// Make sure that element opacity exists
+		// (IE uses filter instead)
+		// Use a regex to work around a WebKit issue. See #5145
+		opacity: /^0.55/.test( a.style.opacity ),
+
+		// Verify style float existence
+		// (IE uses styleFloat instead of cssFloat)
+		cssFloat: !!a.style.cssFloat,
+
+		// Make sure that if no value is specified for a checkbox
+		// that it defaults to "on".
+		// (WebKit defaults to "" instead)
+		checkOn: ( input.value === "on" ),
+
+		// Make sure that a selected-by-default option has a working selected property.
+		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+		optSelected: opt.selected,
+
+		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+		getSetAttribute: div.className !== "t",
+
+		// Tests for enctype support on a form(#6743)
+		enctype: !!document.createElement("form").enctype,
+
+		// Makes sure cloning an html5 element does not cause problems
+		// Where outerHTML is undefined, this still works
+		html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
+
+		// Will be defined later
+		submitBubbles: true,
+		changeBubbles: true,
+		focusinBubbles: false,
+		deleteExpando: true,
+		noCloneEvent: true,
+		inlineBlockNeedsLayout: false,
+		shrinkWrapBlocks: false,
+		reliableMarginRight: true,
+		pixelMargin: true
+	};
+
+	// jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
+	jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
+
+	// Make sure checked status is properly cloned
+	input.checked = true;
+	support.noCloneChecked = input.cloneNode( true ).checked;
+
+	// Make sure that the options inside disabled selects aren't marked as disabled
+	// (WebKit marks them as disabled)
+	select.disabled = true;
+	support.optDisabled = !opt.disabled;
+
+	// Test to see if it's possible to delete an expando from an element
+	// Fails in Internet Explorer
+	try {
+		delete div.test;
+	} catch( e ) {
+		support.deleteExpando = false;
+	}
+
+	if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+		div.attachEvent( "onclick", function() {
+			// Cloning a node shouldn't copy over any
+			// bound event handlers (IE does this)
+			support.noCloneEvent = false;
+		});
+		div.cloneNode( true ).fireEvent( "onclick" );
+	}
+
+	// Check if a radio maintains its value
+	// after being appended to the DOM
+	input = document.createElement("input");
+	input.value = "t";
+	input.setAttribute("type", "radio");
+	support.radioValue = input.value === "t";
+
+	input.setAttribute("checked", "checked");
+
+	// #11217 - WebKit loses check when the name is after the checked attribute
+	input.setAttribute( "name", "t" );
+
+	div.appendChild( input );
+	fragment = document.createDocumentFragment();
+	fragment.appendChild( div.lastChild );
+
+	// WebKit doesn't clone checked state correctly in fragments
+	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+	// Check if a disconnected checkbox will retain its checked
+	// value of true after appended to the DOM (IE6/7)
+	support.appendChecked = input.checked;
+
+	fragment.removeChild( input );
+	fragment.appendChild( div );
+
+	// Technique from Juriy Zaytsev
+	// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
+	// We only care about the case where non-standard event systems
+	// are used, namely in IE. Short-circuiting here helps us to
+	// avoid an eval call (in setAttribute) which can cause CSP
+	// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+	if ( div.attachEvent ) {
+		for ( i in {
+			submit: 1,
+			change: 1,
+			focusin: 1
+		}) {
+			eventName = "on" + i;
+			isSupported = ( eventName in div );
+			if ( !isSupported ) {
+				div.setAttribute( eventName, "return;" );
+				isSupported = ( typeof div[ eventName ] === "function" );
+			}
+			support[ i + "Bubbles" ] = isSupported;
+		}
+	}
+
+	fragment.removeChild( div );
+
+	// Null elements to avoid leaks in IE
+	fragment = select = opt = div = input = null;
+
+	// Run tests that need a body at doc ready
+	jQuery(function() {
+		var container, outer, inner, table, td, offsetSupport,
+			marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
+			paddingMarginBorderVisibility, paddingMarginBorder,
+			body = document.getElementsByTagName("body")[0];
+
+		if ( !body ) {
+			// Return for frameset docs that don't have a body
+			return;
+		}
+
+		conMarginTop = 1;
+		paddingMarginBorder = "padding:0;margin:0;border:";
+		positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
+		paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
+		style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
+		html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
+			"<table " + style + "' cellpadding='0' cellspacing='0'>" +
+			"<tr><td></td></tr></table>";
+
+		container = document.createElement("div");
+		container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
+		body.insertBefore( container, body.firstChild );
+
+		// Construct the test element
+		div = document.createElement("div");
+		container.appendChild( div );
+
+		// Check if table cells still have offsetWidth/Height when they are set
+		// to display:none and there are still other visible table cells in a
+		// table row; if so, offsetWidth/Height are not reliable for use when
+		// determining if an element has been hidden directly using
+		// display:none (it is still safe to use offsets if a parent element is
+		// hidden; don safety goggles and see bug #4512 for more information).
+		// (only IE 8 fails this test)
+		div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";
+		tds = div.getElementsByTagName( "td" );
+		isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+		tds[ 0 ].style.display = "";
+		tds[ 1 ].style.display = "none";
+
+		// Check if empty table cells still have offsetWidth/Height
+		// (IE <= 8 fail this test)
+		support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+		// Check if div with explicit width and no margin-right incorrectly
+		// gets computed margin-right based on width of container. For more
+		// info see bug #3333
+		// Fails in WebKit before Feb 2011 nightlies
+		// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+		if ( window.getComputedStyle ) {
+			div.innerHTML = "";
+			marginDiv = document.createElement( "div" );
+			marginDiv.style.width = "0";
+			marginDiv.style.marginRight = "0";
+			div.style.width = "2px";
+			div.appendChild( marginDiv );
+			support.reliableMarginRight =
+				( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+		}
+
+		if ( typeof div.style.zoom !== "undefined" ) {
+			// Check if natively block-level elements act like inline-block
+			// elements when setting their display to 'inline' and giving
+			// them layout
+			// (IE < 8 does this)
+			div.innerHTML = "";
+			div.style.width = div.style.padding = "1px";
+			div.style.border = 0;
+			div.style.overflow = "hidden";
+			div.style.display = "inline";
+			div.style.zoom = 1;
+			support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+			// Check if elements with layout shrink-wrap their children
+			// (IE 6 does this)
+			div.style.display = "block";
+			div.style.overflow = "visible";
+			div.innerHTML = "<div style='width:5px;'></div>";
+			support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+		}
+
+		div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
+		div.innerHTML = html;
+
+		outer = div.firstChild;
+		inner = outer.firstChild;
+		td = outer.nextSibling.firstChild.firstChild;
+
+		offsetSupport = {
+			doesNotAddBorder: ( inner.offsetTop !== 5 ),
+			doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
+		};
+
+		inner.style.position = "fixed";
+		inner.style.top = "20px";
+
+		// safari subtracts parent border width here which is 5px
+		offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
+		inner.style.position = inner.style.top = "";
+
+		outer.style.overflow = "hidden";
+		outer.style.position = "relative";
+
+		offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
+		offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
+
+		if ( window.getComputedStyle ) {
+			div.style.marginTop = "1%";
+			support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
+		}
+
+		if ( typeof container.style.zoom !== "undefined" ) {
+			container.style.zoom = 1;
+		}
+
+		body.removeChild( container );
+		marginDiv = div = container = null;
+
+		jQuery.extend( support, offsetSupport );
+	});
+
+	return support;
+})();
+
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/,
+	rmultiDash = /([A-Z])/g;
+
+jQuery.extend({
+	cache: {},
+
+	// Please use with caution
+	uuid: 0,
+
+	// Unique for each copy of jQuery on the page
+	// Non-digits removed to match rinlinejQuery
+	expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+	// The following elements throw uncatchable exceptions if you
+	// attempt to add expando properties to them.
+	noData: {
+		"embed": true,
+		// Ban all objects except for Flash (which handle expandos)
+		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+		"applet": true
+	},
+
+	hasData: function( elem ) {
+		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+		return !!elem && !isEmptyDataObject( elem );
+	},
+
+	data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+		if ( !jQuery.acceptData( elem ) ) {
+			return;
+		}
+
+		var privateCache, thisCache, ret,
+			internalKey = jQuery.expando,
+			getByName = typeof name === "string",
+
+			// We have to handle DOM nodes and JS objects differently because IE6-7
+			// can't GC object references properly across the DOM-JS boundary
+			isNode = elem.nodeType,
+
+			// Only DOM nodes need the global jQuery cache; JS object data is
+			// attached directly to the object so GC can occur automatically
+			cache = isNode ? jQuery.cache : elem,
+
+			// Only defining an ID for JS objects if its cache already exists allows
+			// the code to shortcut on the same path as a DOM node with no cache
+			id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
+			isEvents = name === "events";
+
+		// Avoid doing any more work than we need to when trying to get data on an
+		// object that has no data at all
+		if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
+			return;
+		}
+
+		if ( !id ) {
+			// Only DOM nodes need a new unique ID for each element since their data
+			// ends up in the global cache
+			if ( isNode ) {
+				elem[ internalKey ] = id = ++jQuery.uuid;
+			} else {
+				id = internalKey;
+			}
+		}
+
+		if ( !cache[ id ] ) {
+			cache[ id ] = {};
+
+			// Avoids exposing jQuery metadata on plain JS objects when the object
+			// is serialized using JSON.stringify
+			if ( !isNode ) {
+				cache[ id ].toJSON = jQuery.noop;
+			}
+		}
+
+		// An object can be passed to jQuery.data instead of a key/value pair; this gets
+		// shallow copied over onto the existing cache
+		if ( typeof name === "object" || typeof name === "function" ) {
+			if ( pvt ) {
+				cache[ id ] = jQuery.extend( cache[ id ], name );
+			} else {
+				cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+			}
+		}
+
+		privateCache = thisCache = cache[ id ];
+
+		// jQuery data() is stored in a separate object inside the object's internal data
+		// cache in order to avoid key collisions between internal data and user-defined
+		// data.
+		if ( !pvt ) {
+			if ( !thisCache.data ) {
+				thisCache.data = {};
+			}
+
+			thisCache = thisCache.data;
+		}
+
+		if ( data !== undefined ) {
+			thisCache[ jQuery.camelCase( name ) ] = data;
+		}
+
+		// Users should not attempt to inspect the internal events object using jQuery.data,
+		// it is undocumented and subject to change. But does anyone listen? No.
+		if ( isEvents && !thisCache[ name ] ) {
+			return privateCache.events;
+		}
+
+		// Check for both converted-to-camel and non-converted data property names
+		// If a data property was specified
+		if ( getByName ) {
+
+			// First Try to find as-is property data
+			ret = thisCache[ name ];
+
+			// Test for null|undefined property data
+			if ( ret == null ) {
+
+				// Try to find the camelCased property
+				ret = thisCache[ jQuery.camelCase( name ) ];
+			}
+		} else {
+			ret = thisCache;
+		}
+
+		return ret;
+	},
+
+	removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+		if ( !jQuery.acceptData( elem ) ) {
+			return;
+		}
+
+		var thisCache, i, l,
+
+			// Reference to internal data cache key
+			internalKey = jQuery.expando,
+
+			isNode = elem.nodeType,
+
+			// See jQuery.data for more information
+			cache = isNode ? jQuery.cache : elem,
+
+			// See jQuery.data for more information
+			id = isNode ? elem[ internalKey ] : internalKey;
+
+		// If there is already no cache entry for this object, there is no
+		// purpose in continuing
+		if ( !cache[ id ] ) {
+			return;
+		}
+
+		if ( name ) {
+
+			thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+			if ( thisCache ) {
+
+				// Support array or space separated string names for data keys
+				if ( !jQuery.isArray( name ) ) {
+
+					// try the string as a key before any manipulation
+					if ( name in thisCache ) {
+						name = [ name ];
+					} else {
+
+						// split the camel cased version by spaces unless a key with the spaces exists
+						name = jQuery.camelCase( name );
+						if ( name in thisCache ) {
+							name = [ name ];
+						} else {
+							name = name.split( " " );
+						}
+					}
+				}
+
+				for ( i = 0, l = name.length; i < l; i++ ) {
+					delete thisCache[ name[i] ];
+				}
+
+				// If there is no data left in the cache, we want to continue
+				// and let the cache object itself get destroyed
+				if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+					return;
+				}
+			}
+		}
+
+		// See jQuery.data for more information
+		if ( !pvt ) {
+			delete cache[ id ].data;
+
+			// Don't destroy the parent cache unless the internal data object
+			// had been the only thing left in it
+			if ( !isEmptyDataObject(cache[ id ]) ) {
+				return;
+			}
+		}
+
+		// Browsers that fail expando deletion also refuse to delete expandos on
+		// the window, but it will allow it on all other JS objects; other browsers
+		// don't care
+		// Ensure that `cache` is not a window object #10080
+		if ( jQuery.support.deleteExpando || !cache.setInterval ) {
+			delete cache[ id ];
+		} else {
+			cache[ id ] = null;
+		}
+
+		// We destroyed the cache and need to eliminate the expando on the node to avoid
+		// false lookups in the cache for entries that no longer exist
+		if ( isNode ) {
+			// IE does not allow us to delete expando properties from nodes,
+			// nor does it have a removeAttribute function on Document nodes;
+			// we must handle all of these cases
+			if ( jQuery.support.deleteExpando ) {
+				delete elem[ internalKey ];
+			} else if ( elem.removeAttribute ) {
+				elem.removeAttribute( internalKey );
+			} else {
+				elem[ internalKey ] = null;
+			}
+		}
+	},
+
+	// For internal use only.
+	_data: function( elem, name, data ) {
+		return jQuery.data( elem, name, data, true );
+	},
+
+	// A method for determining if a DOM node can handle the data expando
+	acceptData: function( elem ) {
+		if ( elem.nodeName ) {
+			var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+			if ( match ) {
+				return !(match === true || elem.getAttribute("classid") !== match);
+			}
+		}
+
+		return true;
+	}
+});
+
+jQuery.fn.extend({
+	data: function( key, value ) {
+		var parts, part, attr, name, l,
+			elem = this[0],
+			i = 0,
+			data = null;
+
+		// Gets all values
+		if ( key === undefined ) {
+			if ( this.length ) {
+				data = jQuery.data( elem );
+
+				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+					attr = elem.attributes;
+					for ( l = attr.length; i < l; i++ ) {
+						name = attr[i].name;
+
+						if ( name.indexOf( "data-" ) === 0 ) {
+							name = jQuery.camelCase( name.substring(5) );
+
+							dataAttr( elem, name, data[ name ] );
+						}
+					}
+					jQuery._data( elem, "parsedAttrs", true );
+				}
+			}
+
+			return data;
+		}
+
+		// Sets multiple values
+		if ( typeof key === "object" ) {
+			return this.each(function() {
+				jQuery.data( this, key );
+			});
+		}
+
+		parts = key.split( ".", 2 );
+		parts[1] = parts[1] ? "." + parts[1] : "";
+		part = parts[1] + "!";
+
+		return jQuery.access( this, function( value ) {
+
+			if ( value === undefined ) {
+				data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+				// Try to fetch any internally stored data first
+				if ( data === undefined && elem ) {
+					data = jQuery.data( elem, key );
+					data = dataAttr( elem, key, data );
+				}
+
+				return data === undefined && parts[1] ?
+					this.data( parts[0] ) :
+					data;
+			}
+
+			parts[1] = value;
+			this.each(function() {
+				var self = jQuery( this );
+
+				self.triggerHandler( "setData" + part, parts );
+				jQuery.data( this, key, value );
+				self.triggerHandler( "changeData" + part, parts );
+			});
+		}, null, value, arguments.length > 1, null, false );
+	},
+
+	removeData: function( key ) {
+		return this.each(function() {
+			jQuery.removeData( this, key );
+		});
+	}
+});
+
+function dataAttr( elem, key, data ) {
+	// If nothing was found internally, try to fetch any
+	// data from the HTML5 data-* attribute
+	if ( data === undefined && elem.nodeType === 1 ) {
+
+		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+		data = elem.getAttribute( name );
+
+		if ( typeof data === "string" ) {
+			try {
+				data = data === "true" ? true :
+				data === "false" ? false :
+				data === "null" ? null :
+				jQuery.isNumeric( data ) ? +data :
+					rbrace.test( data ) ? jQuery.parseJSON( data ) :
+					data;
+			} catch( e ) {}
+
+			// Make sure we set the data so it isn't changed later
+			jQuery.data( elem, key, data );
+
+		} else {
+			data = undefined;
+		}
+	}
+
+	return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+	for ( var name in obj ) {
+
+		// if the public data object is empty, the private is still empty
+		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+			continue;
+		}
+		if ( name !== "toJSON" ) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+
+
+
+function handleQueueMarkDefer( elem, type, src ) {
+	var deferDataKey = type + "defer",
+		queueDataKey = type + "queue",
+		markDataKey = type + "mark",
+		defer = jQuery._data( elem, deferDataKey );
+	if ( defer &&
+		( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
+		( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
+		// Give room for hard-coded callbacks to fire first
+		// and eventually mark/queue something else on the element
+		setTimeout( function() {
+			if ( !jQuery._data( elem, queueDataKey ) &&
+				!jQuery._data( elem, markDataKey ) ) {
+				jQuery.removeData( elem, deferDataKey, true );
+				defer.fire();
+			}
+		}, 0 );
+	}
+}
+
+jQuery.extend({
+
+	_mark: function( elem, type ) {
+		if ( elem ) {
+			type = ( type || "fx" ) + "mark";
+			jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
+		}
+	},
+
+	_unmark: function( force, elem, type ) {
+		if ( force !== true ) {
+			type = elem;
+			elem = force;
+			force = false;
+		}
+		if ( elem ) {
+			type = type || "fx";
+			var key = type + "mark",
+				count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
+			if ( count ) {
+				jQuery._data( elem, key, count );
+			} else {
+				jQuery.removeData( elem, key, true );
+				handleQueueMarkDefer( elem, type, "mark" );
+			}
+		}
+	},
+
+	queue: function( elem, type, data ) {
+		var q;
+		if ( elem ) {
+			type = ( type || "fx" ) + "queue";
+			q = jQuery._data( elem, type );
+
+			// Speed up dequeue by getting out quickly if this is just a lookup
+			if ( data ) {
+				if ( !q || jQuery.isArray(data) ) {
+					q = jQuery._data( elem, type, jQuery.makeArray(data) );
+				} else {
+					q.push( data );
+				}
+			}
+			return q || [];
+		}
+	},
+
+	dequeue: function( elem, type ) {
+		type = type || "fx";
+
+		var queue = jQuery.queue( elem, type ),
+			fn = queue.shift(),
+			hooks = {};
+
+		// If the fx queue is dequeued, always remove the progress sentinel
+		if ( fn === "inprogress" ) {
+			fn = queue.shift();
+		}
+
+		if ( fn ) {
+			// Add a progress sentinel to prevent the fx queue from being
+			// automatically dequeued
+			if ( type === "fx" ) {
+				queue.unshift( "inprogress" );
+			}
+
+			jQuery._data( elem, type + ".run", hooks );
+			fn.call( elem, function() {
+				jQuery.dequeue( elem, type );
+			}, hooks );
+		}
+
+		if ( !queue.length ) {
+			jQuery.removeData( elem, type + "queue " + type + ".run", true );
+			handleQueueMarkDefer( elem, type, "queue" );
+		}
+	}
+});
+
+jQuery.fn.extend({
+	queue: function( type, data ) {
+		var setter = 2;
+
+		if ( typeof type !== "string" ) {
+			data = type;
+			type = "fx";
+			setter--;
+		}
+
+		if ( arguments.length < setter ) {
+			return jQuery.queue( this[0], type );
+		}
+
+		return data === undefined ?
+			this :
+			this.each(function() {
+				var queue = jQuery.queue( this, type, data );
+
+				if ( type === "fx" && queue[0] !== "inprogress" ) {
+					jQuery.dequeue( this, type );
+				}
+			});
+	},
+	dequeue: function( type ) {
+		return this.each(function() {
+			jQuery.dequeue( this, type );
+		});
+	},
+	// Based off of the plugin by Clint Helfers, with permission.
+	// http://blindsignals.com/index.php/2009/07/jquery-delay/
+	delay: function( time, type ) {
+		time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+		type = type || "fx";
+
+		return this.queue( type, function( next, hooks ) {
+			var timeout = setTimeout( next, time );
+			hooks.stop = function() {
+				clearTimeout( timeout );
+			};
+		});
+	},
+	clearQueue: function( type ) {
+		return this.queue( type || "fx", [] );
+	},
+	// Get a promise resolved when queues of a certain type
+	// are emptied (fx is the type by default)
+	promise: function( type, object ) {
+		if ( typeof type !== "string" ) {
+			object = type;
+			type = undefined;
+		}
+		type = type || "fx";
+		var defer = jQuery.Deferred(),
+			elements = this,
+			i = elements.length,
+			count = 1,
+			deferDataKey = type + "defer",
+			queueDataKey = type + "queue",
+			markDataKey = type + "mark",
+			tmp;
+		function resolve() {
+			if ( !( --count ) ) {
+				defer.resolveWith( elements, [ elements ] );
+			}
+		}
+		while( i-- ) {
+			if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
+					( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
+						jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
+					jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
+				count++;
+				tmp.add( resolve );
+			}
+		}
+		resolve();
+		return defer.promise( object );
+	}
+});
+
+
+
+
+var rclass = /[\n\t\r]/g,
+	rspace = /\s+/,
+	rreturn = /\r/g,
+	rtype = /^(?:button|input)$/i,
+	rfocusable = /^(?:button|input|object|select|textarea)$/i,
+	rclickable = /^a(?:rea)?$/i,
+	rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+	getSetAttribute = jQuery.support.getSetAttribute,
+	nodeHook, boolHook, fixSpecified;
+
+jQuery.fn.extend({
+	attr: function( name, value ) {
+		return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+	},
+
+	removeAttr: function( name ) {
+		return this.each(function() {
+			jQuery.removeAttr( this, name );
+		});
+	},
+
+	prop: function( name, value ) {
+		return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+	},
+
+	removeProp: function( name ) {
+		name = jQuery.propFix[ name ] || name;
+		return this.each(function() {
+			// try/catch handles cases where IE balks (such as removing a property on window)
+			try {
+				this[ name ] = undefined;
+				delete this[ name ];
+			} catch( e ) {}
+		});
+	},
+
+	addClass: function( value ) {
+		var classNames, i, l, elem,
+			setClass, c, cl;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).addClass( value.call(this, j, this.className) );
+			});
+		}
+
+		if ( value && typeof value === "string" ) {
+			classNames = value.split( rspace );
+
+			for ( i = 0, l = this.length; i < l; i++ ) {
+				elem = this[ i ];
+
+				if ( elem.nodeType === 1 ) {
+					if ( !elem.className && classNames.length === 1 ) {
+						elem.className = value;
+
+					} else {
+						setClass = " " + elem.className + " ";
+
+						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+							if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
+								setClass += classNames[ c ] + " ";
+							}
+						}
+						elem.className = jQuery.trim( setClass );
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	removeClass: function( value ) {
+		var classNames, i, l, elem, className, c, cl;
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( j ) {
+				jQuery( this ).removeClass( value.call(this, j, this.className) );
+			});
+		}
+
+		if ( (value && typeof value === "string") || value === undefined ) {
+			classNames = ( value || "" ).split( rspace );
+
+			for ( i = 0, l = this.length; i < l; i++ ) {
+				elem = this[ i ];
+
+				if ( elem.nodeType === 1 && elem.className ) {
+					if ( value ) {
+						className = (" " + elem.className + " ").replace( rclass, " " );
+						for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+							className = className.replace(" " + classNames[ c ] + " ", " ");
+						}
+						elem.className = jQuery.trim( className );
+
+					} else {
+						elem.className = "";
+					}
+				}
+			}
+		}
+
+		return this;
+	},
+
+	toggleClass: function( value, stateVal ) {
+		var type = typeof value,
+			isBool = typeof stateVal === "boolean";
+
+		if ( jQuery.isFunction( value ) ) {
+			return this.each(function( i ) {
+				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+			});
+		}
+
+		return this.each(function() {
+			if ( type === "string" ) {
+				// toggle individual class names
+				var className,
+					i = 0,
+					self = jQuery( this ),
+					state = stateVal,
+					classNames = value.split( rspace );
+
+				while ( (className = classNames[ i++ ]) ) {
+					// check each className given, space seperated list
+					state = isBool ? state : !self.hasClass( className );
+					self[ state ? "addClass" : "removeClass" ]( className );
+				}
+
+			} else if ( type === "undefined" || type === "boolean" ) {
+				if ( this.className ) {
+					// store className if set
+					jQuery._data( this, "__className__", this.className );
+				}
+
+				// toggle whole className
+				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+			}
+		});
+	},
+
+	hasClass: function( selector ) {
+		var className = " " + selector + " ",
+			i = 0,
+			l = this.length;
+		for ( ; i < l; i++ ) {
+			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+				return true;
+			}
+		}
+
+		return false;
+	},
+
+	val: function( value ) {
+		var hooks, ret, isFunction,
+			elem = this[0];
+
+		if ( !arguments.length ) {
+			if ( elem ) {
+				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+					return ret;
+				}
+
+				ret = elem.value;
+
+				return typeof ret === "string" ?
+					// handle most common string cases
+					ret.replace(rreturn, "") :
+					// handle cases where value is null/undef or number
+					ret == null ? "" : ret;
+			}
+
+			return;
+		}
+
+		isFunction = jQuery.isFunction( value );
+
+		return this.each(function( i ) {
+			var self = jQuery(this), val;
+
+			if ( this.nodeType !== 1 ) {
+				return;
+			}
+
+			if ( isFunction ) {
+				val = value.call( this, i, self.val() );
+			} else {
+				val = value;
+			}
+
+			// Treat null/undefined as ""; convert numbers to string
+			if ( val == null ) {
+				val = "";
+			} else if ( typeof val === "number" ) {
+				val += "";
+			} else if ( jQuery.isArray( val ) ) {
+				val = jQuery.map(val, function ( value ) {
+					return value == null ? "" : value + "";
+				});
+			}
+
+			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+			// If set returns undefined, fall back to normal setting
+			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+				this.value = val;
+			}
+		});
+	}
+});
+
+jQuery.extend({
+	valHooks: {
+		option: {
+			get: function( elem ) {
+				// attributes.value is undefined in Blackberry 4.7 but
+				// uses .value. See #6932
+				var val = elem.attributes.value;
+				return !val || val.specified ? elem.value : elem.text;
+			}
+		},
+		select: {
+			get: function( elem ) {
+				var value, i, max, option,
+					index = elem.selectedIndex,
+					values = [],
+					options = elem.options,
+					one = elem.type === "select-one";
+
+				// Nothing was selected
+				if ( index < 0 ) {
+					return null;
+				}
+
+				// Loop through all the selected options
+				i = one ? index : 0;
+				max = one ? index + 1 : options.length;
+				for ( ; i < max; i++ ) {
+					option = options[ i ];
+
+					// Don't return options that are disabled or in a disabled optgroup
+					if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+							(!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+						// Get the specific value for the option
+						value = jQuery( option ).val();
+
+						// We don't need an array for one selects
+						if ( one ) {
+							return value;
+						}
+
+						// Multi-Selects return an array
+						values.push( value );
+					}
+				}
+
+				// Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+				if ( one && !values.length && options.length ) {
+					return jQuery( options[ index ] ).val();
+				}
+
+				return values;
+			},
+
+			set: function( elem, value ) {
+				var values = jQuery.makeArray( value );
+
+				jQuery(elem).find("option").each(function() {
+					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+				});
+
+				if ( !values.length ) {
+					elem.selectedIndex = -1;
+				}
+				return values;
+			}
+		}
+	},
+
+	attrFn: {
+		val: true,
+		css: true,
+		html: true,
+		text: true,
+		data: true,
+		width: true,
+		height: true,
+		offset: true
+	},
+
+	attr: function( elem, name, value, pass ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// don't get/set attributes on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		if ( pass && name in jQuery.attrFn ) {
+			return jQuery( elem )[ name ]( value );
+		}
+
+		// Fallback to prop when attributes are not supported
+		if ( typeof elem.getAttribute === "undefined" ) {
+			return jQuery.prop( elem, name, value );
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		// All attributes are lowercase
+		// Grab necessary hook if one is defined
+		if ( notxml ) {
+			name = name.toLowerCase();
+			hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+		}
+
+		if ( value !== undefined ) {
+
+			if ( value === null ) {
+				jQuery.removeAttr( elem, name );
+				return;
+
+			} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				elem.setAttribute( name, "" + value );
+				return value;
+			}
+
+		} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+			return ret;
+
+		} else {
+
+			ret = elem.getAttribute( name );
+
+			// Non-existent attributes return null, we normalize to undefined
+			return ret === null ?
+				undefined :
+				ret;
+		}
+	},
+
+	removeAttr: function( elem, value ) {
+		var propName, attrNames, name, l, isBool,
+			i = 0;
+
+		if ( value && elem.nodeType === 1 ) {
+			attrNames = value.toLowerCase().split( rspace );
+			l = attrNames.length;
+
+			for ( ; i < l; i++ ) {
+				name = attrNames[ i ];
+
+				if ( name ) {
+					propName = jQuery.propFix[ name ] || name;
+					isBool = rboolean.test( name );
+
+					// See #9699 for explanation of this approach (setting first, then removal)
+					// Do not do this for boolean attributes (see #10870)
+					if ( !isBool ) {
+						jQuery.attr( elem, name, "" );
+					}
+					elem.removeAttribute( getSetAttribute ? name : propName );
+
+					// Set corresponding property to false for boolean attributes
+					if ( isBool && propName in elem ) {
+						elem[ propName ] = false;
+					}
+				}
+			}
+		}
+	},
+
+	attrHooks: {
+		type: {
+			set: function( elem, value ) {
+				// We can't allow the type property to be changed (since it causes problems in IE)
+				if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+					jQuery.error( "type property can't be changed" );
+				} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+					// Setting the type on a radio button after the value resets the value in IE6-9
+					// Reset value to it's default in case type is set after value
+					// This is for element creation
+					var val = elem.value;
+					elem.setAttribute( "type", value );
+					if ( val ) {
+						elem.value = val;
+					}
+					return value;
+				}
+			}
+		},
+		// Use the value property for back compat
+		// Use the nodeHook for button elements in IE6/7 (#1954)
+		value: {
+			get: function( elem, name ) {
+				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+					return nodeHook.get( elem, name );
+				}
+				return name in elem ?
+					elem.value :
+					null;
+			},
+			set: function( elem, value, name ) {
+				if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+					return nodeHook.set( elem, value, name );
+				}
+				// Does not return so that setAttribute is also used
+				elem.value = value;
+			}
+		}
+	},
+
+	propFix: {
+		tabindex: "tabIndex",
+		readonly: "readOnly",
+		"for": "htmlFor",
+		"class": "className",
+		maxlength: "maxLength",
+		cellspacing: "cellSpacing",
+		cellpadding: "cellPadding",
+		rowspan: "rowSpan",
+		colspan: "colSpan",
+		usemap: "useMap",
+		frameborder: "frameBorder",
+		contenteditable: "contentEditable"
+	},
+
+	prop: function( elem, name, value ) {
+		var ret, hooks, notxml,
+			nType = elem.nodeType;
+
+		// don't get/set properties on text, comment and attribute nodes
+		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+			return;
+		}
+
+		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+		if ( notxml ) {
+			// Fix name and attach hooks
+			name = jQuery.propFix[ name ] || name;
+			hooks = jQuery.propHooks[ name ];
+		}
+
+		if ( value !== undefined ) {
+			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+				return ret;
+
+			} else {
+				return ( elem[ name ] = value );
+			}
+
+		} else {
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+				return ret;
+
+			} else {
+				return elem[ name ];
+			}
+		}
+	},
+
+	propHooks: {
+		tabIndex: {
+			get: function( elem ) {
+				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+				var attributeNode = elem.getAttributeNode("tabindex");
+
+				return attributeNode && attributeNode.specified ?
+					parseInt( attributeNode.value, 10 ) :
+					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+						0 :
+						undefined;
+			}
+		}
+	}
+});
+
+// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
+jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
+
+// Hook for boolean attributes
+boolHook = {
+	get: function( elem, name ) {
+		// Align boolean attributes with corresponding properties
+		// Fall back to attribute presence where some booleans are not supported
+		var attrNode,
+			property = jQuery.prop( elem, name );
+		return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+			name.toLowerCase() :
+			undefined;
+	},
+	set: function( elem, value, name ) {
+		var propName;
+		if ( value === false ) {
+			// Remove boolean attributes when set to false
+			jQuery.removeAttr( elem, name );
+		} else {
+			// value is true since we know at this point it's type boolean and not false
+			// Set boolean attributes to the same name and set the DOM property
+			propName = jQuery.propFix[ name ] || name;
+			if ( propName in elem ) {
+				// Only set the IDL specifically if it already exists on the element
+				elem[ propName ] = true;
+			}
+
+			elem.setAttribute( name, name.toLowerCase() );
+		}
+		return name;
+	}
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+	fixSpecified = {
+		name: true,
+		id: true,
+		coords: true
+	};
+
+	// Use this for any attribute in IE6/7
+	// This fixes almost every IE6/7 issue
+	nodeHook = jQuery.valHooks.button = {
+		get: function( elem, name ) {
+			var ret;
+			ret = elem.getAttributeNode( name );
+			return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
+				ret.nodeValue :
+				undefined;
+		},
+		set: function( elem, value, name ) {
+			// Set the existing or create a new attribute node
+			var ret = elem.getAttributeNode( name );
+			if ( !ret ) {
+				ret = document.createAttribute( name );
+				elem.setAttributeNode( ret );
+			}
+			return ( ret.nodeValue = value + "" );
+		}
+	};
+
+	// Apply the nodeHook to tabindex
+	jQuery.attrHooks.tabindex.set = nodeHook.set;
+
+	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
+	// This is for removals
+	jQuery.each([ "width", "height" ], function( i, name ) {
+		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+			set: function( elem, value ) {
+				if ( value === "" ) {
+					elem.setAttribute( name, "auto" );
+					return value;
+				}
+			}
+		});
+	});
+
+	// Set contenteditable to false on removals(#10429)
+	// Setting to empty string throws an error as an invalid value
+	jQuery.attrHooks.contenteditable = {
+		get: nodeHook.get,
+		set: function( elem, value, name ) {
+			if ( value === "" ) {
+				value = "false";
+			}
+			nodeHook.set( elem, value, name );
+		}
+	};
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+			get: function( elem ) {
+				var ret = elem.getAttribute( name, 2 );
+				return ret === null ? undefined : ret;
+			}
+		});
+	});
+}
+
+if ( !jQuery.support.style ) {
+	jQuery.attrHooks.style = {
+		get: function( elem ) {
+			// Return undefined in the case of empty string
+			// Normalize to lowercase since IE uppercases css property names
+			return elem.style.cssText.toLowerCase() || undefined;
+		},
+		set: function( elem, value ) {
+			return ( elem.style.cssText = "" + value );
+		}
+	};
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+		get: function( elem ) {
+			var parent = elem.parentNode;
+
+			if ( parent ) {
+				parent.selectedIndex;
+
+				// Make sure that it also works with optgroups, see #5701
+				if ( parent.parentNode ) {
+					parent.parentNode.selectedIndex;
+				}
+			}
+			return null;
+		}
+	});
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+	jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+	jQuery.each([ "radio", "checkbox" ], function() {
+		jQuery.valHooks[ this ] = {
+			get: function( elem ) {
+				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+				return elem.getAttribute("value") === null ? "on" : elem.value;
+			}
+		};
+	});
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+		set: function( elem, value ) {
+			if ( jQuery.isArray( value ) ) {
+				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+			}
+		}
+	});
+});
+
+
+
+
+var rformElems = /^(?:textarea|input|select)$/i,
+	rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
+	rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
+	rkeyEvent = /^key/,
+	rmouseEvent = /^(?:mouse|contextmenu)|click/,
+	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+	rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
+	quickParse = function( selector ) {
+		var quick = rquickIs.exec( selector );
+		if ( quick ) {
+			//   0  1    2   3
+			// [ _, tag, id, class ]
+			quick[1] = ( quick[1] || "" ).toLowerCase();
+			quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
+		}
+		return quick;
+	},
+	quickIs = function( elem, m ) {
+		var attrs = elem.attributes || {};
+		return (
+			(!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
+			(!m[2] || (attrs.id || {}).value === m[2]) &&
+			(!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
+		);
+	},
+	hoverHack = function( events ) {
+		return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+	};
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+	add: function( elem, types, handler, data, selector ) {
+
+		var elemData, eventHandle, events,
+			t, tns, type, namespaces, handleObj,
+			handleObjIn, quick, handlers, special;
+
+		// Don't attach events to noData or text/comment nodes (allow plain objects tho)
+		if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
+			return;
+		}
+
+		// Caller can pass in an object of custom data in lieu of the handler
+		if ( handler.handler ) {
+			handleObjIn = handler;
+			handler = handleObjIn.handler;
+			selector = handleObjIn.selector;
+		}
+
+		// Make sure that the handler has a unique ID, used to find/remove it later
+		if ( !handler.guid ) {
+			handler.guid = jQuery.guid++;
+		}
+
+		// Init the element's event structure and main handler, if this is the first
+		events = elemData.events;
+		if ( !events ) {
+			elemData.events = events = {};
+		}
+		eventHandle = elemData.handle;
+		if ( !eventHandle ) {
+			elemData.handle = eventHandle = function( e ) {
+				// Discard the second event of a jQuery.event.trigger() and
+				// when an event is called after a page has unloaded
+				return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+					undefined;
+			};
+			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+			eventHandle.elem = elem;
+		}
+
+		// Handle multiple events separated by a space
+		// jQuery(...).bind("mouseover mouseout", fn);
+		types = jQuery.trim( hoverHack(types) ).split( " " );
+		for ( t = 0; t < types.length; t++ ) {
+
+			tns = rtypenamespace.exec( types[t] ) || [];
+			type = tns[1];
+			namespaces = ( tns[2] || "" ).split( "." ).sort();
+
+			// If event changes its type, use the special event handlers for the changed type
+			special = jQuery.event.special[ type ] || {};
+
+			// If selector defined, determine special event api type, otherwise given type
+			type = ( selector ? special.delegateType : special.bindType ) || type;
+
+			// Update special based on newly reset type
+			special = jQuery.event.special[ type ] || {};
+
+			// handleObj is passed to all event handlers
+			handleObj = jQuery.extend({
+				type: type,
+				origType: tns[1],
+				data: data,
+				handler: handler,
+				guid: handler.guid,
+				selector: selector,
+				quick: selector && quickParse( selector ),
+				namespace: namespaces.join(".")
+			}, handleObjIn );
+
+			// Init the event handler queue if we're the first
+			handlers = events[ type ];
+			if ( !handlers ) {
+				handlers = events[ type ] = [];
+				handlers.delegateCount = 0;
+
+				// Only use addEventListener/attachEvent if the special events handler returns false
+				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+					// Bind the global event handler to the element
+					if ( elem.addEventListener ) {
+						elem.addEventListener( type, eventHandle, false );
+
+					} else if ( elem.attachEvent ) {
+						elem.attachEvent( "on" + type, eventHandle );
+					}
+				}
+			}
+
+			if ( special.add ) {
+				special.add.call( elem, handleObj );
+
+				if ( !handleObj.handler.guid ) {
+					handleObj.handler.guid = handler.guid;
+				}
+			}
+
+			// Add to the element's handler list, delegates in front
+			if ( selector ) {
+				handlers.splice( handlers.delegateCount++, 0, handleObj );
+			} else {
+				handlers.push( handleObj );
+			}
+
+			// Keep track of which events have ever been used, for event optimization
+			jQuery.event.global[ type ] = true;
+		}
+
+		// Nullify elem to prevent memory leaks in IE
+		elem = null;
+	},
+
+	global: {},
+
+	// Detach an event or set of events from an element
+	remove: function( elem, types, handler, selector, mappedTypes ) {
+
+		var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+			t, tns, type, origType, namespaces, origCount,
+			j, events, special, handle, eventType, handleObj;
+
+		if ( !elemData || !(events = elemData.events) ) {
+			return;
+		}
+
+		// Once for each type.namespace in types; type may be omitted
+		types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+		for ( t = 0; t < types.length; t++ ) {
+			tns = rtypenamespace.exec( types[t] ) || [];
+			type = origType = tns[1];
+			namespaces = tns[2];
+
+			// Unbind all events (on this namespace, if provided) for the element
+			if ( !type ) {
+				for ( type in events ) {
+					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+				}
+				continue;
+			}
+
+			special = jQuery.event.special[ type ] || {};
+			type = ( selector? special.delegateType : special.bindType ) || type;
+			eventType = events[ type ] || [];
+			origCount = eventType.length;
+			namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+
+			// Remove matching events
+			for ( j = 0; j < eventType.length; j++ ) {
+				handleObj = eventType[ j ];
+
+				if ( ( mappedTypes || origType === handleObj.origType ) &&
+					 ( !handler || handler.guid === handleObj.guid ) &&
+					 ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+					 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+					eventType.splice( j--, 1 );
+
+					if ( handleObj.selector ) {
+						eventType.delegateCount--;
+					}
+					if ( special.remove ) {
+						special.remove.call( elem, handleObj );
+					}
+				}
+			}
+
+			// Remove generic event handler if we removed something and no more handlers exist
+			// (avoids potential for endless recursion during removal of special event handlers)
+			if ( eventType.length === 0 && origCount !== eventType.length ) {
+				if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+					jQuery.removeEvent( elem, type, elemData.handle );
+				}
+
+				delete events[ type ];
+			}
+		}
+
+		// Remove the expando if it's no longer used
+		if ( jQuery.isEmptyObject( events ) ) {
+			handle = elemData.handle;
+			if ( handle ) {
+				handle.elem = null;
+			}
+
+			// removeData also checks for emptiness and clears the expando if empty
+			// so use it instead of delete
+			jQuery.removeData( elem, [ "events", "handle" ], true );
+		}
+	},
+
+	// Events that are safe to short-circuit if no handlers are attached.
+	// Native DOM events should not be added, they may have inline handlers.
+	customEvent: {
+		"getData": true,
+		"setData": true,
+		"changeData": true
+	},
+
+	trigger: function( event, data, elem, onlyHandlers ) {
+		// Don't do events on text and comment nodes
+		if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+			return;
+		}
+
+		// Event object or event type
+		var type = event.type || event,
+			namespaces = [],
+			cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
+
+		// focus/blur morphs to focusin/out; ensure we're not firing them right now
+		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+			return;
+		}
+
+		if ( type.indexOf( "!" ) >= 0 ) {
+			// Exclusive events trigger only for the exact event (no namespaces)
+			type = type.slice(0, -1);
+			exclusive = true;
+		}
+
+		if ( type.indexOf( "." ) >= 0 ) {
+			// Namespaced trigger; create a regexp to match event type in handle()
+			namespaces = type.split(".");
+			type = namespaces.shift();
+			namespaces.sort();
+		}
+
+		if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+			// No jQuery handlers for this event type, and it can't have inline handlers
+			return;
+		}
+
+		// Caller can pass in an Event, Object, or just an event type string
+		event = typeof event === "object" ?
+			// jQuery.Event object
+			event[ jQuery.expando ] ? event :
+			// Object literal
+			new jQuery.Event( type, event ) :
+			// Just the event type (string)
+			new jQuery.Event( type );
+
+		event.type = type;
+		event.isTrigger = true;
+		event.exclusive = exclusive;
+		event.namespace = namespaces.join( "." );
+		event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+		ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
+		// Handle a global trigger
+		if ( !elem ) {
+
+			// TODO: Stop taunting the data cache; remove global events and always attach to document
+			cache = jQuery.cache;
+			for ( i in cache ) {
+				if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+					jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
+				}
+			}
+			return;
+		}
+
+		// Clean up the event in case it is being reused
+		event.result = undefined;
+		if ( !event.target ) {
+			event.target = elem;
+		}
+
+		// Clone any incoming data and prepend the event, creating the handler arg list
+		data = data != null ? jQuery.makeArray( data ) : [];
+		data.unshift( event );
+
+		// Allow special events to draw outside the lines
+		special = jQuery.event.special[ type ] || {};
+		if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+			return;
+		}
+
+		// Determine event propagation path in advance, per W3C events spec (#9951)
+		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+		eventPath = [[ elem, special.bindType || type ]];
+		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+			bubbleType = special.delegateType || type;
+			cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+			old = null;
+			for ( ; cur; cur = cur.parentNode ) {
+				eventPath.push([ cur, bubbleType ]);
+				old = cur;
+			}
+
+			// Only add window if we got to document (e.g., not plain obj or detached DOM)
+			if ( old && old === elem.ownerDocument ) {
+				eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+			}
+		}
+
+		// Fire handlers on the event path
+		for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+			cur = eventPath[i][0];
+			event.type = eventPath[i][1];
+
+			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+			if ( handle ) {
+				handle.apply( cur, data );
+			}
+			// Note that this is a bare JS function and not a jQuery handler
+			handle = ontype && cur[ ontype ];
+			if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
+				event.preventDefault();
+			}
+		}
+		event.type = type;
+
+		// If nobody prevented the default action, do it now
+		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+			if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+				// Call a native DOM method on the target with the same name name as the event.
+				// Can't use an .isFunction() check here because IE6/7 fails that test.
+				// Don't do default actions on window, that's where global variables be (#6170)
+				// IE<9 dies on focus/blur to hidden element (#1486)
+				if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+
+					// Don't re-trigger an onFOO event when we call its FOO() method
+					old = elem[ ontype ];
+
+					if ( old ) {
+						elem[ ontype ] = null;
+					}
+
+					// Prevent re-triggering of the same event, since we already bubbled it above
+					jQuery.event.triggered = type;
+					elem[ type ]();
+					jQuery.event.triggered = undefined;
+
+					if ( old ) {
+						elem[ ontype ] = old;
+					}
+				}
+			}
+		}
+
+		return event.result;
+	},
+
+	dispatch: function( event ) {
+
+		// Make a writable jQuery.Event from the native event object
+		event = jQuery.event.fix( event || window.event );
+
+		var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+			delegateCount = handlers.delegateCount,
+			args = [].slice.call( arguments, 0 ),
+			run_all = !event.exclusive && !event.namespace,
+			special = jQuery.event.special[ event.type ] || {},
+			handlerQueue = [],
+			i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
+
+		// Use the fix-ed jQuery.Event rather than the (read-only) native event
+		args[0] = event;
+		event.delegateTarget = this;
+
+		// Call the preDispatch hook for the mapped type, and let it bail if desired
+		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+			return;
+		}
+
+		// Determine handlers that should run if there are delegated events
+		// Avoid non-left-click bubbling in Firefox (#3861)
+		if ( delegateCount && !(event.button && event.type === "click") ) {
+
+			// Pregenerate a single jQuery object for reuse with .is()
+			jqcur = jQuery(this);
+			jqcur.context = this.ownerDocument || this;
+
+			for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+
+				// Don't process events on disabled elements (#6911, #8165)
+				if ( cur.disabled !== true ) {
+					selMatch = {};
+					matches = [];
+					jqcur[0] = cur;
+					for ( i = 0; i < delegateCount; i++ ) {
+						handleObj = handlers[ i ];
+						sel = handleObj.selector;
+
+						if ( selMatch[ sel ] === undefined ) {
+							selMatch[ sel ] = (
+								handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
+							);
+						}
+						if ( selMatch[ sel ] ) {
+							matches.push( handleObj );
+						}
+					}
+					if ( matches.length ) {
+						handlerQueue.push({ elem: cur, matches: matches });
+					}
+				}
+			}
+		}
+
+		// Add the remaining (directly-bound) handlers
+		if ( handlers.length > delegateCount ) {
+			handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+		}
+
+		// Run delegates first; they may want to stop propagation beneath us
+		for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+			matched = handlerQueue[ i ];
+			event.currentTarget = matched.elem;
+
+			for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+				handleObj = matched.matches[ j ];
+
+				// Triggered event must either 1) be non-exclusive and have no namespace, or
+				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+				if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+					event.data = handleObj.data;
+					event.handleObj = handleObj;
+
+					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+							.apply( matched.elem, args );
+
+					if ( ret !== undefined ) {
+						event.result = ret;
+						if ( ret === false ) {
+							event.preventDefault();
+							event.stopPropagation();
+						}
+					}
+				}
+			}
+		}
+
+		// Call the postDispatch hook for the mapped type
+		if ( special.postDispatch ) {
+			special.postDispatch.call( this, event );
+		}
+
+		return event.result;
+	},
+
+	// Includes some event props shared by KeyEvent and MouseEvent
+	// *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+	props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+	fixHooks: {},
+
+	keyHooks: {
+		props: "char charCode key keyCode".split(" "),
+		filter: function( event, original ) {
+
+			// Add which for key events
+			if ( event.which == null ) {
+				event.which = original.charCode != null ? original.charCode : original.keyCode;
+			}
+
+			return event;
+		}
+	},
+
+	mouseHooks: {
+		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+		filter: function( event, original ) {
+			var eventDoc, doc, body,
+				button = original.button,
+				fromElement = original.fromElement;
+
+			// Calculate pageX/Y if missing and clientX/Y available
+			if ( event.pageX == null && original.clientX != null ) {
+				eventDoc = event.target.ownerDocument || document;
+				doc = eventDoc.documentElement;
+				body = eventDoc.body;
+
+				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
+			}
+
+			// Add relatedTarget, if necessary
+			if ( !event.relatedTarget && fromElement ) {
+				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+			}
+
+			// Add which for click: 1 === left; 2 === middle; 3 === right
+			// Note: button is not normalized, so don't use it
+			if ( !event.which && button !== undefined ) {
+				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+			}
+
+			return event;
+		}
+	},
+
+	fix: function( event ) {
+		if ( event[ jQuery.expando ] ) {
+			return event;
+		}
+
+		// Create a writable copy of the event object and normalize some properties
+		var i, prop,
+			originalEvent = event,
+			fixHook = jQuery.event.fixHooks[ event.type ] || {},
+			copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+		event = jQuery.Event( originalEvent );
+
+		for ( i = copy.length; i; ) {
+			prop = copy[ --i ];
+			event[ prop ] = originalEvent[ prop ];
+		}
+
+		// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
+		if ( !event.target ) {
+			event.target = originalEvent.srcElement || document;
+		}
+
+		// Target should not be a text node (#504, Safari)
+		if ( event.target.nodeType === 3 ) {
+			event.target = event.target.parentNode;
+		}
+
+		// For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
+		if ( event.metaKey === undefined ) {
+			event.metaKey = event.ctrlKey;
+		}
+
+		return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+	},
+
+	special: {
+		ready: {
+			// Make sure the ready event is setup
+			setup: jQuery.bindReady
+		},
+
+		load: {
+			// Prevent triggered image.load events from bubbling to window.load
+			noBubble: true
+		},
+
+		focus: {
+			delegateType: "focusin"
+		},
+		blur: {
+			delegateType: "focusout"
+		},
+
+		beforeunload: {
+			setup: function( data, namespaces, eventHandle ) {
+				// We only want to do this special case on windows
+				if ( jQuery.isWindow( this ) ) {
+					this.onbeforeunload = eventHandle;
+				}
+			},
+
+			teardown: function( namespaces, eventHandle ) {
+				if ( this.onbeforeunload === eventHandle ) {
+					this.onbeforeunload = null;
+				}
+			}
+		}
+	},
+
+	simulate: function( type, elem, event, bubble ) {
+		// Piggyback on a donor event to simulate a different one.
+		// Fake originalEvent to avoid donor's stopPropagation, but if the
+		// simulated event prevents default then we do the same on the donor.
+		var e = jQuery.extend(
+			new jQuery.Event(),
+			event,
+			{ type: type,
+				isSimulated: true,
+				originalEvent: {}
+			}
+		);
+		if ( bubble ) {
+			jQuery.event.trigger( e, null, elem );
+		} else {
+			jQuery.event.dispatch.call( elem, e );
+		}
+		if ( e.isDefaultPrevented() ) {
+			event.preventDefault();
+		}
+	}
+};
+
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
+jQuery.removeEvent = document.removeEventListener ?
+	function( elem, type, handle ) {
+		if ( elem.removeEventListener ) {
+			elem.removeEventListener( type, handle, false );
+		}
+	} :
+	function( elem, type, handle ) {
+		if ( elem.detachEvent ) {
+			elem.detachEvent( "on" + type, handle );
+		}
+	};
+
+jQuery.Event = function( src, props ) {
+	// Allow instantiation without the 'new' keyword
+	if ( !(this instanceof jQuery.Event) ) {
+		return new jQuery.Event( src, props );
+	}
+
+	// Event object
+	if ( src && src.type ) {
+		this.originalEvent = src;
+		this.type = src.type;
+
+		// Events bubbling up the document may have been marked as prevented
+		// by a handler lower down the tree; reflect the correct value.
+		this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+			src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+	// Event type
+	} else {
+		this.type = src;
+	}
+
+	// Put explicitly provided properties onto the event object
+	if ( props ) {
+		jQuery.extend( this, props );
+	}
+
+	// Create a timestamp if incoming event doesn't have one
+	this.timeStamp = src && src.timeStamp || jQuery.now();
+
+	// Mark it as fixed
+	this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+	return false;
+}
+function returnTrue() {
+	return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+	preventDefault: function() {
+		this.isDefaultPrevented = returnTrue;
+
+		var e = this.originalEvent;
+		if ( !e ) {
+			return;
+		}
+
+		// if preventDefault exists run it on the original event
+		if ( e.preventDefault ) {
+			e.preventDefault();
+
+		// otherwise set the returnValue property of the original event to false (IE)
+		} else {
+			e.returnValue = false;
+		}
+	},
+	stopPropagation: function() {
+		this.isPropagationStopped = returnTrue;
+
+		var e = this.originalEvent;
+		if ( !e ) {
+			return;
+		}
+		// if stopPropagation exists run it on the original event
+		if ( e.stopPropagation ) {
+			e.stopPropagation();
+		}
+		// otherwise set the cancelBubble property of the original event to true (IE)
+		e.cancelBubble = true;
+	},
+	stopImmediatePropagation: function() {
+		this.isImmediatePropagationStopped = returnTrue;
+		this.stopPropagation();
+	},
+	isDefaultPrevented: returnFalse,
+	isPropagationStopped: returnFalse,
+	isImmediatePropagationStopped: returnFalse
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+	mouseenter: "mouseover",
+	mouseleave: "mouseout"
+}, function( orig, fix ) {
+	jQuery.event.special[ orig ] = {
+		delegateType: fix,
+		bindType: fix,
+
+		handle: function( event ) {
+			var target = this,
+				related = event.relatedTarget,
+				handleObj = event.handleObj,
+				selector = handleObj.selector,
+				ret;
+
+			// For mousenter/leave call the handler if related is outside the target.
+			// NB: No relatedTarget if the mouse left/entered the browser window
+			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+				event.type = handleObj.origType;
+				ret = handleObj.handler.apply( this, arguments );
+				event.type = fix;
+			}
+			return ret;
+		}
+	};
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+	jQuery.event.special.submit = {
+		setup: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Lazy-add a submit handler when a descendant form may potentially be submitted
+			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+				// Node name check avoids a VML-related crash in IE (#9807)
+				var elem = e.target,
+					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+				if ( form && !form._submit_attached ) {
+					jQuery.event.add( form, "submit._submit", function( event ) {
+						event._submit_bubble = true;
+					});
+					form._submit_attached = true;
+				}
+			});
+			// return undefined since we don't need an event listener
+		},
+		
+		postDispatch: function( event ) {
+			// If form was submitted by the user, bubble the event up the tree
+			if ( event._submit_bubble ) {
+				delete event._submit_bubble;
+				if ( this.parentNode && !event.isTrigger ) {
+					jQuery.event.simulate( "submit", this.parentNode, event, true );
+				}
+			}
+		},
+
+		teardown: function() {
+			// Only need this for delegated form submit events
+			if ( jQuery.nodeName( this, "form" ) ) {
+				return false;
+			}
+
+			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+			jQuery.event.remove( this, "._submit" );
+		}
+	};
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+	jQuery.event.special.change = {
+
+		setup: function() {
+
+			if ( rformElems.test( this.nodeName ) ) {
+				// IE doesn't fire change on a check/radio until blur; trigger it on click
+				// after a propertychange. Eat the blur-change in special.change.handle.
+				// This still fires onchange a second time for check/radio after blur.
+				if ( this.type === "checkbox" || this.type === "radio" ) {
+					jQuery.event.add( this, "propertychange._change", function( event ) {
+						if ( event.originalEvent.propertyName === "checked" ) {
+							this._just_changed = true;
+						}
+					});
+					jQuery.event.add( this, "click._change", function( event ) {
+						if ( this._just_changed && !event.isTrigger ) {
+							this._just_changed = false;
+							jQuery.event.simulate( "change", this, event, true );
+						}
+					});
+				}
+				return false;
+			}
+			// Delegated event; lazy-add a change handler on descendant inputs
+			jQuery.event.add( this, "beforeactivate._change", function( e ) {
+				var elem = e.target;
+
+				if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
+					jQuery.event.add( elem, "change._change", function( event ) {
+						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+							jQuery.event.simulate( "change", this.parentNode, event, true );
+						}
+					});
+					elem._change_attached = true;
+				}
+			});
+		},
+
+		handle: function( event ) {
+			var elem = event.target;
+
+			// Swallow native change events from checkbox/radio, we already triggered them above
+			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+				return event.handleObj.handler.apply( this, arguments );
+			}
+		},
+
+		teardown: function() {
+			jQuery.event.remove( this, "._change" );
+
+			return rformElems.test( this.nodeName );
+		}
+	};
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+		// Attach a single capturing handler while someone wants focusin/focusout
+		var attaches = 0,
+			handler = function( event ) {
+				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+			};
+
+		jQuery.event.special[ fix ] = {
+			setup: function() {
+				if ( attaches++ === 0 ) {
+					document.addEventListener( orig, handler, true );
+				}
+			},
+			teardown: function() {
+				if ( --attaches === 0 ) {
+					document.removeEventListener( orig, handler, true );
+				}
+			}
+		};
+	});
+}
+
+jQuery.fn.extend({
+
+	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+		var origFn, type;
+
+		// Types can be a map of types/handlers
+		if ( typeof types === "object" ) {
+			// ( types-Object, selector, data )
+			if ( typeof selector !== "string" ) { // && selector != null
+				// ( types-Object, data )
+				data = data || selector;
+				selector = undefined;
+			}
+			for ( type in types ) {
+				this.on( type, selector, data, types[ type ], one );
+			}
+			return this;
+		}
+
+		if ( data == null && fn == null ) {
+			// ( types, fn )
+			fn = selector;
+			data = selector = undefined;
+		} else if ( fn == null ) {
+			if ( typeof selector === "string" ) {
+				// ( types, selector, fn )
+				fn = data;
+				data = undefined;
+			} else {
+				// ( types, data, fn )
+				fn = data;
+				data = selector;
+				selector = undefined;
+			}
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		} else if ( !fn ) {
+			return this;
+		}
+
+		if ( one === 1 ) {
+			origFn = fn;
+			fn = function( event ) {
+				// Can use an empty set, since event contains the info
+				jQuery().off( event );
+				return origFn.apply( this, arguments );
+			};
+			// Use same guid so caller can remove using origFn
+			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+		}
+		return this.each( function() {
+			jQuery.event.add( this, types, fn, data, selector );
+		});
+	},
+	one: function( types, selector, data, fn ) {
+		return this.on( types, selector, data, fn, 1 );
+	},
+	off: function( types, selector, fn ) {
+		if ( types && types.preventDefault && types.handleObj ) {
+			// ( event )  dispatched jQuery.Event
+			var handleObj = types.handleObj;
+			jQuery( types.delegateTarget ).off(
+				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+				handleObj.selector,
+				handleObj.handler
+			);
+			return this;
+		}
+		if ( typeof types === "object" ) {
+			// ( types-object [, selector] )
+			for ( var type in types ) {
+				this.off( type, selector, types[ type ] );
+			}
+			return this;
+		}
+		if ( selector === false || typeof selector === "function" ) {
+			// ( types [, fn] )
+			fn = selector;
+			selector = undefined;
+		}
+		if ( fn === false ) {
+			fn = returnFalse;
+		}
+		return this.each(function() {
+			jQuery.event.remove( this, types, fn, selector );
+		});
+	},
+
+	bind: function( types, data, fn ) {
+		return this.on( types, null, data, fn );
+	},
+	unbind: function( types, fn ) {
+		return this.off( types, null, fn );
+	},
+
+	live: function( types, data, fn ) {
+		jQuery( this.context ).on( types, this.selector, data, fn );
+		return this;
+	},
+	die: function( types, fn ) {
+		jQuery( this.context ).off( types, this.selector || "**", fn );
+		return this;
+	},
+
+	delegate: function( selector, types, data, fn ) {
+		return this.on( types, selector, data, fn );
+	},
+	undelegate: function( selector, types, fn ) {
+		// ( namespace ) or ( selector, types [, fn] )
+		return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
+	},
+
+	trigger: function( type, data ) {
+		return this.each(function() {
+			jQuery.event.trigger( type, data, this );
+		});
+	},
+	triggerHandler: function( type, data ) {
+		if ( this[0] ) {
+			return jQuery.event.trigger( type, data, this[0], true );
+		}
+	},
+
+	toggle: function( fn ) {
+		// Save reference to arguments for access in closure
+		var args = arguments,
+			guid = fn.guid || jQuery.guid++,
+			i = 0,
+			toggler = function( event ) {
+				// Figure out which function to execute
+				var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+				jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+				// Make sure that clicks stop
+				event.preventDefault();
+
+				// and execute the function
+				return args[ lastToggle ].apply( this, arguments ) || false;
+			};
+
+		// link all the functions, so any of them can unbind this click handler
+		toggler.guid = guid;
+		while ( i < args.length ) {
+			args[ i++ ].guid = guid;
+		}
+
+		return this.click( toggler );
+	},
+
+	hover: function( fnOver, fnOut ) {
+		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+	}
+});
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+	// Handle event binding
+	jQuery.fn[ name ] = function( data, fn ) {
+		if ( fn == null ) {
+			fn = data;
+			data = null;
+		}
+
+		return arguments.length > 0 ?
+			this.on( name, null, data, fn ) :
+			this.trigger( name );
+	};
+
+	if ( jQuery.attrFn ) {
+		jQuery.attrFn[ name ] = true;
+	}
+
+	if ( rkeyEvent.test( name ) ) {
+		jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+	}
+
+	if ( rmouseEvent.test( name ) ) {
+		jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+	}
+});
+
+
+
+/*
+ * Sizzle CSS Selector Engine
+ *  Copyright 2011, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+	expando = "sizcache" + (Math.random() + '').replace('.', ''),
+	done = 0,
+	toString = Object.prototype.toString,
+	hasDuplicate = false,
+	baseHasDuplicate = true,
+	rBackslash = /\\/g,
+	rReturn = /\r\n/g,
+	rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+//   Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+	baseHasDuplicate = false;
+	return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+	results = results || [];
+	context = context || document;
+
+	var origContext = context;
+
+	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+		return [];
+	}
+
+	if ( !selector || typeof selector !== "string" ) {
+		return results;
+	}
+
+	var m, set, checkSet, extra, ret, cur, pop, i,
+		prune = true,
+		contextXML = Sizzle.isXML( context ),
+		parts = [],
+		soFar = selector;
+
+	// Reset the position of the chunker regexp (start from head)
+	do {
+		chunker.exec( "" );
+		m = chunker.exec( soFar );
+
+		if ( m ) {
+			soFar = m[3];
+
+			parts.push( m[1] );
+
+			if ( m[2] ) {
+				extra = m[3];
+				break;
+			}
+		}
+	} while ( m );
+
+	if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+			set = posProcess( parts[0] + parts[1], context, seed );
+
+		} else {
+			set = Expr.relative[ parts[0] ] ?
+				[ context ] :
+				Sizzle( parts.shift(), context );
+
+			while ( parts.length ) {
+				selector = parts.shift();
+
+				if ( Expr.relative[ selector ] ) {
+					selector += parts.shift();
+				}
+
+				set = posProcess( selector, set, seed );
+			}
+		}
+
+	} else {
+		// Take a shortcut and set the context if the root selector is an ID
+		// (but not if it'll be faster if the inner selector is an ID)
+		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+			ret = Sizzle.find( parts.shift(), context, contextXML );
+			context = ret.expr ?
+				Sizzle.filter( ret.expr, ret.set )[0] :
+				ret.set[0];
+		}
+
+		if ( context ) {
+			ret = seed ?
+				{ expr: parts.pop(), set: makeArray(seed) } :
+				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+			set = ret.expr ?
+				Sizzle.filter( ret.expr, ret.set ) :
+				ret.set;
+
+			if ( parts.length > 0 ) {
+				checkSet = makeArray( set );
+
+			} else {
+				prune = false;
+			}
+
+			while ( parts.length ) {
+				cur = parts.pop();
+				pop = cur;
+
+				if ( !Expr.relative[ cur ] ) {
+					cur = "";
+				} else {
+					pop = parts.pop();
+				}
+
+				if ( pop == null ) {
+					pop = context;
+				}
+
+				Expr.relative[ cur ]( checkSet, pop, contextXML );
+			}
+
+		} else {
+			checkSet = parts = [];
+		}
+	}
+
+	if ( !checkSet ) {
+		checkSet = set;
+	}
+
+	if ( !checkSet ) {
+		Sizzle.error( cur || selector );
+	}
+
+	if ( toString.call(checkSet) === "[object Array]" ) {
+		if ( !prune ) {
+			results.push.apply( results, checkSet );
+
+		} else if ( context && context.nodeType === 1 ) {
+			for ( i = 0; checkSet[i] != null; i++ ) {
+				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+					results.push( set[i] );
+				}
+			}
+
+		} else {
+			for ( i = 0; checkSet[i] != null; i++ ) {
+				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+					results.push( set[i] );
+				}
+			}
+		}
+
+	} else {
+		makeArray( checkSet, results );
+	}
+
+	if ( extra ) {
+		Sizzle( extra, origContext, results, seed );
+		Sizzle.uniqueSort( results );
+	}
+
+	return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+	if ( sortOrder ) {
+		hasDuplicate = baseHasDuplicate;
+		results.sort( sortOrder );
+
+		if ( hasDuplicate ) {
+			for ( var i = 1; i < results.length; i++ ) {
+				if ( results[i] === results[ i - 1 ] ) {
+					results.splice( i--, 1 );
+				}
+			}
+		}
+	}
+
+	return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+	return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+	return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+	var set, i, len, match, type, left;
+
+	if ( !expr ) {
+		return [];
+	}
+
+	for ( i = 0, len = Expr.order.length; i < len; i++ ) {
+		type = Expr.order[i];
+
+		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+			left = match[1];
+			match.splice( 1, 1 );
+
+			if ( left.substr( left.length - 1 ) !== "\\" ) {
+				match[1] = (match[1] || "").replace( rBackslash, "" );
+				set = Expr.find[ type ]( match, context, isXML );
+
+				if ( set != null ) {
+					expr = expr.replace( Expr.match[ type ], "" );
+					break;
+				}
+			}
+		}
+	}
+
+	if ( !set ) {
+		set = typeof context.getElementsByTagName !== "undefined" ?
+			context.getElementsByTagName( "*" ) :
+			[];
+	}
+
+	return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+	var match, anyFound,
+		type, found, item, filter, left,
+		i, pass,
+		old = expr,
+		result = [],
+		curLoop = set,
+		isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+	while ( expr && set.length ) {
+		for ( type in Expr.filter ) {
+			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+				filter = Expr.filter[ type ];
+				left = match[1];
+
+				anyFound = false;
+
+				match.splice(1,1);
+
+				if ( left.substr( left.length - 1 ) === "\\" ) {
+					continue;
+				}
+
+				if ( curLoop === result ) {
+					result = [];
+				}
+
+				if ( Expr.preFilter[ type ] ) {
+					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+					if ( !match ) {
+						anyFound = found = true;
+
+					} else if ( match === true ) {
+						continue;
+					}
+				}
+
+				if ( match ) {
+					for ( i = 0; (item = curLoop[i]) != null; i++ ) {
+						if ( item ) {
+							found = filter( item, match, i, curLoop );
+							pass = not ^ found;
+
+							if ( inplace && found != null ) {
+								if ( pass ) {
+									anyFound = true;
+
+								} else {
+									curLoop[i] = false;
+								}
+
+							} else if ( pass ) {
+								result.push( item );
+								anyFound = true;
+							}
+						}
+					}
+				}
+
+				if ( found !== undefined ) {
+					if ( !inplace ) {
+						curLoop = result;
+					}
+
+					expr = expr.replace( Expr.match[ type ], "" );
+
+					if ( !anyFound ) {
+						return [];
+					}
+
+					break;
+				}
+			}
+		}
+
+		// Improper expression
+		if ( expr === old ) {
+			if ( anyFound == null ) {
+				Sizzle.error( expr );
+
+			} else {
+				break;
+			}
+		}
+
+		old = expr;
+	}
+
+	return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+	throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Utility function for retreiving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+var getText = Sizzle.getText = function( elem ) {
+    var i, node,
+		nodeType = elem.nodeType,
+		ret = "";
+
+	if ( nodeType ) {
+		if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+			// Use textContent || innerText for elements
+			if ( typeof elem.textContent === 'string' ) {
+				return elem.textContent;
+			} else if ( typeof elem.innerText === 'string' ) {
+				// Replace IE's carriage returns
+				return elem.innerText.replace( rReturn, '' );
+			} else {
+				// Traverse it's children
+				for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+					ret += getText( elem );
+				}
+			}
+		} else if ( nodeType === 3 || nodeType === 4 ) {
+			return elem.nodeValue;
+		}
+	} else {
+
+		// If no nodeType, this is expected to be an array
+		for ( i = 0; (node = elem[i]); i++ ) {
+			// Do not traverse comment nodes
+			if ( node.nodeType !== 8 ) {
+				ret += getText( node );
+			}
+		}
+	}
+	return ret;
+};
+
+var Expr = Sizzle.selectors = {
+	order: [ "ID", "NAME", "TAG" ],
+
+	match: {
+		ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+		CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+		TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+		CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+		PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+	},
+
+	leftMatch: {},
+
+	attrMap: {
+		"class": "className",
+		"for": "htmlFor"
+	},
+
+	attrHandle: {
+		href: function( elem ) {
+			return elem.getAttribute( "href" );
+		},
+		type: function( elem ) {
+			return elem.getAttribute( "type" );
+		}
+	},
+
+	relative: {
+		"+": function(checkSet, part){
+			var isPartStr = typeof part === "string",
+				isTag = isPartStr && !rNonWord.test( part ),
+				isPartStrNotTag = isPartStr && !isTag;
+
+			if ( isTag ) {
+				part = part.toLowerCase();
+			}
+
+			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+				if ( (elem = checkSet[i]) ) {
+					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+						elem || false :
+						elem === part;
+				}
+			}
+
+			if ( isPartStrNotTag ) {
+				Sizzle.filter( part, checkSet, true );
+			}
+		},
+
+		">": function( checkSet, part ) {
+			var elem,
+				isPartStr = typeof part === "string",
+				i = 0,
+				l = checkSet.length;
+
+			if ( isPartStr && !rNonWord.test( part ) ) {
+				part = part.toLowerCase();
+
+				for ( ; i < l; i++ ) {
+					elem = checkSet[i];
+
+					if ( elem ) {
+						var parent = elem.parentNode;
+						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+					}
+				}
+
+			} else {
+				for ( ; i < l; i++ ) {
+					elem = checkSet[i];
+
+					if ( elem ) {
+						checkSet[i] = isPartStr ?
+							elem.parentNode :
+							elem.parentNode === part;
+					}
+				}
+
+				if ( isPartStr ) {
+					Sizzle.filter( part, checkSet, true );
+				}
+			}
+		},
+
+		"": function(checkSet, part, isXML){
+			var nodeCheck,
+				doneName = done++,
+				checkFn = dirCheck;
+
+			if ( typeof part === "string" && !rNonWord.test( part ) ) {
+				part = part.toLowerCase();
+				nodeCheck = part;
+				checkFn = dirNodeCheck;
+			}
+
+			checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+		},
+
+		"~": function( checkSet, part, isXML ) {
+			var nodeCheck,
+				doneName = done++,
+				checkFn = dirCheck;
+
+			if ( typeof part === "string" && !rNonWord.test( part ) ) {
+				part = part.toLowerCase();
+				nodeCheck = part;
+				checkFn = dirNodeCheck;
+			}
+
+			checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+		}
+	},
+
+	find: {
+		ID: function( match, context, isXML ) {
+			if ( typeof context.getElementById !== "undefined" && !isXML ) {
+				var m = context.getElementById(match[1]);
+				// Check parentNode to catch when Blackberry 4.6 returns
+				// nodes that are no longer in the document #6963
+				return m && m.parentNode ? [m] : [];
+			}
+		},
+
+		NAME: function( match, context ) {
+			if ( typeof context.getElementsByName !== "undefined" ) {
+				var ret = [],
+					results = context.getElementsByName( match[1] );
+
+				for ( var i = 0, l = results.length; i < l; i++ ) {
+					if ( results[i].getAttribute("name") === match[1] ) {
+						ret.push( results[i] );
+					}
+				}
+
+				return ret.length === 0 ? null : ret;
+			}
+		},
+
+		TAG: function( match, context ) {
+			if ( typeof context.getElementsByTagName !== "undefined" ) {
+				return context.getElementsByTagName( match[1] );
+			}
+		}
+	},
+	preFilter: {
+		CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+			match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+			if ( isXML ) {
+				return match;
+			}
+
+			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+				if ( elem ) {
+					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+						if ( !inplace ) {
+							result.push( elem );
+						}
+
+					} else if ( inplace ) {
+						curLoop[i] = false;
+					}
+				}
+			}
+
+			return false;
+		},
+
+		ID: function( match ) {
+			return match[1].replace( rBackslash, "" );
+		},
+
+		TAG: function( match, curLoop ) {
+			return match[1].replace( rBackslash, "" ).toLowerCase();
+		},
+
+		CHILD: function( match ) {
+			if ( match[1] === "nth" ) {
+				if ( !match[2] ) {
+					Sizzle.error( match[0] );
+				}
+
+				match[2] = match[2].replace(/^\+|\s*/g, '');
+
+				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+				var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+				// calculate the numbers (first)n+(last) including if they are negative
+				match[2] = (test[1] + (test[2] || 1)) - 0;
+				match[3] = test[3] - 0;
+			}
+			else if ( match[2] ) {
+				Sizzle.error( match[0] );
+			}
+
+			// TODO: Move to normal caching system
+			match[0] = done++;
+
+			return match;
+		},
+
+		ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+			var name = match[1] = match[1].replace( rBackslash, "" );
+
+			if ( !isXML && Expr.attrMap[name] ) {
+				match[1] = Expr.attrMap[name];
+			}
+
+			// Handle if an un-quoted value was used
+			match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+			if ( match[2] === "~=" ) {
+				match[4] = " " + match[4] + " ";
+			}
+
+			return match;
+		},
+
+		PSEUDO: function( match, curLoop, inplace, result, not ) {
+			if ( match[1] === "not" ) {
+				// If we're dealing with a complex expression, or a simple one
+				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+					match[3] = Sizzle(match[3], null, null, curLoop);
+
+				} else {
+					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+					if ( !inplace ) {
+						result.push.apply( result, ret );
+					}
+
+					return false;
+				}
+
+			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+				return true;
+			}
+
+			return match;
+		},
+
+		POS: function( match ) {
+			match.unshift( true );
+
+			return match;
+		}
+	},
+
+	filters: {
+		enabled: function( elem ) {
+			return elem.disabled === false && elem.type !== "hidden";
+		},
+
+		disabled: function( elem ) {
+			return elem.disabled === true;
+		},
+
+		checked: function( elem ) {
+			return elem.checked === true;
+		},
+
+		selected: function( elem ) {
+			// Accessing this property makes selected-by-default
+			// options in Safari work properly
+			if ( elem.parentNode ) {
+				elem.parentNode.selectedIndex;
+			}
+
+			return elem.selected === true;
+		},
+
+		parent: function( elem ) {
+			return !!elem.firstChild;
+		},
+
+		empty: function( elem ) {
+			return !elem.firstChild;
+		},
+
+		has: function( elem, i, match ) {
+			return !!Sizzle( match[3], elem ).length;
+		},
+
+		header: function( elem ) {
+			return (/h\d/i).test( elem.nodeName );
+		},
+
+		text: function( elem ) {
+			var attr = elem.getAttribute( "type" ), type = elem.type;
+			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+			// use getAttribute instead to test this case
+			return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+		},
+
+		radio: function( elem ) {
+			return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+		},
+
+		checkbox: function( elem ) {
+			return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+		},
+
+		file: function( elem ) {
+			return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+		},
+
+		password: function( elem ) {
+			return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+		},
+
+		submit: function( elem ) {
+			var name = elem.nodeName.toLowerCase();
+			return (name === "input" || name === "button") && "submit" === elem.type;
+		},
+
+		image: function( elem ) {
+			return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+		},
+
+		reset: function( elem ) {
+			var name = elem.nodeName.toLowerCase();
+			return (name === "input" || name === "button") && "reset" === elem.type;
+		},
+
+		button: function( elem ) {
+			var name = elem.nodeName.toLowerCase();
+			return name === "input" && "button" === elem.type || name === "button";
+		},
+
+		input: function( elem ) {
+			return (/input|select|textarea|button/i).test( elem.nodeName );
+		},
+
+		focus: function( elem ) {
+			return elem === elem.ownerDocument.activeElement;
+		}
+	},
+	setFilters: {
+		first: function( elem, i ) {
+			return i === 0;
+		},
+
+		last: function( elem, i, match, array ) {
+			return i === array.length - 1;
+		},
+
+		even: function( elem, i ) {
+			return i % 2 === 0;
+		},
+
+		odd: function( elem, i ) {
+			return i % 2 === 1;
+		},
+
+		lt: function( elem, i, match ) {
+			return i < match[3] - 0;
+		},
+
+		gt: function( elem, i, match ) {
+			return i > match[3] - 0;
+		},
+
+		nth: function( elem, i, match ) {
+			return match[3] - 0 === i;
+		},
+
+		eq: function( elem, i, match ) {
+			return match[3] - 0 === i;
+		}
+	},
+	filter: {
+		PSEUDO: function( elem, match, i, array ) {
+			var name = match[1],
+				filter = Expr.filters[ name ];
+
+			if ( filter ) {
+				return filter( elem, i, match, array );
+
+			} else if ( name === "contains" ) {
+				return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+			} else if ( name === "not" ) {
+				var not = match[3];
+
+				for ( var j = 0, l = not.length; j < l; j++ ) {
+					if ( not[j] === elem ) {
+						return false;
+					}
+				}
+
+				return true;
+
+			} else {
+				Sizzle.error( name );
+			}
+		},
+
+		CHILD: function( elem, match ) {
+			var first, last,
+				doneName, parent, cache,
+				count, diff,
+				type = match[1],
+				node = elem;
+
+			switch ( type ) {
+				case "only":
+				case "first":
+					while ( (node = node.previousSibling) ) {
+						if ( node.nodeType === 1 ) {
+							return false;
+						}
+					}
+
+					if ( type === "first" ) {
+						return true;
+					}
+
+					node = elem;
+
+					/* falls through */
+				case "last":
+					while ( (node = node.nextSibling) ) {
+						if ( node.nodeType === 1 ) {
+							return false;
+						}
+					}
+
+					return true;
+
+				case "nth":
+					first = match[2];
+					last = match[3];
+
+					if ( first === 1 && last === 0 ) {
+						return true;
+					}
+
+					doneName = match[0];
+					parent = elem.parentNode;
+
+					if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
+						count = 0;
+
+						for ( node = parent.firstChild; node; node = node.nextSibling ) {
+							if ( node.nodeType === 1 ) {
+								node.nodeIndex = ++count;
+							}
+						}
+
+						parent[ expando ] = doneName;
+					}
+
+					diff = elem.nodeIndex - last;
+
+					if ( first === 0 ) {
+						return diff === 0;
+
+					} else {
+						return ( diff % first === 0 && diff / first >= 0 );
+					}
+			}
+		},
+
+		ID: function( elem, match ) {
+			return elem.nodeType === 1 && elem.getAttribute("id") === match;
+		},
+
+		TAG: function( elem, match ) {
+			return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
+		},
+
+		CLASS: function( elem, match ) {
+			return (" " + (elem.className || elem.getAttribute("class")) + " ")
+				.indexOf( match ) > -1;
+		},
+
+		ATTR: function( elem, match ) {
+			var name = match[1],
+				result = Sizzle.attr ?
+					Sizzle.attr( elem, name ) :
+					Expr.attrHandle[ name ] ?
+					Expr.attrHandle[ name ]( elem ) :
+					elem[ name ] != null ?
+						elem[ name ] :
+						elem.getAttribute( name ),
+				value = result + "",
+				type = match[2],
+				check = match[4];
+
+			return result == null ?
+				type === "!=" :
+				!type && Sizzle.attr ?
+				result != null :
+				type === "=" ?
+				value === check :
+				type === "*=" ?
+				value.indexOf(check) >= 0 :
+				type === "~=" ?
+				(" " + value + " ").indexOf(check) >= 0 :
+				!check ?
+				value && result !== false :
+				type === "!=" ?
+				value !== check :
+				type === "^=" ?
+				value.indexOf(check) === 0 :
+				type === "$=" ?
+				value.substr(value.length - check.length) === check :
+				type === "|=" ?
+				value === check || value.substr(0, check.length + 1) === check + "-" :
+				false;
+		},
+
+		POS: function( elem, match, i, array ) {
+			var name = match[2],
+				filter = Expr.setFilters[ name ];
+
+			if ( filter ) {
+				return filter( elem, i, match, array );
+			}
+		}
+	}
+};
+
+var origPOS = Expr.match.POS,
+	fescape = function(all, num){
+		return "\\" + (num - 0 + 1);
+	};
+
+for ( var type in Expr.match ) {
+	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+// Expose origPOS
+// "global" as in regardless of relation to brackets/parens
+Expr.match.globalPOS = origPOS;
+
+var makeArray = function( array, results ) {
+	array = Array.prototype.slice.call( array, 0 );
+
+	if ( results ) {
+		results.push.apply( results, array );
+		return results;
+	}
+
+	return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+	makeArray = function( array, results ) {
+		var i = 0,
+			ret = results || [];
+
+		if ( toString.call(array) === "[object Array]" ) {
+			Array.prototype.push.apply( ret, array );
+
+		} else {
+			if ( typeof array.length === "number" ) {
+				for ( var l = array.length; i < l; i++ ) {
+					ret.push( array[i] );
+				}
+
+			} else {
+				for ( ; array[i]; i++ ) {
+					ret.push( array[i] );
+				}
+			}
+		}
+
+		return ret;
+	};
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+	sortOrder = function( a, b ) {
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+		}
+
+		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+			return a.compareDocumentPosition ? -1 : 1;
+		}
+
+		return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+	};
+
+} else {
+	sortOrder = function( a, b ) {
+		// The nodes are identical, we can exit early
+		if ( a === b ) {
+			hasDuplicate = true;
+			return 0;
+
+		// Fallback to using sourceIndex (in IE) if it's available on both nodes
+		} else if ( a.sourceIndex && b.sourceIndex ) {
+			return a.sourceIndex - b.sourceIndex;
+		}
+
+		var al, bl,
+			ap = [],
+			bp = [],
+			aup = a.parentNode,
+			bup = b.parentNode,
+			cur = aup;
+
+		// If the nodes are siblings (or identical) we can do a quick check
+		if ( aup === bup ) {
+			return siblingCheck( a, b );
+
+		// If no parents were found then the nodes are disconnected
+		} else if ( !aup ) {
+			return -1;
+
+		} else if ( !bup ) {
+			return 1;
+		}
+
+		// Otherwise they're somewhere else in the tree so we need
+		// to build up a full list of the parentNodes for comparison
+		while ( cur ) {
+			ap.unshift( cur );
+			cur = cur.parentNode;
+		}
+
+		cur = bup;
+
+		while ( cur ) {
+			bp.unshift( cur );
+			cur = cur.parentNode;
+		}
+
+		al = ap.length;
+		bl = bp.length;
+
+		// Start walking down the tree looking for a discrepancy
+		for ( var i = 0; i < al && i < bl; i++ ) {
+			if ( ap[i] !== bp[i] ) {
+				return siblingCheck( ap[i], bp[i] );
+			}
+		}
+
+		// We ended someplace up the tree so do a sibling check
+		return i === al ?
+			siblingCheck( a, bp[i], -1 ) :
+			siblingCheck( ap[i], b, 1 );
+	};
+
+	siblingCheck = function( a, b, ret ) {
+		if ( a === b ) {
+			return ret;
+		}
+
+		var cur = a.nextSibling;
+
+		while ( cur ) {
+			if ( cur === b ) {
+				return -1;
+			}
+
+			cur = cur.nextSibling;
+		}
+
+		return 1;
+	};
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+	// We're going to inject a fake input element with a specified name
+	var form = document.createElement("div"),
+		id = "script" + (new Date()).getTime(),
+		root = document.documentElement;
+
+	form.innerHTML = "<a name='" + id + "'/>";
+
+	// Inject it into the root element, check its status, and remove it quickly
+	root.insertBefore( form, root.firstChild );
+
+	// The workaround has to do additional checks after a getElementById
+	// Which slows things down for other browsers (hence the branching)
+	if ( document.getElementById( id ) ) {
+		Expr.find.ID = function( match, context, isXML ) {
+			if ( typeof context.getElementById !== "undefined" && !isXML ) {
+				var m = context.getElementById(match[1]);
+
+				return m ?
+					m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+						[m] :
+						undefined :
+					[];
+			}
+		};
+
+		Expr.filter.ID = function( elem, match ) {
+			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+			return elem.nodeType === 1 && node && node.nodeValue === match;
+		};
+	}
+
+	root.removeChild( form );
+
+	// release memory in IE
+	root = form = null;
+})();
+
+(function(){
+	// Check to see if the browser returns only elements
+	// when doing getElementsByTagName("*")
+
+	// Create a fake element
+	var div = document.createElement("div");
+	div.appendChild( document.createComment("") );
+
+	// Make sure no comments are found
+	if ( div.getElementsByTagName("*").length > 0 ) {
+		Expr.find.TAG = function( match, context ) {
+			var results = context.getElementsByTagName( match[1] );
+
+			// Filter out possible comments
+			if ( match[1] === "*" ) {
+				var tmp = [];
+
+				for ( var i = 0; results[i]; i++ ) {
+					if ( results[i].nodeType === 1 ) {
+						tmp.push( results[i] );
+					}
+				}
+
+				results = tmp;
+			}
+
+			return results;
+		};
+	}
+
+	// Check to see if an attribute returns normalized href attributes
+	div.innerHTML = "<a href='#'></a>";
+
+	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+			div.firstChild.getAttribute("href") !== "#" ) {
+
+		Expr.attrHandle.href = function( elem ) {
+			return elem.getAttribute( "href", 2 );
+		};
+	}
+
+	// release memory in IE
+	div = null;
+})();
+
+if ( document.querySelectorAll ) {
+	(function(){
+		var oldSizzle = Sizzle,
+			div = document.createElement("div"),
+			id = "__sizzle__";
+
+		div.innerHTML = "<p class='TEST'></p>";
+
+		// Safari can't handle uppercase or unicode characters when
+		// in quirks mode.
+		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+			return;
+		}
+
+		Sizzle = function( query, context, extra, seed ) {
+			context = context || document;
+
+			// Only use querySelectorAll on non-XML documents
+			// (ID selectors don't work in non-HTML documents)
+			if ( !seed && !Sizzle.isXML(context) ) {
+				// See if we find a selector to speed up
+				var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+
+				if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+					// Speed-up: Sizzle("TAG")
+					if ( match[1] ) {
+						return makeArray( context.getElementsByTagName( query ), extra );
+
+					// Speed-up: Sizzle(".CLASS")
+					} else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+						return makeArray( context.getElementsByClassName( match[2] ), extra );
+					}
+				}
+
+				if ( context.nodeType === 9 ) {
+					// Speed-up: Sizzle("body")
+					// The body element only exists once, optimize finding it
+					if ( query === "body" && context.body ) {
+						return makeArray( [ context.body ], extra );
+
+					// Speed-up: Sizzle("#ID")
+					} else if ( match && match[3] ) {
+						var elem = context.getElementById( match[3] );
+
+						// Check parentNode to catch when Blackberry 4.6 returns
+						// nodes that are no longer in the document #6963
+						if ( elem && elem.parentNode ) {
+							// Handle the case where IE and Opera return items
+							// by name instead of ID
+							if ( elem.id === match[3] ) {
+								return makeArray( [ elem ], extra );
+							}
+
+						} else {
+							return makeArray( [], extra );
+						}
+					}
+
+					try {
+						return makeArray( context.querySelectorAll(query), extra );
+					} catch(qsaError) {}
+
+				// qSA works strangely on Element-rooted queries
+				// We can work around this by specifying an extra ID on the root
+				// and working up from there (Thanks to Andrew Dupont for the technique)
+				// IE 8 doesn't work on object elements
+				} else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+					var oldContext = context,
+						old = context.getAttribute( "id" ),
+						nid = old || id,
+						hasParent = context.parentNode,
+						relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+					if ( !old ) {
+						context.setAttribute( "id", nid );
+					} else {
+						nid = nid.replace( /'/g, "\\$&" );
+					}
+					if ( relativeHierarchySelector && hasParent ) {
+						context = context.parentNode;
+					}
+
+					try {
+						if ( !relativeHierarchySelector || hasParent ) {
+							return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+						}
+
+					} catch(pseudoError) {
+					} finally {
+						if ( !old ) {
+							oldContext.removeAttribute( "id" );
+						}
+					}
+				}
+			}
+
+			return oldSizzle(query, context, extra, seed);
+		};
+
+		for ( var prop in oldSizzle ) {
+			Sizzle[ prop ] = oldSizzle[ prop ];
+		}
+
+		// release memory in IE
+		div = null;
+	})();
+}
+
+(function(){
+	var html = document.documentElement,
+		matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+	if ( matches ) {
+		// Check to see if it's possible to do matchesSelector
+		// on a disconnected node (IE 9 fails this)
+		var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+			pseudoWorks = false;
+
+		try {
+			// This should fail with an exception
+			// Gecko does not error, returns false instead
+			matches.call( document.documentElement, "[test!='']:sizzle" );
+
+		} catch( pseudoError ) {
+			pseudoWorks = true;
+		}
+
+		Sizzle.matchesSelector = function( node, expr ) {
+			// Make sure that attribute selectors are quoted
+			expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+			if ( !Sizzle.isXML( node ) ) {
+				try {
+					if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+						var ret = matches.call( node, expr );
+
+						// IE 9's matchesSelector returns false on disconnected nodes
+						if ( ret || !disconnectedMatch ||
+								// As well, disconnected nodes are said to be in a document
+								// fragment in IE 9, so check for that
+								node.document && node.document.nodeType !== 11 ) {
+							return ret;
+						}
+					}
+				} catch(e) {}
+			}
+
+			return Sizzle(expr, null, null, [node]).length > 0;
+		};
+	}
+})();
+
+(function(){
+	var div = document.createElement("div");
+
+	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+	// Opera can't find a second classname (in 9.6)
+	// Also, make sure that getElementsByClassName actually exists
+	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+		return;
+	}
+
+	// Safari caches class attributes, doesn't catch changes (in 3.2)
+	div.lastChild.className = "e";
+
+	if ( div.getElementsByClassName("e").length === 1 ) {
+		return;
+	}
+
+	Expr.order.splice(1, 0, "CLASS");
+	Expr.find.CLASS = function( match, context, isXML ) {
+		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+			return context.getElementsByClassName(match[1]);
+		}
+	};
+
+	// release memory in IE
+	div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+		var elem = checkSet[i];
+
+		if ( elem ) {
+			var match = false;
+
+			elem = elem[dir];
+
+			while ( elem ) {
+				if ( elem[ expando ] === doneName ) {
+					match = checkSet[elem.sizset];
+					break;
+				}
+
+				if ( elem.nodeType === 1 && !isXML ){
+					elem[ expando ] = doneName;
+					elem.sizset = i;
+				}
+
+				if ( elem.nodeName.toLowerCase() === cur ) {
+					match = elem;
+					break;
+				}
+
+				elem = elem[dir];
+			}
+
+			checkSet[i] = match;
+		}
+	}
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+		var elem = checkSet[i];
+
+		if ( elem ) {
+			var match = false;
+
+			elem = elem[dir];
+
+			while ( elem ) {
+				if ( elem[ expando ] === doneName ) {
+					match = checkSet[elem.sizset];
+					break;
+				}
+
+				if ( elem.nodeType === 1 ) {
+					if ( !isXML ) {
+						elem[ expando ] = doneName;
+						elem.sizset = i;
+					}
+
+					if ( typeof cur !== "string" ) {
+						if ( elem === cur ) {
+							match = true;
+							break;
+						}
+
+					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+						match = elem;
+						break;
+					}
+				}
+
+				elem = elem[dir];
+			}
+
+			checkSet[i] = match;
+		}
+	}
+}
+
+if ( document.documentElement.contains ) {
+	Sizzle.contains = function( a, b ) {
+		return a !== b && (a.contains ? a.contains(b) : true);
+	};
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+	Sizzle.contains = function( a, b ) {
+		return !!(a.compareDocumentPosition(b) & 16);
+	};
+
+} else {
+	Sizzle.contains = function() {
+		return false;
+	};
+}
+
+Sizzle.isXML = function( elem ) {
+	// documentElement is verified for cases where it doesn't yet exist
+	// (such as loading iframes in IE - #4833)
+	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+	return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context, seed ) {
+	var match,
+		tmpSet = [],
+		later = "",
+		root = context.nodeType ? [context] : context;
+
+	// Position selectors must be done after the filter
+	// And so must :not(positional) so we move all PSEUDOs to the end
+	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+		later += match[0];
+		selector = selector.replace( Expr.match.PSEUDO, "" );
+	}
+
+	selector = Expr.relative[selector] ? selector + "*" : selector;
+
+	for ( var i = 0, l = root.length; i < l; i++ ) {
+		Sizzle( selector, root[i], tmpSet, seed );
+	}
+
+	return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+Sizzle.selectors.attrMap = {};
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})();
+
+
+var runtil = /Until$/,
+	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+	// Note: This RegExp should be improved, or likely pulled from Sizzle
+	rmultiselector = /,/,
+	isSimple = /^.[^:#\[\.,]*$/,
+	slice = Array.prototype.slice,
+	POS = jQuery.expr.match.globalPOS,
+	// methods guaranteed to produce a unique set when starting from a unique set
+	guaranteedUnique = {
+		children: true,
+		contents: true,
+		next: true,
+		prev: true
+	};
+
+jQuery.fn.extend({
+	find: function( selector ) {
+		var self = this,
+			i, l;
+
+		if ( typeof selector !== "string" ) {
+			return jQuery( selector ).filter(function() {
+				for ( i = 0, l = self.length; i < l; i++ ) {
+					if ( jQuery.contains( self[ i ], this ) ) {
+						return true;
+					}
+				}
+			});
+		}
+
+		var ret = this.pushStack( "", "find", selector ),
+			length, n, r;
+
+		for ( i = 0, l = this.length; i < l; i++ ) {
+			length = ret.length;
+			jQuery.find( selector, this[i], ret );
+
+			if ( i > 0 ) {
+				// Make sure that the results are unique
+				for ( n = length; n < ret.length; n++ ) {
+					for ( r = 0; r < length; r++ ) {
+						if ( ret[r] === ret[n] ) {
+							ret.splice(n--, 1);
+							break;
+						}
+					}
+				}
+			}
+		}
+
+		return ret;
+	},
+
+	has: function( target ) {
+		var targets = jQuery( target );
+		return this.filter(function() {
+			for ( var i = 0, l = targets.length; i < l; i++ ) {
+				if ( jQuery.contains( this, targets[i] ) ) {
+					return true;
+				}
+			}
+		});
+	},
+
+	not: function( selector ) {
+		return this.pushStack( winnow(this, selector, false), "not", selector);
+	},
+
+	filter: function( selector ) {
+		return this.pushStack( winnow(this, selector, true), "filter", selector );
+	},
+
+	is: function( selector ) {
+		return !!selector && (
+			typeof selector === "string" ?
+				// If this is a positional selector, check membership in the returned set
+				// so $("p:first").is("p:last") won't return true for a doc with two "p".
+				POS.test( selector ) ?
+					jQuery( selector, this.context ).index( this[0] ) >= 0 :
+					jQuery.filter( selector, this ).length > 0 :
+				this.filter( selector ).length > 0 );
+	},
+
+	closest: function( selectors, context ) {
+		var ret = [], i, l, cur = this[0];
+
+		// Array (deprecated as of jQuery 1.7)
+		if ( jQuery.isArray( selectors ) ) {
+			var level = 1;
+
+			while ( cur && cur.ownerDocument && cur !== context ) {
+				for ( i = 0; i < selectors.length; i++ ) {
+
+					if ( jQuery( cur ).is( selectors[ i ] ) ) {
+						ret.push({ selector: selectors[ i ], elem: cur, level: level });
+					}
+				}
+
+				cur = cur.parentNode;
+				level++;
+			}
+
+			return ret;
+		}
+
+		// String
+		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
+				jQuery( selectors, context || this.context ) :
+				0;
+
+		for ( i = 0, l = this.length; i < l; i++ ) {
+			cur = this[i];
+
+			while ( cur ) {
+				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+					ret.push( cur );
+					break;
+
+				} else {
+					cur = cur.parentNode;
+					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
+						break;
+					}
+				}
+			}
+		}
+
+		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+		return this.pushStack( ret, "closest", selectors );
+	},
+
+	// Determine the position of an element within
+	// the matched set of elements
+	index: function( elem ) {
+
+		// No argument, return index in parent
+		if ( !elem ) {
+			return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+		}
+
+		// index in selector
+		if ( typeof elem === "string" ) {
+			return jQuery.inArray( this[0], jQuery( elem ) );
+		}
+
+		// Locate the position of the desired element
+		return jQuery.inArray(
+			// If it receives a jQuery object, the first element is used
+			elem.jquery ? elem[0] : elem, this );
+	},
+
+	add: function( selector, context ) {
+		var set = typeof selector === "string" ?
+				jQuery( selector, context ) :
+				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+			all = jQuery.merge( this.get(), set );
+
+		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+			all :
+			jQuery.unique( all ) );
+	},
+
+	andSelf: function() {
+		return this.add( this.prevObject );
+	}
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+	return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+	parent: function( elem ) {
+		var parent = elem.parentNode;
+		return parent && parent.nodeType !== 11 ? parent : null;
+	},
+	parents: function( elem ) {
+		return jQuery.dir( elem, "parentNode" );
+	},
+	parentsUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "parentNode", until );
+	},
+	next: function( elem ) {
+		return jQuery.nth( elem, 2, "nextSibling" );
+	},
+	prev: function( elem ) {
+		return jQuery.nth( elem, 2, "previousSibling" );
+	},
+	nextAll: function( elem ) {
+		return jQuery.dir( elem, "nextSibling" );
+	},
+	prevAll: function( elem ) {
+		return jQuery.dir( elem, "previousSibling" );
+	},
+	nextUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "nextSibling", until );
+	},
+	prevUntil: function( elem, i, until ) {
+		return jQuery.dir( elem, "previousSibling", until );
+	},
+	siblings: function( elem ) {
+		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+	},
+	children: function( elem ) {
+		return jQuery.sibling( elem.firstChild );
+	},
+	contents: function( elem ) {
+		return jQuery.nodeName( elem, "iframe" ) ?
+			elem.contentDocument || elem.contentWindow.document :
+			jQuery.makeArray( elem.childNodes );
+	}
+}, function( name, fn ) {
+	jQuery.fn[ name ] = function( until, selector ) {
+		var ret = jQuery.map( this, fn, until );
+
+		if ( !runtil.test( name ) ) {
+			selector = until;
+		}
+
+		if ( selector && typeof selector === "string" ) {
+			ret = jQuery.filter( selector, ret );
+		}
+
+		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+			ret = ret.reverse();
+		}
+
+		return this.pushStack( ret, name, slice.call( arguments ).join(",") );
+	};
+});
+
+jQuery.extend({
+	filter: function( expr, elems, not ) {
+		if ( not ) {
+			expr = ":not(" + expr + ")";
+		}
+
+		return elems.length === 1 ?
+			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+			jQuery.find.matches(expr, elems);
+	},
+
+	dir: function( elem, dir, until ) {
+		var matched = [],
+			cur = elem[ dir ];
+
+		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+			if ( cur.nodeType === 1 ) {
+				matched.push( cur );
+			}
+			cur = cur[dir];
+		}
+		return matched;
+	},
+
+	nth: function( cur, result, dir, elem ) {
+		result = result || 1;
+		var num = 0;
+
+		for ( ; cur; cur = cur[dir] ) {
+			if ( cur.nodeType === 1 && ++num === result ) {
+				break;
+			}
+		}
+
+		return cur;
+	},
+
+	sibling: function( n, elem ) {
+		var r = [];
+
+		for ( ; n; n = n.nextSibling ) {
+			if ( n.nodeType === 1 && n !== elem ) {
+				r.push( n );
+			}
+		}
+
+		return r;
+	}
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+	// Can't pass null or undefined to indexOf in Firefox 4
+	// Set to 0 to skip string check
+	qualifier = qualifier || 0;
+
+	if ( jQuery.isFunction( qualifier ) ) {
+		return jQuery.grep(elements, function( elem, i ) {
+			var retVal = !!qualifier.call( elem, i, elem );
+			return retVal === keep;
+		});
+
+	} else if ( qualifier.nodeType ) {
+		return jQuery.grep(elements, function( elem, i ) {
+			return ( elem === qualifier ) === keep;
+		});
+
+	} else if ( typeof qualifier === "string" ) {
+		var filtered = jQuery.grep(elements, function( elem ) {
+			return elem.nodeType === 1;
+		});
+
+		if ( isSimple.test( qualifier ) ) {
+			return jQuery.filter(qualifier, filtered, !keep);
+		} else {
+			qualifier = jQuery.filter( qualifier, filtered );
+		}
+	}
+
+	return jQuery.grep(elements, function( elem, i ) {
+		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+	});
+}
+
+
+
+
+function createSafeFragment( document ) {
+	var list = nodeNames.split( "|" ),
+	safeFrag = document.createDocumentFragment();
+
+	if ( safeFrag.createElement ) {
+		while ( list.length ) {
+			safeFrag.createElement(
+				list.pop()
+			);
+		}
+	}
+	return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+	rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+	rleadingWhitespace = /^\s+/,
+	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+	rtagName = /<([\w:]+)/,
+	rtbody = /<tbody/i,
+	rhtml = /<|&#?\w+;/,
+	rnoInnerhtml = /<(?:script|style)/i,
+	rnocache = /<(?:script|object|embed|option|style)/i,
+	rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+	// checked="checked" or checked
+	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+	rscriptType = /\/(java|ecma)script/i,
+	rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
+	wrapMap = {
+		option: [ 1, "<select multiple='multiple'>", "</select>" ],
+		legend: [ 1, "<fieldset>", "</fieldset>" ],
+		thead: [ 1, "<table>", "</table>" ],
+		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+		area: [ 1, "<map>", "</map>" ],
+		_default: [ 0, "", "" ]
+	},
+	safeFragment = createSafeFragment( document );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+	wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+	text: function( value ) {
+		return jQuery.access( this, function( value ) {
+			return value === undefined ?
+				jQuery.text( this ) :
+				this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+		}, null, value, arguments.length );
+	},
+
+	wrapAll: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapAll( html.call(this, i) );
+			});
+		}
+
+		if ( this[0] ) {
+			// The elements to wrap the target around
+			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+			if ( this[0].parentNode ) {
+				wrap.insertBefore( this[0] );
+			}
+
+			wrap.map(function() {
+				var elem = this;
+
+				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+					elem = elem.firstChild;
+				}
+
+				return elem;
+			}).append( this );
+		}
+
+		return this;
+	},
+
+	wrapInner: function( html ) {
+		if ( jQuery.isFunction( html ) ) {
+			return this.each(function(i) {
+				jQuery(this).wrapInner( html.call(this, i) );
+			});
+		}
+
+		return this.each(function() {
+			var self = jQuery( this ),
+				contents = self.contents();
+
+			if ( contents.length ) {
+				contents.wrapAll( html );
+
+			} else {
+				self.append( html );
+			}
+		});
+	},
+
+	wrap: function( html ) {
+		var isFunction = jQuery.isFunction( html );
+
+		return this.each(function(i) {
+			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+		});
+	},
+
+	unwrap: function() {
+		return this.parent().each(function() {
+			if ( !jQuery.nodeName( this, "body" ) ) {
+				jQuery( this ).replaceWith( this.childNodes );
+			}
+		}).end();
+	},
+
+	append: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 ) {
+				this.appendChild( elem );
+			}
+		});
+	},
+
+	prepend: function() {
+		return this.domManip(arguments, true, function( elem ) {
+			if ( this.nodeType === 1 ) {
+				this.insertBefore( elem, this.firstChild );
+			}
+		});
+	},
+
+	before: function() {
+		if ( this[0] && this[0].parentNode ) {
+			return this.domManip(arguments, false, function( elem ) {
+				this.parentNode.insertBefore( elem, this );
+			});
+		} else if ( arguments.length ) {
+			var set = jQuery.clean( arguments );
+			set.push.apply( set, this.toArray() );
+			return this.pushStack( set, "before", arguments );
+		}
+	},
+
+	after: function() {
+		if ( this[0] && this[0].parentNode ) {
+			return this.domManip(arguments, false, function( elem ) {
+				this.parentNode.insertBefore( elem, this.nextSibling );
+			});
+		} else if ( arguments.length ) {
+			var set = this.pushStack( this, "after", arguments );
+			set.push.apply( set, jQuery.clean(arguments) );
+			return set;
+		}
+	},
+
+	// keepData is for internal use only--do not document
+	remove: function( selector, keepData ) {
+		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+			if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+				if ( !keepData && elem.nodeType === 1 ) {
+					jQuery.cleanData( elem.getElementsByTagName("*") );
+					jQuery.cleanData( [ elem ] );
+				}
+
+				if ( elem.parentNode ) {
+					elem.parentNode.removeChild( elem );
+				}
+			}
+		}
+
+		return this;
+	},
+
+	empty: function() {
+		for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+			// Remove element nodes and prevent memory leaks
+			if ( elem.nodeType === 1 ) {
+				jQuery.cleanData( elem.getElementsByTagName("*") );
+			}
+
+			// Remove any remaining nodes
+			while ( elem.firstChild ) {
+				elem.removeChild( elem.firstChild );
+			}
+		}
+
+		return this;
+	},
+
+	clone: function( dataAndEvents, deepDataAndEvents ) {
+		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+		return this.map( function () {
+			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+		});
+	},
+
+	html: function( value ) {
+		return jQuery.access( this, function( value ) {
+			var elem = this[0] || {},
+				i = 0,
+				l = this.length;
+
+			if ( value === undefined ) {
+				return elem.nodeType === 1 ?
+					elem.innerHTML.replace( rinlinejQuery, "" ) :
+					null;
+			}
+
+
+			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+				( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+				!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+				value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+				try {
+					for (; i < l; i++ ) {
+						// Remove element nodes and prevent memory leaks
+						elem = this[i] || {};
+						if ( elem.nodeType === 1 ) {
+							jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+							elem.innerHTML = value;
+						}
+					}
+
+					elem = 0;
+
+				// If using innerHTML throws an exception, use the fallback method
+				} catch(e) {}
+			}
+
+			if ( elem ) {
+				this.empty().append( value );
+			}
+		}, null, value, arguments.length );
+	},
+
+	replaceWith: function( value ) {
+		if ( this[0] && this[0].parentNode ) {
+			// Make sure that the elements are removed from the DOM before they are inserted
+			// this can help fix replacing a parent with child elements
+			if ( jQuery.isFunction( value ) ) {
+				return this.each(function(i) {
+					var self = jQuery(this), old = self.html();
+					self.replaceWith( value.call( this, i, old ) );
+				});
+			}
+
+			if ( typeof value !== "string" ) {
+				value = jQuery( value ).detach();
+			}
+
+			return this.each(function() {
+				var next = this.nextSibling,
+					parent = this.parentNode;
+
+				jQuery( this ).remove();
+
+				if ( next ) {
+					jQuery(next).before( value );
+				} else {
+					jQuery(parent).append( value );
+				}
+			});
+		} else {
+			return this.length ?
+				this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+				this;
+		}
+	},
+
+	detach: function( selector ) {
+		return this.remove( selector, true );
+	},
+
+	domManip: function( args, table, callback ) {
+		var results, first, fragment, parent,
+			value = args[0],
+			scripts = [];
+
+		// We can't cloneNode fragments that contain checked, in WebKit
+		if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+			return this.each(function() {
+				jQuery(this).domManip( args, table, callback, true );
+			});
+		}
+
+		if ( jQuery.isFunction(value) ) {
+			return this.each(function(i) {
+				var self = jQuery(this);
+				args[0] = value.call(this, i, table ? self.html() : undefined);
+				self.domManip( args, table, callback );
+			});
+		}
+
+		if ( this[0] ) {
+			parent = value && value.parentNode;
+
+			// If we're in a fragment, just use that instead of building a new one
+			if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+				results = { fragment: parent };
+
+			} else {
+				results = jQuery.buildFragment( args, this, scripts );
+			}
+
+			fragment = results.fragment;
+
+			if ( fragment.childNodes.length === 1 ) {
+				first = fragment = fragment.firstChild;
+			} else {
+				first = fragment.firstChild;
+			}
+
+			if ( first ) {
+				table = table && jQuery.nodeName( first, "tr" );
+
+				for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
+					callback.call(
+						table ?
+							root(this[i], first) :
+							this[i],
+						// Make sure that we do not leak memory by inadvertently discarding
+						// the original fragment (which might have attached data) instead of
+						// using it; in addition, use the original fragment object for the last
+						// item instead of first because it can end up being emptied incorrectly
+						// in certain situations (Bug #8070).
+						// Fragments from the fragment cache must always be cloned and never used
+						// in place.
+						results.cacheable || ( l > 1 && i < lastIndex ) ?
+							jQuery.clone( fragment, true, true ) :
+							fragment
+					);
+				}
+			}
+
+			if ( scripts.length ) {
+				jQuery.each( scripts, function( i, elem ) {
+					if ( elem.src ) {
+						jQuery.ajax({
+							type: "GET",
+							global: false,
+							url: elem.src,
+							async: false,
+							dataType: "script"
+						});
+					} else {
+						jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
+					}
+
+					if ( elem.parentNode ) {
+						elem.parentNode.removeChild( elem );
+					}
+				});
+			}
+		}
+
+		return this;
+	}
+});
+
+function root( elem, cur ) {
+	return jQuery.nodeName(elem, "table") ?
+		(elem.getElementsByTagName("tbody")[0] ||
+		elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+		elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+
+	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+		return;
+	}
+
+	var type, i, l,
+		oldData = jQuery._data( src ),
+		curData = jQuery._data( dest, oldData ),
+		events = oldData.events;
+
+	if ( events ) {
+		delete curData.handle;
+		curData.events = {};
+
+		for ( type in events ) {
+			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+				jQuery.event.add( dest, type, events[ type ][ i ] );
+			}
+		}
+	}
+
+	// make the cloned public data object a copy from the original
+	if ( curData.data ) {
+		curData.data = jQuery.extend( {}, curData.data );
+	}
+}
+
+function cloneFixAttributes( src, dest ) {
+	var nodeName;
+
+	// We do not need to do anything for non-Elements
+	if ( dest.nodeType !== 1 ) {
+		return;
+	}
+
+	// clearAttributes removes the attributes, which we don't want,
+	// but also removes the attachEvent events, which we *do* want
+	if ( dest.clearAttributes ) {
+		dest.clearAttributes();
+	}
+
+	// mergeAttributes, in contrast, only merges back on the
+	// original attributes, not the events
+	if ( dest.mergeAttributes ) {
+		dest.mergeAttributes( src );
+	}
+
+	nodeName = dest.nodeName.toLowerCase();
+
+	// IE6-8 fail to clone children inside object elements that use
+	// the proprietary classid attribute value (rather than the type
+	// attribute) to identify the type of content to display
+	if ( nodeName === "object" ) {
+		dest.outerHTML = src.outerHTML;
+
+	} else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+		// IE6-8 fails to persist the checked state of a cloned checkbox
+		// or radio button. Worse, IE6-7 fail to give the cloned element
+		// a checked appearance if the defaultChecked value isn't also set
+		if ( src.checked ) {
+			dest.defaultChecked = dest.checked = src.checked;
+		}
+
+		// IE6-7 get confused and end up setting the value of a cloned
+		// checkbox/radio button to an empty string instead of "on"
+		if ( dest.value !== src.value ) {
+			dest.value = src.value;
+		}
+
+	// IE6-8 fails to return the selected option to the default selected
+	// state when cloning options
+	} else if ( nodeName === "option" ) {
+		dest.selected = src.defaultSelected;
+
+	// IE6-8 fails to set the defaultValue to the correct value when
+	// cloning other types of input fields
+	} else if ( nodeName === "input" || nodeName === "textarea" ) {
+		dest.defaultValue = src.defaultValue;
+
+	// IE blanks contents when cloning scripts
+	} else if ( nodeName === "script" && dest.text !== src.text ) {
+		dest.text = src.text;
+	}
+
+	// Event data gets referenced instead of copied if the expando
+	// gets copied too
+	dest.removeAttribute( jQuery.expando );
+
+	// Clear flags for bubbling special change/submit events, they must
+	// be reattached when the newly cloned events are first activated
+	dest.removeAttribute( "_submit_attached" );
+	dest.removeAttribute( "_change_attached" );
+}
+
+jQuery.buildFragment = function( args, nodes, scripts ) {
+	var fragment, cacheable, cacheresults, doc,
+	first = args[ 0 ];
+
+	// nodes may contain either an explicit document object,
+	// a jQuery collection or context object.
+	// If nodes[0] contains a valid object to assign to doc
+	if ( nodes && nodes[0] ) {
+		doc = nodes[0].ownerDocument || nodes[0];
+	}
+
+	// Ensure that an attr object doesn't incorrectly stand in as a document object
+	// Chrome and Firefox seem to allow this to occur and will throw exception
+	// Fixes #8950
+	if ( !doc.createDocumentFragment ) {
+		doc = document;
+	}
+
+	// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+	// Cloning options loses the selected state, so don't cache them
+	// IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+	// Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+	// Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+	if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
+		first.charAt(0) === "<" && !rnocache.test( first ) &&
+		(jQuery.support.checkClone || !rchecked.test( first )) &&
+		(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
+
+		cacheable = true;
+
+		cacheresults = jQuery.fragments[ first ];
+		if ( cacheresults && cacheresults !== 1 ) {
+			fragment = cacheresults;
+		}
+	}
+
+	if ( !fragment ) {
+		fragment = doc.createDocumentFragment();
+		jQuery.clean( args, doc, fragment, scripts );
+	}
+
+	if ( cacheable ) {
+		jQuery.fragments[ first ] = cacheresults ? fragment : 1;
+	}
+
+	return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+	appendTo: "append",
+	prependTo: "prepend",
+	insertBefore: "before",
+	insertAfter: "after",
+	replaceAll: "replaceWith"
+}, function( name, original ) {
+	jQuery.fn[ name ] = function( selector ) {
+		var ret = [],
+			insert = jQuery( selector ),
+			parent = this.length === 1 && this[0].parentNode;
+
+		if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+			insert[ original ]( this[0] );
+			return this;
+
+		} else {
+			for ( var i = 0, l = insert.length; i < l; i++ ) {
+				var elems = ( i > 0 ? this.clone(true) : this ).get();
+				jQuery( insert[i] )[ original ]( elems );
+				ret = ret.concat( elems );
+			}
+
+			return this.pushStack( ret, name, insert.selector );
+		}
+	};
+});
+
+function getAll( elem ) {
+	if ( typeof elem.getElementsByTagName !== "undefined" ) {
+		return elem.getElementsByTagName( "*" );
+
+	} else if ( typeof elem.querySelectorAll !== "undefined" ) {
+		return elem.querySelectorAll( "*" );
+
+	} else {
+		return [];
+	}
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+	if ( elem.type === "checkbox" || elem.type === "radio" ) {
+		elem.defaultChecked = elem.checked;
+	}
+}
+// Finds all inputs and passes them to fixDefaultChecked
+function findInputs( elem ) {
+	var nodeName = ( elem.nodeName || "" ).toLowerCase();
+	if ( nodeName === "input" ) {
+		fixDefaultChecked( elem );
+	// Skip scripts, get other children
+	} else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
+		jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+	}
+}
+
+// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
+function shimCloneNode( elem ) {
+	var div = document.createElement( "div" );
+	safeFragment.appendChild( div );
+
+	div.innerHTML = elem.outerHTML;
+	return div.firstChild;
+}
+
+jQuery.extend({
+	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+		var srcElements,
+			destElements,
+			i,
+			// IE<=8 does not properly clone detached, unknown element nodes
+			clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
+				elem.cloneNode( true ) :
+				shimCloneNode( elem );
+
+		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+			// IE copies events bound via attachEvent when using cloneNode.
+			// Calling detachEvent on the clone will also remove the events
+			// from the original. In order to get around this, we use some
+			// proprietary methods to clear the events. Thanks to MooTools
+			// guys for this hotness.
+
+			cloneFixAttributes( elem, clone );
+
+			// Using Sizzle here is crazy slow, so we use getElementsByTagName instead
+			srcElements = getAll( elem );
+			destElements = getAll( clone );
+
+			// Weird iteration because IE will replace the length property
+			// with an element if you are cloning the body and one of the
+			// elements on the page has a name or id of "length"
+			for ( i = 0; srcElements[i]; ++i ) {
+				// Ensure that the destination node is not null; Fixes #9587
+				if ( destElements[i] ) {
+					cloneFixAttributes( srcElements[i], destElements[i] );
+				}
+			}
+		}
+
+		// Copy the events from the original to the clone
+		if ( dataAndEvents ) {
+			cloneCopyEvent( elem, clone );
+
+			if ( deepDataAndEvents ) {
+				srcElements = getAll( elem );
+				destElements = getAll( clone );
+
+				for ( i = 0; srcElements[i]; ++i ) {
+					cloneCopyEvent( srcElements[i], destElements[i] );
+				}
+			}
+		}
+
+		srcElements = destElements = null;
+
+		// Return the cloned set
+		return clone;
+	},
+
+	clean: function( elems, context, fragment, scripts ) {
+		var checkScriptType, script, j,
+				ret = [];
+
+		context = context || document;
+
+		// !context.createElement fails in IE with an error but returns typeof 'object'
+		if ( typeof context.createElement === "undefined" ) {
+			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+		}
+
+		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+			if ( typeof elem === "number" ) {
+				elem += "";
+			}
+
+			if ( !elem ) {
+				continue;
+			}
+
+			// Convert html string into DOM nodes
+			if ( typeof elem === "string" ) {
+				if ( !rhtml.test( elem ) ) {
+					elem = context.createTextNode( elem );
+				} else {
+					// Fix "XHTML"-style tags in all browsers
+					elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+					// Trim whitespace, otherwise indexOf won't work as expected
+					var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
+						wrap = wrapMap[ tag ] || wrapMap._default,
+						depth = wrap[0],
+						div = context.createElement("div"),
+						safeChildNodes = safeFragment.childNodes,
+						remove;
+
+					// Append wrapper element to unknown element safe doc fragment
+					if ( context === document ) {
+						// Use the fragment we've already created for this document
+						safeFragment.appendChild( div );
+					} else {
+						// Use a fragment created with the owner document
+						createSafeFragment( context ).appendChild( div );
+					}
+
+					// Go to html and back, then peel off extra wrappers
+					div.innerHTML = wrap[1] + elem + wrap[2];
+
+					// Move to the right depth
+					while ( depth-- ) {
+						div = div.lastChild;
+					}
+
+					// Remove IE's autoinserted <tbody> from table fragments
+					if ( !jQuery.support.tbody ) {
+
+						// String was a <table>, *may* have spurious <tbody>
+						var hasBody = rtbody.test(elem),
+							tbody = tag === "table" && !hasBody ?
+								div.firstChild && div.firstChild.childNodes :
+
+								// String was a bare <thead> or <tfoot>
+								wrap[1] === "<table>" && !hasBody ?
+									div.childNodes :
+									[];
+
+						for ( j = tbody.length - 1; j >= 0 ; --j ) {
+							if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+								tbody[ j ].parentNode.removeChild( tbody[ j ] );
+							}
+						}
+					}
+
+					// IE completely kills leading whitespace when innerHTML is used
+					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+						div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+					}
+
+					elem = div.childNodes;
+
+					// Clear elements from DocumentFragment (safeFragment or otherwise)
+					// to avoid hoarding elements. Fixes #11356
+					if ( div ) {
+						div.parentNode.removeChild( div );
+
+						// Guard against -1 index exceptions in FF3.6
+						if ( safeChildNodes.length > 0 ) {
+							remove = safeChildNodes[ safeChildNodes.length - 1 ];
+
+							if ( remove && remove.parentNode ) {
+								remove.parentNode.removeChild( remove );
+							}
+						}
+					}
+				}
+			}
+
+			// Resets defaultChecked for any radios and checkboxes
+			// about to be appended to the DOM in IE 6/7 (#8060)
+			var len;
+			if ( !jQuery.support.appendChecked ) {
+				if ( elem[0] && typeof (len = elem.length) === "number" ) {
+					for ( j = 0; j < len; j++ ) {
+						findInputs( elem[j] );
+					}
+				} else {
+					findInputs( elem );
+				}
+			}
+
+			if ( elem.nodeType ) {
+				ret.push( elem );
+			} else {
+				ret = jQuery.merge( ret, elem );
+			}
+		}
+
+		if ( fragment ) {
+			checkScriptType = function( elem ) {
+				return !elem.type || rscriptType.test( elem.type );
+			};
+			for ( i = 0; ret[i]; i++ ) {
+				script = ret[i];
+				if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
+					scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );
+
+				} else {
+					if ( script.nodeType === 1 ) {
+						var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );
+
+						ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+					}
+					fragment.appendChild( script );
+				}
+			}
+		}
+
+		return ret;
+	},
+
+	cleanData: function( elems ) {
+		var data, id,
+			cache = jQuery.cache,
+			special = jQuery.event.special,
+			deleteExpando = jQuery.support.deleteExpando;
+
+		for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+			if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+				continue;
+			}
+
+			id = elem[ jQuery.expando ];
+
+			if ( id ) {
+				data = cache[ id ];
+
+				if ( data && data.events ) {
+					for ( var type in data.events ) {
+						if ( special[ type ] ) {
+							jQuery.event.remove( elem, type );
+
+						// This is a shortcut to avoid jQuery.event.remove's overhead
+						} else {
+							jQuery.removeEvent( elem, type, data.handle );
+						}
+					}
+
+					// Null the DOM reference to avoid IE6/7/8 leak (#7054)
+					if ( data.handle ) {
+						data.handle.elem = null;
+					}
+				}
+
+				if ( deleteExpando ) {
+					delete elem[ jQuery.expando ];
+
+				} else if ( elem.removeAttribute ) {
+					elem.removeAttribute( jQuery.expando );
+				}
+
+				delete cache[ id ];
+			}
+		}
+	}
+});
+
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
+	ropacity = /opacity=([^)]*)/,
+	// fixed for IE9, see #8346
+	rupper = /([A-Z]|^ms)/g,
+	rnum = /^[\-+]?(?:\d*\.)?\d+$/i,
+	rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
+	rrelNum = /^([\-+])=([\-+.\de]+)/,
+	rmargin = /^margin/,
+
+	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+
+	// order is important!
+	cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+
+	curCSS,
+
+	getComputedStyle,
+	currentStyle;
+
+jQuery.fn.css = function( name, value ) {
+	return jQuery.access( this, function( elem, name, value ) {
+		return value !== undefined ?
+			jQuery.style( elem, name, value ) :
+			jQuery.css( elem, name );
+	}, name, value, arguments.length > 1 );
+};
+
+jQuery.extend({
+	// Add in style property hooks for overriding the default
+	// behavior of getting and setting a style property
+	cssHooks: {
+		opacity: {
+			get: function( elem, computed ) {
+				if ( computed ) {
+					// We should always get a number back from opacity
+					var ret = curCSS( elem, "opacity" );
+					return ret === "" ? "1" : ret;
+
+				} else {
+					return elem.style.opacity;
+				}
+			}
+		}
+	},
+
+	// Exclude the following css properties to add px
+	cssNumber: {
+		"fillOpacity": true,
+		"fontWeight": true,
+		"lineHeight": true,
+		"opacity": true,
+		"orphans": true,
+		"widows": true,
+		"zIndex": true,
+		"zoom": true
+	},
+
+	// Add in properties whose names you wish to fix before
+	// setting or getting the value
+	cssProps: {
+		// normalize float css property
+		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+	},
+
+	// Get and set the style property on a DOM Node
+	style: function( elem, name, value, extra ) {
+		// Don't set styles on text and comment nodes
+		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+			return;
+		}
+
+		// Make sure that we're working with the right name
+		var ret, type, origName = jQuery.camelCase( name ),
+			style = elem.style, hooks = jQuery.cssHooks[ origName ];
+
+		name = jQuery.cssProps[ origName ] || origName;
+
+		// Check if we're setting a value
+		if ( value !== undefined ) {
+			type = typeof value;
+
+			// convert relative number strings (+= or -=) to relative numbers. #7345
+			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+				value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
+				// Fixes bug #9237
+				type = "number";
+			}
+
+			// Make sure that NaN and null values aren't set. See: #7116
+			if ( value == null || type === "number" && isNaN( value ) ) {
+				return;
+			}
+
+			// If a number was passed in, add 'px' to the (except for certain CSS properties)
+			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+				value += "px";
+			}
+
+			// If a hook was provided, use that value, otherwise just set the specified value
+			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+				// Fixes bug #5509
+				try {
+					style[ name ] = value;
+				} catch(e) {}
+			}
+
+		} else {
+			// If a hook was provided get the non-computed value from there
+			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+				return ret;
+			}
+
+			// Otherwise just get the value from the style object
+			return style[ name ];
+		}
+	},
+
+	css: function( elem, name, extra ) {
+		var ret, hooks;
+
+		// Make sure that we're working with the right name
+		name = jQuery.camelCase( name );
+		hooks = jQuery.cssHooks[ name ];
+		name = jQuery.cssProps[ name ] || name;
+
+		// cssFloat needs a special treatment
+		if ( name === "cssFloat" ) {
+			name = "float";
+		}
+
+		// If a hook was provided get the computed value from there
+		if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+			return ret;
+
+		// Otherwise, if a way to get the computed value exists, use that
+		} else if ( curCSS ) {
+			return curCSS( elem, name );
+		}
+	},
+
+	// A method for quickly swapping in/out CSS properties to get correct calculations
+	swap: function( elem, options, callback ) {
+		var old = {},
+			ret, name;
+
+		// Remember the old values, and insert the new ones
+		for ( name in options ) {
+			old[ name ] = elem.style[ name ];
+			elem.style[ name ] = options[ name ];
+		}
+
+		ret = callback.call( elem );
+
+		// Revert the old values
+		for ( name in options ) {
+			elem.style[ name ] = old[ name ];
+		}
+
+		return ret;
+	}
+});
+
+// DEPRECATED in 1.3, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
+
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+	getComputedStyle = function( elem, name ) {
+		var ret, defaultView, computedStyle, width,
+			style = elem.style;
+
+		name = name.replace( rupper, "-$1" ).toLowerCase();
+
+		if ( (defaultView = elem.ownerDocument.defaultView) &&
+				(computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+
+			ret = computedStyle.getPropertyValue( name );
+			if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+				ret = jQuery.style( elem, name );
+			}
+		}
+
+		// A tribute to the "awesome hack by Dean Edwards"
+		// WebKit uses "computed value (percentage if specified)" instead of "used value" for margins
+		// which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+		if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {
+			width = style.width;
+			style.width = ret;
+			ret = computedStyle.width;
+			style.width = width;
+		}
+
+		return ret;
+	};
+}
+
+if ( document.documentElement.currentStyle ) {
+	currentStyle = function( elem, name ) {
+		var left, rsLeft, uncomputed,
+			ret = elem.currentStyle && elem.currentStyle[ name ],
+			style = elem.style;
+
+		// Avoid setting ret to empty string here
+		// so we don't default to auto
+		if ( ret == null && style && (uncomputed = style[ name ]) ) {
+			ret = uncomputed;
+		}
+
+		// From the awesome hack by Dean Edwards
+		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+		// If we're not dealing with a regular pixel number
+		// but a number that has a weird ending, we need to convert it to pixels
+		if ( rnumnonpx.test( ret ) ) {
+
+			// Remember the original values
+			left = style.left;
+			rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+			// Put in the new values to get a computed value out
+			if ( rsLeft ) {
+				elem.runtimeStyle.left = elem.currentStyle.left;
+			}
+			style.left = name === "fontSize" ? "1em" : ret;
+			ret = style.pixelLeft + "px";
+
+			// Revert the changed values
+			style.left = left;
+			if ( rsLeft ) {
+				elem.runtimeStyle.left = rsLeft;
+			}
+		}
+
+		return ret === "" ? "auto" : ret;
+	};
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWidthOrHeight( elem, name, extra ) {
+
+	// Start with offset property
+	var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+		i = name === "width" ? 1 : 0,
+		len = 4;
+
+	if ( val > 0 ) {
+		if ( extra !== "border" ) {
+			for ( ; i < len; i += 2 ) {
+				if ( !extra ) {
+					val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+				}
+				if ( extra === "margin" ) {
+					val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
+				} else {
+					val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+				}
+			}
+		}
+
+		return val + "px";
+	}
+
+	// Fall back to computed then uncomputed css if necessary
+	val = curCSS( elem, name );
+	if ( val < 0 || val == null ) {
+		val = elem.style[ name ];
+	}
+
+	// Computed unit is not pixels. Stop here and return.
+	if ( rnumnonpx.test(val) ) {
+		return val;
+	}
+
+	// Normalize "", auto, and prepare for extra
+	val = parseFloat( val ) || 0;
+
+	// Add padding, border, margin
+	if ( extra ) {
+		for ( ; i < len; i += 2 ) {
+			val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+			if ( extra !== "padding" ) {
+				val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+			}
+			if ( extra === "margin" ) {
+				val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
+			}
+		}
+	}
+
+	return val + "px";
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+	jQuery.cssHooks[ name ] = {
+		get: function( elem, computed, extra ) {
+			if ( computed ) {
+				if ( elem.offsetWidth !== 0 ) {
+					return getWidthOrHeight( elem, name, extra );
+				} else {
+					return jQuery.swap( elem, cssShow, function() {
+						return getWidthOrHeight( elem, name, extra );
+					});
+				}
+			}
+		},
+
+		set: function( elem, value ) {
+			return rnum.test( value ) ?
+				value + "px" :
+				value;
+		}
+	};
+});
+
+if ( !jQuery.support.opacity ) {
+	jQuery.cssHooks.opacity = {
+		get: function( elem, computed ) {
+			// IE uses filters for opacity
+			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+				( parseFloat( RegExp.$1 ) / 100 ) + "" :
+				computed ? "1" : "";
+		},
+
+		set: function( elem, value ) {
+			var style = elem.style,
+				currentStyle = elem.currentStyle,
+				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+				filter = currentStyle && currentStyle.filter || style.filter || "";
+
+			// IE has trouble with opacity if it does not have layout
+			// Force it by setting the zoom level
+			style.zoom = 1;
+
+			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+			if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
+
+				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+				// if "filter:" is present at all, clearType is disabled, we want to avoid this
+				// style.removeAttribute is IE Only, but so apparently is this code path...
+				style.removeAttribute( "filter" );
+
+				// if there there is no filter style applied in a css rule, we are done
+				if ( currentStyle && !currentStyle.filter ) {
+					return;
+				}
+			}
+
+			// otherwise, set new filter values
+			style.filter = ralpha.test( filter ) ?
+				filter.replace( ralpha, opacity ) :
+				filter + " " + opacity;
+		}
+	};
+}
+
+jQuery(function() {
+	// This hook cannot be added until DOM ready because the support test
+	// for it is not run until after DOM ready
+	if ( !jQuery.support.reliableMarginRight ) {
+		jQuery.cssHooks.marginRight = {
+			get: function( elem, computed ) {
+				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+				// Work around by temporarily setting element display to inline-block
+				return jQuery.swap( elem, { "display": "inline-block" }, function() {
+					if ( computed ) {
+						return curCSS( elem, "margin-right" );
+					} else {
+						return elem.style.marginRight;
+					}
+				});
+			}
+		};
+	}
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.hidden = function( elem ) {
+		var width = elem.offsetWidth,
+			height = elem.offsetHeight;
+
+		return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+	};
+
+	jQuery.expr.filters.visible = function( elem ) {
+		return !jQuery.expr.filters.hidden( elem );
+	};
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+	margin: "",
+	padding: "",
+	border: "Width"
+}, function( prefix, suffix ) {
+
+	jQuery.cssHooks[ prefix + suffix ] = {
+		expand: function( value ) {
+			var i,
+
+				// assumes a single number if not a string
+				parts = typeof value === "string" ? value.split(" ") : [ value ],
+				expanded = {};
+
+			for ( i = 0; i < 4; i++ ) {
+				expanded[ prefix + cssExpand[ i ] + suffix ] =
+					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+			}
+
+			return expanded;
+		}
+	};
+});
+
+
+
+
+var r20 = /%20/g,
+	rbracket = /\[\]$/,
+	rCRLF = /\r?\n/g,
+	rhash = /#.*$/,
+	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+	rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+	// #7653, #8125, #8152: local protocol detection
+	rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+	rnoContent = /^(?:GET|HEAD)$/,
+	rprotocol = /^\/\//,
+	rquery = /\?/,
+	rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+	rselectTextarea = /^(?:select|textarea)/i,
+	rspacesAjax = /\s+/,
+	rts = /([?&])_=[^&]*/,
+	rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+	// Keep a copy of the old load method
+	_load = jQuery.fn.load,
+
+	/* Prefilters
+	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+	 * 2) These are called:
+	 *    - BEFORE asking for a transport
+	 *    - AFTER param serialization (s.data is a string if s.processData is true)
+	 * 3) key is the dataType
+	 * 4) the catchall symbol "*" can be used
+	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+	 */
+	prefilters = {},
+
+	/* Transports bindings
+	 * 1) key is the dataType
+	 * 2) the catchall symbol "*" can be used
+	 * 3) selection will start with transport dataType and THEN go to "*" if needed
+	 */
+	transports = {},
+
+	// Document location
+	ajaxLocation,
+
+	// Document location segments
+	ajaxLocParts,
+
+	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+	allTypes = ["*/"] + ["*"];
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+	ajaxLocation = location.href;
+} catch( e ) {
+	// Use the href attribute of an A element
+	// since IE will modify it given document.location
+	ajaxLocation = document.createElement( "a" );
+	ajaxLocation.href = "";
+	ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+	// dataTypeExpression is optional and defaults to "*"
+	return function( dataTypeExpression, func ) {
+
+		if ( typeof dataTypeExpression !== "string" ) {
+			func = dataTypeExpression;
+			dataTypeExpression = "*";
+		}
+
+		if ( jQuery.isFunction( func ) ) {
+			var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+				i = 0,
+				length = dataTypes.length,
+				dataType,
+				list,
+				placeBefore;
+
+			// For each dataType in the dataTypeExpression
+			for ( ; i < length; i++ ) {
+				dataType = dataTypes[ i ];
+				// We control if we're asked to add before
+				// any existing element
+				placeBefore = /^\+/.test( dataType );
+				if ( placeBefore ) {
+					dataType = dataType.substr( 1 ) || "*";
+				}
+				list = structure[ dataType ] = structure[ dataType ] || [];
+				// then we add to the structure accordingly
+				list[ placeBefore ? "unshift" : "push" ]( func );
+			}
+		}
+	};
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+		dataType /* internal */, inspected /* internal */ ) {
+
+	dataType = dataType || options.dataTypes[ 0 ];
+	inspected = inspected || {};
+
+	inspected[ dataType ] = true;
+
+	var list = structure[ dataType ],
+		i = 0,
+		length = list ? list.length : 0,
+		executeOnly = ( structure === prefilters ),
+		selection;
+
+	for ( ; i < length && ( executeOnly || !selection ); i++ ) {
+		selection = list[ i ]( options, originalOptions, jqXHR );
+		// If we got redirected to another dataType
+		// we try there if executing only and not done already
+		if ( typeof selection === "string" ) {
+			if ( !executeOnly || inspected[ selection ] ) {
+				selection = undefined;
+			} else {
+				options.dataTypes.unshift( selection );
+				selection = inspectPrefiltersOrTransports(
+						structure, options, originalOptions, jqXHR, selection, inspected );
+			}
+		}
+	}
+	// If we're only executing or nothing was selected
+	// we try the catchall dataType if not done already
+	if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+		selection = inspectPrefiltersOrTransports(
+				structure, options, originalOptions, jqXHR, "*", inspected );
+	}
+	// unnecessary when only executing (prefilters)
+	// but it'll be ignored by the caller in that case
+	return selection;
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+	var key, deep,
+		flatOptions = jQuery.ajaxSettings.flatOptions || {};
+	for ( key in src ) {
+		if ( src[ key ] !== undefined ) {
+			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+		}
+	}
+	if ( deep ) {
+		jQuery.extend( true, target, deep );
+	}
+}
+
+jQuery.fn.extend({
+	load: function( url, params, callback ) {
+		if ( typeof url !== "string" && _load ) {
+			return _load.apply( this, arguments );
+
+		// Don't do a request if no elements are being requested
+		} else if ( !this.length ) {
+			return this;
+		}
+
+		var off = url.indexOf( " " );
+		if ( off >= 0 ) {
+			var selector = url.slice( off, url.length );
+			url = url.slice( 0, off );
+		}
+
+		// Default to a GET request
+		var type = "GET";
+
+		// If the second parameter was provided
+		if ( params ) {
+			// If it's a function
+			if ( jQuery.isFunction( params ) ) {
+				// We assume that it's the callback
+				callback = params;
+				params = undefined;
+
+			// Otherwise, build a param string
+			} else if ( typeof params === "object" ) {
+				params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+				type = "POST";
+			}
+		}
+
+		var self = this;
+
+		// Request the remote document
+		jQuery.ajax({
+			url: url,
+			type: type,
+			dataType: "html",
+			data: params,
+			// Complete callback (responseText is used internally)
+			complete: function( jqXHR, status, responseText ) {
+				// Store the response as specified by the jqXHR object
+				responseText = jqXHR.responseText;
+				// If successful, inject the HTML into all the matched elements
+				if ( jqXHR.isResolved() ) {
+					// #4825: Get the actual response in case
+					// a dataFilter is present in ajaxSettings
+					jqXHR.done(function( r ) {
+						responseText = r;
+					});
+					// See if a selector was specified
+					self.html( selector ?
+						// Create a dummy div to hold the results
+						jQuery("<div>")
+							// inject the contents of the document in, removing the scripts
+							// to avoid any 'Permission Denied' errors in IE
+							.append(responseText.replace(rscript, ""))
+
+							// Locate the specified elements
+							.find(selector) :
+
+						// If not, just inject the full result
+						responseText );
+				}
+
+				if ( callback ) {
+					self.each( callback, [ responseText, status, jqXHR ] );
+				}
+			}
+		});
+
+		return this;
+	},
+
+	serialize: function() {
+		return jQuery.param( this.serializeArray() );
+	},
+
+	serializeArray: function() {
+		return this.map(function(){
+			return this.elements ? jQuery.makeArray( this.elements ) : this;
+		})
+		.filter(function(){
+			return this.name && !this.disabled &&
+				( this.checked || rselectTextarea.test( this.nodeName ) ||
+					rinput.test( this.type ) );
+		})
+		.map(function( i, elem ){
+			var val = jQuery( this ).val();
+
+			return val == null ?
+				null :
+				jQuery.isArray( val ) ?
+					jQuery.map( val, function( val, i ){
+						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+					}) :
+					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+		}).get();
+	}
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+	jQuery.fn[ o ] = function( f ){
+		return this.on( o, f );
+	};
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+	jQuery[ method ] = function( url, data, callback, type ) {
+		// shift arguments if data argument was omitted
+		if ( jQuery.isFunction( data ) ) {
+			type = type || callback;
+			callback = data;
+			data = undefined;
+		}
+
+		return jQuery.ajax({
+			type: method,
+			url: url,
+			data: data,
+			success: callback,
+			dataType: type
+		});
+	};
+});
+
+jQuery.extend({
+
+	getScript: function( url, callback ) {
+		return jQuery.get( url, undefined, callback, "script" );
+	},
+
+	getJSON: function( url, data, callback ) {
+		return jQuery.get( url, data, callback, "json" );
+	},
+
+	// Creates a full fledged settings object into target
+	// with both ajaxSettings and settings fields.
+	// If target is omitted, writes into ajaxSettings.
+	ajaxSetup: function( target, settings ) {
+		if ( settings ) {
+			// Building a settings object
+			ajaxExtend( target, jQuery.ajaxSettings );
+		} else {
+			// Extending ajaxSettings
+			settings = target;
+			target = jQuery.ajaxSettings;
+		}
+		ajaxExtend( target, settings );
+		return target;
+	},
+
+	ajaxSettings: {
+		url: ajaxLocation,
+		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+		global: true,
+		type: "GET",
+		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+		processData: true,
+		async: true,
+		/*
+		timeout: 0,
+		data: null,
+		dataType: null,
+		username: null,
+		password: null,
+		cache: null,
+		traditional: false,
+		headers: {},
+		*/
+
+		accepts: {
+			xml: "application/xml, text/xml",
+			html: "text/html",
+			text: "text/plain",
+			json: "application/json, text/javascript",
+			"*": allTypes
+		},
+
+		contents: {
+			xml: /xml/,
+			html: /html/,
+			json: /json/
+		},
+
+		responseFields: {
+			xml: "responseXML",
+			text: "responseText"
+		},
+
+		// List of data converters
+		// 1) key format is "source_type destination_type" (a single space in-between)
+		// 2) the catchall symbol "*" can be used for source_type
+		converters: {
+
+			// Convert anything to text
+			"* text": window.String,
+
+			// Text to html (true = no transformation)
+			"text html": true,
+
+			// Evaluate text as a json expression
+			"text json": jQuery.parseJSON,
+
+			// Parse text as xml
+			"text xml": jQuery.parseXML
+		},
+
+		// For options that shouldn't be deep extended:
+		// you can add your own custom options here if
+		// and when you create one that shouldn't be
+		// deep extended (see ajaxExtend)
+		flatOptions: {
+			context: true,
+			url: true
+		}
+	},
+
+	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+	ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+	// Main method
+	ajax: function( url, options ) {
+
+		// If url is an object, simulate pre-1.5 signature
+		if ( typeof url === "object" ) {
+			options = url;
+			url = undefined;
+		}
+
+		// Force options to be an object
+		options = options || {};
+
+		var // Create the final options object
+			s = jQuery.ajaxSetup( {}, options ),
+			// Callbacks context
+			callbackContext = s.context || s,
+			// Context for global events
+			// It's the callbackContext if one was provided in the options
+			// and if it's a DOM node or a jQuery collection
+			globalEventContext = callbackContext !== s &&
+				( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+						jQuery( callbackContext ) : jQuery.event,
+			// Deferreds
+			deferred = jQuery.Deferred(),
+			completeDeferred = jQuery.Callbacks( "once memory" ),
+			// Status-dependent callbacks
+			statusCode = s.statusCode || {},
+			// ifModified key
+			ifModifiedKey,
+			// Headers (they are sent all at once)
+			requestHeaders = {},
+			requestHeadersNames = {},
+			// Response headers
+			responseHeadersString,
+			responseHeaders,
+			// transport
+			transport,
+			// timeout handle
+			timeoutTimer,
+			// Cross-domain detection vars
+			parts,
+			// The jqXHR state
+			state = 0,
+			// To know if global events are to be dispatched
+			fireGlobals,
+			// Loop variable
+			i,
+			// Fake xhr
+			jqXHR = {
+
+				readyState: 0,
+
+				// Caches the header
+				setRequestHeader: function( name, value ) {
+					if ( !state ) {
+						var lname = name.toLowerCase();
+						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+						requestHeaders[ name ] = value;
+					}
+					return this;
+				},
+
+				// Raw string
+				getAllResponseHeaders: function() {
+					return state === 2 ? responseHeadersString : null;
+				},
+
+				// Builds headers hashtable if needed
+				getResponseHeader: function( key ) {
+					var match;
+					if ( state === 2 ) {
+						if ( !responseHeaders ) {
+							responseHeaders = {};
+							while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+							}
+						}
+						match = responseHeaders[ key.toLowerCase() ];
+					}
+					return match === undefined ? null : match;
+				},
+
+				// Overrides response content-type header
+				overrideMimeType: function( type ) {
+					if ( !state ) {
+						s.mimeType = type;
+					}
+					return this;
+				},
+
+				// Cancel the request
+				abort: function( statusText ) {
+					statusText = statusText || "abort";
+					if ( transport ) {
+						transport.abort( statusText );
+					}
+					done( 0, statusText );
+					return this;
+				}
+			};
+
+		// Callback for when everything is done
+		// It is defined here because jslint complains if it is declared
+		// at the end of the function (which would be more logical and readable)
+		function done( status, nativeStatusText, responses, headers ) {
+
+			// Called once
+			if ( state === 2 ) {
+				return;
+			}
+
+			// State is "done" now
+			state = 2;
+
+			// Clear timeout if it exists
+			if ( timeoutTimer ) {
+				clearTimeout( timeoutTimer );
+			}
+
+			// Dereference transport for early garbage collection
+			// (no matter how long the jqXHR object will be used)
+			transport = undefined;
+
+			// Cache response headers
+			responseHeadersString = headers || "";
+
+			// Set readyState
+			jqXHR.readyState = status > 0 ? 4 : 0;
+
+			var isSuccess,
+				success,
+				error,
+				statusText = nativeStatusText,
+				response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+				lastModified,
+				etag;
+
+			// If successful, handle type chaining
+			if ( status >= 200 && status < 300 || status === 304 ) {
+
+				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+				if ( s.ifModified ) {
+
+					if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+						jQuery.lastModified[ ifModifiedKey ] = lastModified;
+					}
+					if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+						jQuery.etag[ ifModifiedKey ] = etag;
+					}
+				}
+
+				// If not modified
+				if ( status === 304 ) {
+
+					statusText = "notmodified";
+					isSuccess = true;
+
+				// If we have data
+				} else {
+
+					try {
+						success = ajaxConvert( s, response );
+						statusText = "success";
+						isSuccess = true;
+					} catch(e) {
+						// We have a parsererror
+						statusText = "parsererror";
+						error = e;
+					}
+				}
+			} else {
+				// We extract error from statusText
+				// then normalize statusText and status for non-aborts
+				error = statusText;
+				if ( !statusText || status ) {
+					statusText = "error";
+					if ( status < 0 ) {
+						status = 0;
+					}
+				}
+			}
+
+			// Set data for the fake xhr object
+			jqXHR.status = status;
+			jqXHR.statusText = "" + ( nativeStatusText || statusText );
+
+			// Success/Error
+			if ( isSuccess ) {
+				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+			} else {
+				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+			}
+
+			// Status-dependent callbacks
+			jqXHR.statusCode( statusCode );
+			statusCode = undefined;
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+						[ jqXHR, s, isSuccess ? success : error ] );
+			}
+
+			// Complete
+			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+				// Handle the global AJAX counter
+				if ( !( --jQuery.active ) ) {
+					jQuery.event.trigger( "ajaxStop" );
+				}
+			}
+		}
+
+		// Attach deferreds
+		deferred.promise( jqXHR );
+		jqXHR.success = jqXHR.done;
+		jqXHR.error = jqXHR.fail;
+		jqXHR.complete = completeDeferred.add;
+
+		// Status-dependent callbacks
+		jqXHR.statusCode = function( map ) {
+			if ( map ) {
+				var tmp;
+				if ( state < 2 ) {
+					for ( tmp in map ) {
+						statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+					}
+				} else {
+					tmp = map[ jqXHR.status ];
+					jqXHR.then( tmp, tmp );
+				}
+			}
+			return this;
+		};
+
+		// Remove hash character (#7531: and string promotion)
+		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+		// We also use the url parameter if available
+		s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+		// Extract dataTypes list
+		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+		// Determine if a cross-domain request is in order
+		if ( s.crossDomain == null ) {
+			parts = rurl.exec( s.url.toLowerCase() );
+			s.crossDomain = !!( parts &&
+				( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+			);
+		}
+
+		// Convert data if not already a string
+		if ( s.data && s.processData && typeof s.data !== "string" ) {
+			s.data = jQuery.param( s.data, s.traditional );
+		}
+
+		// Apply prefilters
+		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+		// If request was aborted inside a prefilter, stop there
+		if ( state === 2 ) {
+			return false;
+		}
+
+		// We can fire global events as of now if asked to
+		fireGlobals = s.global;
+
+		// Uppercase the type
+		s.type = s.type.toUpperCase();
+
+		// Determine if request has content
+		s.hasContent = !rnoContent.test( s.type );
+
+		// Watch for a new set of requests
+		if ( fireGlobals && jQuery.active++ === 0 ) {
+			jQuery.event.trigger( "ajaxStart" );
+		}
+
+		// More options handling for requests with no content
+		if ( !s.hasContent ) {
+
+			// If data is available, append data to url
+			if ( s.data ) {
+				s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+				// #9682: remove data so that it's not used in an eventual retry
+				delete s.data;
+			}
+
+			// Get ifModifiedKey before adding the anti-cache parameter
+			ifModifiedKey = s.url;
+
+			// Add anti-cache in url if needed
+			if ( s.cache === false ) {
+
+				var ts = jQuery.now(),
+					// try replacing _= if it is there
+					ret = s.url.replace( rts, "$1_=" + ts );
+
+				// if nothing was replaced, add timestamp to the end
+				s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+			}
+		}
+
+		// Set the correct header, if data is being sent
+		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+			jqXHR.setRequestHeader( "Content-Type", s.contentType );
+		}
+
+		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+		if ( s.ifModified ) {
+			ifModifiedKey = ifModifiedKey || s.url;
+			if ( jQuery.lastModified[ ifModifiedKey ] ) {
+				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+			}
+			if ( jQuery.etag[ ifModifiedKey ] ) {
+				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+			}
+		}
+
+		// Set the Accepts header for the server, depending on the dataType
+		jqXHR.setRequestHeader(
+			"Accept",
+			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+				s.accepts[ "*" ]
+		);
+
+		// Check for headers option
+		for ( i in s.headers ) {
+			jqXHR.setRequestHeader( i, s.headers[ i ] );
+		}
+
+		// Allow custom headers/mimetypes and early abort
+		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+				// Abort if not done already
+				jqXHR.abort();
+				return false;
+
+		}
+
+		// Install callbacks on deferreds
+		for ( i in { success: 1, error: 1, complete: 1 } ) {
+			jqXHR[ i ]( s[ i ] );
+		}
+
+		// Get transport
+		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+		// If no transport, we auto-abort
+		if ( !transport ) {
+			done( -1, "No Transport" );
+		} else {
+			jqXHR.readyState = 1;
+			// Send global event
+			if ( fireGlobals ) {
+				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+			}
+			// Timeout
+			if ( s.async && s.timeout > 0 ) {
+				timeoutTimer = setTimeout( function(){
+					jqXHR.abort( "timeout" );
+				}, s.timeout );
+			}
+
+			try {
+				state = 1;
+				transport.send( requestHeaders, done );
+			} catch (e) {
+				// Propagate exception as error if not done
+				if ( state < 2 ) {
+					done( -1, e );
+				// Simply rethrow otherwise
+				} else {
+					throw e;
+				}
+			}
+		}
+
+		return jqXHR;
+	},
+
+	// Serialize an array of form elements or a set of
+	// key/values into a query string
+	param: function( a, traditional ) {
+		var s = [],
+			add = function( key, value ) {
+				// If value is a function, invoke it and return its value
+				value = jQuery.isFunction( value ) ? value() : value;
+				s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+			};
+
+		// Set traditional to true for jQuery <= 1.3.2 behavior.
+		if ( traditional === undefined ) {
+			traditional = jQuery.ajaxSettings.traditional;
+		}
+
+		// If an array was passed in, assume that it is an array of form elements.
+		if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+			// Serialize the form elements
+			jQuery.each( a, function() {
+				add( this.name, this.value );
+			});
+
+		} else {
+			// If traditional, encode the "old" way (the way 1.3.2 or older
+			// did it), otherwise encode params recursively.
+			for ( var prefix in a ) {
+				buildParams( prefix, a[ prefix ], traditional, add );
+			}
+		}
+
+		// Return the resulting serialization
+		return s.join( "&" ).replace( r20, "+" );
+	}
+});
+
+function buildParams( prefix, obj, traditional, add ) {
+	if ( jQuery.isArray( obj ) ) {
+		// Serialize array item.
+		jQuery.each( obj, function( i, v ) {
+			if ( traditional || rbracket.test( prefix ) ) {
+				// Treat each array item as a scalar.
+				add( prefix, v );
+
+			} else {
+				// If array item is non-scalar (array or object), encode its
+				// numeric index to resolve deserialization ambiguity issues.
+				// Note that rack (as of 1.0.0) can't currently deserialize
+				// nested arrays properly, and attempting to do so may cause
+				// a server error. Possible fixes are to modify rack's
+				// deserialization algorithm or to provide an option or flag
+				// to force array serialization to be shallow.
+				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+			}
+		});
+
+	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
+		// Serialize object item.
+		for ( var name in obj ) {
+			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+		}
+
+	} else {
+		// Serialize scalar item.
+		add( prefix, obj );
+	}
+}
+
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Last-Modified header cache for next request
+	lastModified: {},
+	etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+	var contents = s.contents,
+		dataTypes = s.dataTypes,
+		responseFields = s.responseFields,
+		ct,
+		type,
+		finalDataType,
+		firstDataType;
+
+	// Fill responseXXX fields
+	for ( type in responseFields ) {
+		if ( type in responses ) {
+			jqXHR[ responseFields[type] ] = responses[ type ];
+		}
+	}
+
+	// Remove auto dataType and get content-type in the process
+	while( dataTypes[ 0 ] === "*" ) {
+		dataTypes.shift();
+		if ( ct === undefined ) {
+			ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+		}
+	}
+
+	// Check if we're dealing with a known content-type
+	if ( ct ) {
+		for ( type in contents ) {
+			if ( contents[ type ] && contents[ type ].test( ct ) ) {
+				dataTypes.unshift( type );
+				break;
+			}
+		}
+	}
+
+	// Check to see if we have a response for the expected dataType
+	if ( dataTypes[ 0 ] in responses ) {
+		finalDataType = dataTypes[ 0 ];
+	} else {
+		// Try convertible dataTypes
+		for ( type in responses ) {
+			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+				finalDataType = type;
+				break;
+			}
+			if ( !firstDataType ) {
+				firstDataType = type;
+			}
+		}
+		// Or just use first one
+		finalDataType = finalDataType || firstDataType;
+	}
+
+	// If we found a dataType
+	// We add the dataType to the list if needed
+	// and return the corresponding response
+	if ( finalDataType ) {
+		if ( finalDataType !== dataTypes[ 0 ] ) {
+			dataTypes.unshift( finalDataType );
+		}
+		return responses[ finalDataType ];
+	}
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+	// Apply the dataFilter if provided
+	if ( s.dataFilter ) {
+		response = s.dataFilter( response, s.dataType );
+	}
+
+	var dataTypes = s.dataTypes,
+		converters = {},
+		i,
+		key,
+		length = dataTypes.length,
+		tmp,
+		// Current and previous dataTypes
+		current = dataTypes[ 0 ],
+		prev,
+		// Conversion expression
+		conversion,
+		// Conversion function
+		conv,
+		// Conversion functions (transitive conversion)
+		conv1,
+		conv2;
+
+	// For each dataType in the chain
+	for ( i = 1; i < length; i++ ) {
+
+		// Create converters map
+		// with lowercased keys
+		if ( i === 1 ) {
+			for ( key in s.converters ) {
+				if ( typeof key === "string" ) {
+					converters[ key.toLowerCase() ] = s.converters[ key ];
+				}
+			}
+		}
+
+		// Get the dataTypes
+		prev = current;
+		current = dataTypes[ i ];
+
+		// If current is auto dataType, update it to prev
+		if ( current === "*" ) {
+			current = prev;
+		// If no auto and dataTypes are actually different
+		} else if ( prev !== "*" && prev !== current ) {
+
+			// Get the converter
+			conversion = prev + " " + current;
+			conv = converters[ conversion ] || converters[ "* " + current ];
+
+			// If there is no direct converter, search transitively
+			if ( !conv ) {
+				conv2 = undefined;
+				for ( conv1 in converters ) {
+					tmp = conv1.split( " " );
+					if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+						conv2 = converters[ tmp[1] + " " + current ];
+						if ( conv2 ) {
+							conv1 = converters[ conv1 ];
+							if ( conv1 === true ) {
+								conv = conv2;
+							} else if ( conv2 === true ) {
+								conv = conv1;
+							}
+							break;
+						}
+					}
+				}
+			}
+			// If we found no converter, dispatch an error
+			if ( !( conv || conv2 ) ) {
+				jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+			}
+			// If found converter is not an equivalence
+			if ( conv !== true ) {
+				// Convert with 1 or 2 converters accordingly
+				response = conv ? conv( response ) : conv2( conv1(response) );
+			}
+		}
+	}
+	return response;
+}
+
+
+
+
+var jsc = jQuery.now(),
+	jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+	jsonp: "callback",
+	jsonpCallback: function() {
+		return jQuery.expando + "_" + ( jsc++ );
+	}
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+	var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
+
+	if ( s.dataTypes[ 0 ] === "jsonp" ||
+		s.jsonp !== false && ( jsre.test( s.url ) ||
+				inspectData && jsre.test( s.data ) ) ) {
+
+		var responseContainer,
+			jsonpCallback = s.jsonpCallback =
+				jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+			previous = window[ jsonpCallback ],
+			url = s.url,
+			data = s.data,
+			replace = "$1" + jsonpCallback + "$2";
+
+		if ( s.jsonp !== false ) {
+			url = url.replace( jsre, replace );
+			if ( s.url === url ) {
+				if ( inspectData ) {
+					data = data.replace( jsre, replace );
+				}
+				if ( s.data === data ) {
+					// Add callback manually
+					url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+				}
+			}
+		}
+
+		s.url = url;
+		s.data = data;
+
+		// Install callback
+		window[ jsonpCallback ] = function( response ) {
+			responseContainer = [ response ];
+		};
+
+		// Clean-up function
+		jqXHR.always(function() {
+			// Set callback back to previous value
+			window[ jsonpCallback ] = previous;
+			// Call if it was a function and we have a response
+			if ( responseContainer && jQuery.isFunction( previous ) ) {
+				window[ jsonpCallback ]( responseContainer[ 0 ] );
+			}
+		});
+
+		// Use data converter to retrieve json after script execution
+		s.converters["script json"] = function() {
+			if ( !responseContainer ) {
+				jQuery.error( jsonpCallback + " was not called" );
+			}
+			return responseContainer[ 0 ];
+		};
+
+		// force json dataType
+		s.dataTypes[ 0 ] = "json";
+
+		// Delegate to script
+		return "script";
+	}
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+	accepts: {
+		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+	},
+	contents: {
+		script: /javascript|ecmascript/
+	},
+	converters: {
+		"text script": function( text ) {
+			jQuery.globalEval( text );
+			return text;
+		}
+	}
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+	if ( s.cache === undefined ) {
+		s.cache = false;
+	}
+	if ( s.crossDomain ) {
+		s.type = "GET";
+		s.global = false;
+	}
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+	// This transport only deals with cross domain requests
+	if ( s.crossDomain ) {
+
+		var script,
+			head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+		return {
+
+			send: function( _, callback ) {
+
+				script = document.createElement( "script" );
+
+				script.async = "async";
+
+				if ( s.scriptCharset ) {
+					script.charset = s.scriptCharset;
+				}
+
+				script.src = s.url;
+
+				// Attach handlers for all browsers
+				script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+						// Handle memory leak in IE
+						script.onload = script.onreadystatechange = null;
+
+						// Remove the script
+						if ( head && script.parentNode ) {
+							head.removeChild( script );
+						}
+
+						// Dereference the script
+						script = undefined;
+
+						// Callback if not abort
+						if ( !isAbort ) {
+							callback( 200, "success" );
+						}
+					}
+				};
+				// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+				// This arises when a base node is used (#2709 and #4378).
+				head.insertBefore( script, head.firstChild );
+			},
+
+			abort: function() {
+				if ( script ) {
+					script.onload( 0, 1 );
+				}
+			}
+		};
+	}
+});
+
+
+
+
+var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+	xhrOnUnloadAbort = window.ActiveXObject ? function() {
+		// Abort all pending requests
+		for ( var key in xhrCallbacks ) {
+			xhrCallbacks[ key ]( 0, 1 );
+		}
+	} : false,
+	xhrId = 0,
+	xhrCallbacks;
+
+// Functions to create xhrs
+function createStandardXHR() {
+	try {
+		return new window.XMLHttpRequest();
+	} catch( e ) {}
+}
+
+function createActiveXHR() {
+	try {
+		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+	} catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+	/* Microsoft failed to properly
+	 * implement the XMLHttpRequest in IE7 (can't request local files),
+	 * so we use the ActiveXObject when it is available
+	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+	 * we need a fallback.
+	 */
+	function() {
+		return !this.isLocal && createStandardXHR() || createActiveXHR();
+	} :
+	// For all other browsers, use the standard XMLHttpRequest object
+	createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+	jQuery.extend( jQuery.support, {
+		ajax: !!xhr,
+		cors: !!xhr && ( "withCredentials" in xhr )
+	});
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+	jQuery.ajaxTransport(function( s ) {
+		// Cross domain only allowed if supported through XMLHttpRequest
+		if ( !s.crossDomain || jQuery.support.cors ) {
+
+			var callback;
+
+			return {
+				send: function( headers, complete ) {
+
+					// Get a new xhr
+					var xhr = s.xhr(),
+						handle,
+						i;
+
+					// Open the socket
+					// Passing null username, generates a login popup on Opera (#2865)
+					if ( s.username ) {
+						xhr.open( s.type, s.url, s.async, s.username, s.password );
+					} else {
+						xhr.open( s.type, s.url, s.async );
+					}
+
+					// Apply custom fields if provided
+					if ( s.xhrFields ) {
+						for ( i in s.xhrFields ) {
+							xhr[ i ] = s.xhrFields[ i ];
+						}
+					}
+
+					// Override mime type if needed
+					if ( s.mimeType && xhr.overrideMimeType ) {
+						xhr.overrideMimeType( s.mimeType );
+					}
+
+					// X-Requested-With header
+					// For cross-domain requests, seeing as conditions for a preflight are
+					// akin to a jigsaw puzzle, we simply never set it to be sure.
+					// (it can always be set on a per-request basis or even using ajaxSetup)
+					// For same-domain requests, won't change header if already provided.
+					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+						headers[ "X-Requested-With" ] = "XMLHttpRequest";
+					}
+
+					// Need an extra try/catch for cross domain requests in Firefox 3
+					try {
+						for ( i in headers ) {
+							xhr.setRequestHeader( i, headers[ i ] );
+						}
+					} catch( _ ) {}
+
+					// Do send the request
+					// This may raise an exception which is actually
+					// handled in jQuery.ajax (so no try/catch here)
+					xhr.send( ( s.hasContent && s.data ) || null );
+
+					// Listener
+					callback = function( _, isAbort ) {
+
+						var status,
+							statusText,
+							responseHeaders,
+							responses,
+							xml;
+
+						// Firefox throws exceptions when accessing properties
+						// of an xhr when a network error occured
+						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+						try {
+
+							// Was never called and is aborted or complete
+							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+								// Only called once
+								callback = undefined;
+
+								// Do not keep as active anymore
+								if ( handle ) {
+									xhr.onreadystatechange = jQuery.noop;
+									if ( xhrOnUnloadAbort ) {
+										delete xhrCallbacks[ handle ];
+									}
+								}
+
+								// If it's an abort
+								if ( isAbort ) {
+									// Abort it manually if needed
+									if ( xhr.readyState !== 4 ) {
+										xhr.abort();
+									}
+								} else {
+									status = xhr.status;
+									responseHeaders = xhr.getAllResponseHeaders();
+									responses = {};
+									xml = xhr.responseXML;
+
+									// Construct response list
+									if ( xml && xml.documentElement /* #4958 */ ) {
+										responses.xml = xml;
+									}
+
+									// When requesting binary data, IE6-9 will throw an exception
+									// on any attempt to access responseText (#11426)
+									try {
+										responses.text = xhr.responseText;
+									} catch( _ ) {
+									}
+
+									// Firefox throws an exception when accessing
+									// statusText for faulty cross-domain requests
+									try {
+										statusText = xhr.statusText;
+									} catch( e ) {
+										// We normalize with Webkit giving an empty statusText
+										statusText = "";
+									}
+
+									// Filter status for non standard behaviors
+
+									// If the request is local and we have data: assume a success
+									// (success with no data won't get notified, that's the best we
+									// can do given current implementations)
+									if ( !status && s.isLocal && !s.crossDomain ) {
+										status = responses.text ? 200 : 404;
+									// IE - #1450: sometimes returns 1223 when it should be 204
+									} else if ( status === 1223 ) {
+										status = 204;
+									}
+								}
+							}
+						} catch( firefoxAccessException ) {
+							if ( !isAbort ) {
+								complete( -1, firefoxAccessException );
+							}
+						}
+
+						// Call complete if needed
+						if ( responses ) {
+							complete( status, statusText, responses, responseHeaders );
+						}
+					};
+
+					// if we're in sync mode or it's in cache
+					// and has been retrieved directly (IE6 & IE7)
+					// we need to manually fire the callback
+					if ( !s.async || xhr.readyState === 4 ) {
+						callback();
+					} else {
+						handle = ++xhrId;
+						if ( xhrOnUnloadAbort ) {
+							// Create the active xhrs callbacks list if needed
+							// and attach the unload handler
+							if ( !xhrCallbacks ) {
+								xhrCallbacks = {};
+								jQuery( window ).unload( xhrOnUnloadAbort );
+							}
+							// Add to list of active xhrs callbacks
+							xhrCallbacks[ handle ] = callback;
+						}
+						xhr.onreadystatechange = callback;
+					}
+				},
+
+				abort: function() {
+					if ( callback ) {
+						callback(0,1);
+					}
+				}
+			};
+		}
+	});
+}
+
+
+
+
+var elemdisplay = {},
+	iframe, iframeDoc,
+	rfxtypes = /^(?:toggle|show|hide)$/,
+	rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+	timerId,
+	fxAttrs = [
+		// height animations
+		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+		// width animations
+		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+		// opacity animations
+		[ "opacity" ]
+	],
+	fxNow;
+
+jQuery.fn.extend({
+	show: function( speed, easing, callback ) {
+		var elem, display;
+
+		if ( speed || speed === 0 ) {
+			return this.animate( genFx("show", 3), speed, easing, callback );
+
+		} else {
+			for ( var i = 0, j = this.length; i < j; i++ ) {
+				elem = this[ i ];
+
+				if ( elem.style ) {
+					display = elem.style.display;
+
+					// Reset the inline display of this element to learn if it is
+					// being hidden by cascaded rules or not
+					if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+						display = elem.style.display = "";
+					}
+
+					// Set elements which have been overridden with display: none
+					// in a stylesheet to whatever the default browser style is
+					// for such an element
+					if ( (display === "" && jQuery.css(elem, "display") === "none") ||
+						!jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+						jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+					}
+				}
+			}
+
+			// Set the display of most of the elements in a second loop
+			// to avoid the constant reflow
+			for ( i = 0; i < j; i++ ) {
+				elem = this[ i ];
+
+				if ( elem.style ) {
+					display = elem.style.display;
+
+					if ( display === "" || display === "none" ) {
+						elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
+					}
+				}
+			}
+
+			return this;
+		}
+	},
+
+	hide: function( speed, easing, callback ) {
+		if ( speed || speed === 0 ) {
+			return this.animate( genFx("hide", 3), speed, easing, callback);
+
+		} else {
+			var elem, display,
+				i = 0,
+				j = this.length;
+
+			for ( ; i < j; i++ ) {
+				elem = this[i];
+				if ( elem.style ) {
+					display = jQuery.css( elem, "display" );
+
+					if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
+						jQuery._data( elem, "olddisplay", display );
+					}
+				}
+			}
+
+			// Set the display of the elements in a second loop
+			// to avoid the constant reflow
+			for ( i = 0; i < j; i++ ) {
+				if ( this[i].style ) {
+					this[i].style.display = "none";
+				}
+			}
+
+			return this;
+		}
+	},
+
+	// Save the old toggle function
+	_toggle: jQuery.fn.toggle,
+
+	toggle: function( fn, fn2, callback ) {
+		var bool = typeof fn === "boolean";
+
+		if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+			this._toggle.apply( this, arguments );
+
+		} else if ( fn == null || bool ) {
+			this.each(function() {
+				var state = bool ? fn : jQuery(this).is(":hidden");
+				jQuery(this)[ state ? "show" : "hide" ]();
+			});
+
+		} else {
+			this.animate(genFx("toggle", 3), fn, fn2, callback);
+		}
+
+		return this;
+	},
+
+	fadeTo: function( speed, to, easing, callback ) {
+		return this.filter(":hidden").css("opacity", 0).show().end()
+					.animate({opacity: to}, speed, easing, callback);
+	},
+
+	animate: function( prop, speed, easing, callback ) {
+		var optall = jQuery.speed( speed, easing, callback );
+
+		if ( jQuery.isEmptyObject( prop ) ) {
+			return this.each( optall.complete, [ false ] );
+		}
+
+		// Do not change referenced properties as per-property easing will be lost
+		prop = jQuery.extend( {}, prop );
+
+		function doAnimation() {
+			// XXX 'this' does not always have a nodeName when running the
+			// test suite
+
+			if ( optall.queue === false ) {
+				jQuery._mark( this );
+			}
+
+			var opt = jQuery.extend( {}, optall ),
+				isElement = this.nodeType === 1,
+				hidden = isElement && jQuery(this).is(":hidden"),
+				name, val, p, e, hooks, replace,
+				parts, start, end, unit,
+				method;
+
+			// will store per property easing and be used to determine when an animation is complete
+			opt.animatedProperties = {};
+
+			// first pass over propertys to expand / normalize
+			for ( p in prop ) {
+				name = jQuery.camelCase( p );
+				if ( p !== name ) {
+					prop[ name ] = prop[ p ];
+					delete prop[ p ];
+				}
+
+				if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
+					replace = hooks.expand( prop[ name ] );
+					delete prop[ name ];
+
+					// not quite $.extend, this wont overwrite keys already present.
+					// also - reusing 'p' from above because we have the correct "name"
+					for ( p in replace ) {
+						if ( ! ( p in prop ) ) {
+							prop[ p ] = replace[ p ];
+						}
+					}
+				}
+			}
+
+			for ( name in prop ) {
+				val = prop[ name ];
+				// easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+				if ( jQuery.isArray( val ) ) {
+					opt.animatedProperties[ name ] = val[ 1 ];
+					val = prop[ name ] = val[ 0 ];
+				} else {
+					opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
+				}
+
+				if ( val === "hide" && hidden || val === "show" && !hidden ) {
+					return opt.complete.call( this );
+				}
+
+				if ( isElement && ( name === "height" || name === "width" ) ) {
+					// Make sure that nothing sneaks out
+					// Record all 3 overflow attributes because IE does not
+					// change the overflow attribute when overflowX and
+					// overflowY are set to the same value
+					opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+					// Set display property to inline-block for height/width
+					// animations on inline elements that are having width/height animated
+					if ( jQuery.css( this, "display" ) === "inline" &&
+							jQuery.css( this, "float" ) === "none" ) {
+
+						// inline-level elements accept inline-block;
+						// block-level elements need to be inline with layout
+						if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
+							this.style.display = "inline-block";
+
+						} else {
+							this.style.zoom = 1;
+						}
+					}
+				}
+			}
+
+			if ( opt.overflow != null ) {
+				this.style.overflow = "hidden";
+			}
+
+			for ( p in prop ) {
+				e = new jQuery.fx( this, opt, p );
+				val = prop[ p ];
+
+				if ( rfxtypes.test( val ) ) {
+
+					// Tracks whether to show or hide based on private
+					// data attached to the element
+					method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
+					if ( method ) {
+						jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
+						e[ method ]();
+					} else {
+						e[ val ]();
+					}
+
+				} else {
+					parts = rfxnum.exec( val );
+					start = e.cur();
+
+					if ( parts ) {
+						end = parseFloat( parts[2] );
+						unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
+
+						// We need to compute starting value
+						if ( unit !== "px" ) {
+							jQuery.style( this, p, (end || 1) + unit);
+							start = ( (end || 1) / e.cur() ) * start;
+							jQuery.style( this, p, start + unit);
+						}
+
+						// If a +=/-= token was provided, we're doing a relative animation
+						if ( parts[1] ) {
+							end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
+						}
+
+						e.custom( start, end, unit );
+
+					} else {
+						e.custom( start, val, "" );
+					}
+				}
+			}
+
+			// For JS strict compliance
+			return true;
+		}
+
+		return optall.queue === false ?
+			this.each( doAnimation ) :
+			this.queue( optall.queue, doAnimation );
+	},
+
+	stop: function( type, clearQueue, gotoEnd ) {
+		if ( typeof type !== "string" ) {
+			gotoEnd = clearQueue;
+			clearQueue = type;
+			type = undefined;
+		}
+		if ( clearQueue && type !== false ) {
+			this.queue( type || "fx", [] );
+		}
+
+		return this.each(function() {
+			var index,
+				hadTimers = false,
+				timers = jQuery.timers,
+				data = jQuery._data( this );
+
+			// clear marker counters if we know they won't be
+			if ( !gotoEnd ) {
+				jQuery._unmark( true, this );
+			}
+
+			function stopQueue( elem, data, index ) {
+				var hooks = data[ index ];
+				jQuery.removeData( elem, index, true );
+				hooks.stop( gotoEnd );
+			}
+
+			if ( type == null ) {
+				for ( index in data ) {
+					if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
+						stopQueue( this, data, index );
+					}
+				}
+			} else if ( data[ index = type + ".run" ] && data[ index ].stop ){
+				stopQueue( this, data, index );
+			}
+
+			for ( index = timers.length; index--; ) {
+				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+					if ( gotoEnd ) {
+
+						// force the next step to be the last
+						timers[ index ]( true );
+					} else {
+						timers[ index ].saveState();
+					}
+					hadTimers = true;
+					timers.splice( index, 1 );
+				}
+			}
+
+			// start the next in the queue if the last step wasn't forced
+			// timers currently will call their complete callbacks, which will dequeue
+			// but only if they were gotoEnd
+			if ( !( gotoEnd && hadTimers ) ) {
+				jQuery.dequeue( this, type );
+			}
+		});
+	}
+
+});
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+	setTimeout( clearFxNow, 0 );
+	return ( fxNow = jQuery.now() );
+}
+
+function clearFxNow() {
+	fxNow = undefined;
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, num ) {
+	var obj = {};
+
+	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
+		obj[ this ] = type;
+	});
+
+	return obj;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+	slideDown: genFx( "show", 1 ),
+	slideUp: genFx( "hide", 1 ),
+	slideToggle: genFx( "toggle", 1 ),
+	fadeIn: { opacity: "show" },
+	fadeOut: { opacity: "hide" },
+	fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+	jQuery.fn[ name ] = function( speed, easing, callback ) {
+		return this.animate( props, speed, easing, callback );
+	};
+});
+
+jQuery.extend({
+	speed: function( speed, easing, fn ) {
+		var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+			complete: fn || !fn && easing ||
+				jQuery.isFunction( speed ) && speed,
+			duration: speed,
+			easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+		};
+
+		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+			opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+		// normalize opt.queue - true/undefined/null -> "fx"
+		if ( opt.queue == null || opt.queue === true ) {
+			opt.queue = "fx";
+		}
+
+		// Queueing
+		opt.old = opt.complete;
+
+		opt.complete = function( noUnmark ) {
+			if ( jQuery.isFunction( opt.old ) ) {
+				opt.old.call( this );
+			}
+
+			if ( opt.queue ) {
+				jQuery.dequeue( this, opt.queue );
+			} else if ( noUnmark !== false ) {
+				jQuery._unmark( this );
+			}
+		};
+
+		return opt;
+	},
+
+	easing: {
+		linear: function( p ) {
+			return p;
+		},
+		swing: function( p ) {
+			return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
+		}
+	},
+
+	timers: [],
+
+	fx: function( elem, options, prop ) {
+		this.options = options;
+		this.elem = elem;
+		this.prop = prop;
+
+		options.orig = options.orig || {};
+	}
+
+});
+
+jQuery.fx.prototype = {
+	// Simple function for setting a style value
+	update: function() {
+		if ( this.options.step ) {
+			this.options.step.call( this.elem, this.now, this );
+		}
+
+		( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
+	},
+
+	// Get the current size
+	cur: function() {
+		if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
+			return this.elem[ this.prop ];
+		}
+
+		var parsed,
+			r = jQuery.css( this.elem, this.prop );
+		// Empty strings, null, undefined and "auto" are converted to 0,
+		// complex values such as "rotate(1rad)" are returned as is,
+		// simple values such as "10px" are parsed to Float.
+		return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+	},
+
+	// Start an animation from one number to another
+	custom: function( from, to, unit ) {
+		var self = this,
+			fx = jQuery.fx;
+
+		this.startTime = fxNow || createFxNow();
+		this.end = to;
+		this.now = this.start = from;
+		this.pos = this.state = 0;
+		this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
+
+		function t( gotoEnd ) {
+			return self.step( gotoEnd );
+		}
+
+		t.queue = this.options.queue;
+		t.elem = this.elem;
+		t.saveState = function() {
+			if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+				if ( self.options.hide ) {
+					jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+				} else if ( self.options.show ) {
+					jQuery._data( self.elem, "fxshow" + self.prop, self.end );
+				}
+			}
+		};
+
+		if ( t() && jQuery.timers.push(t) && !timerId ) {
+			timerId = setInterval( fx.tick, fx.interval );
+		}
+	},
+
+	// Simple 'show' function
+	show: function() {
+		var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
+
+		// Remember where we started, so that we can go back to it later
+		this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
+		this.options.show = true;
+
+		// Begin the animation
+		// Make sure that we start at a small width/height to avoid any flash of content
+		if ( dataShow !== undefined ) {
+			// This show is picking up where a previous hide or show left off
+			this.custom( this.cur(), dataShow );
+		} else {
+			this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
+		}
+
+		// Start by showing the element
+		jQuery( this.elem ).show();
+	},
+
+	// Simple 'hide' function
+	hide: function() {
+		// Remember where we started, so that we can go back to it later
+		this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
+		this.options.hide = true;
+
+		// Begin the animation
+		this.custom( this.cur(), 0 );
+	},
+
+	// Each step of an animation
+	step: function( gotoEnd ) {
+		var p, n, complete,
+			t = fxNow || createFxNow(),
+			done = true,
+			elem = this.elem,
+			options = this.options;
+
+		if ( gotoEnd || t >= options.duration + this.startTime ) {
+			this.now = this.end;
+			this.pos = this.state = 1;
+			this.update();
+
+			options.animatedProperties[ this.prop ] = true;
+
+			for ( p in options.animatedProperties ) {
+				if ( options.animatedProperties[ p ] !== true ) {
+					done = false;
+				}
+			}
+
+			if ( done ) {
+				// Reset the overflow
+				if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+
+					jQuery.each( [ "", "X", "Y" ], function( index, value ) {
+						elem.style[ "overflow" + value ] = options.overflow[ index ];
+					});
+				}
+
+				// Hide the element if the "hide" operation was done
+				if ( options.hide ) {
+					jQuery( elem ).hide();
+				}
+
+				// Reset the properties, if the item has been hidden or shown
+				if ( options.hide || options.show ) {
+					for ( p in options.animatedProperties ) {
+						jQuery.style( elem, p, options.orig[ p ] );
+						jQuery.removeData( elem, "fxshow" + p, true );
+						// Toggle data is no longer needed
+						jQuery.removeData( elem, "toggle" + p, true );
+					}
+				}
+
+				// Execute the complete function
+				// in the event that the complete function throws an exception
+				// we must ensure it won't be called twice. #5684
+
+				complete = options.complete;
+				if ( complete ) {
+
+					options.complete = false;
+					complete.call( elem );
+				}
+			}
+
+			return false;
+
+		} else {
+			// classical easing cannot be used with an Infinity duration
+			if ( options.duration == Infinity ) {
+				this.now = t;
+			} else {
+				n = t - this.startTime;
+				this.state = n / options.duration;
+
+				// Perform the easing function, defaults to swing
+				this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
+				this.now = this.start + ( (this.end - this.start) * this.pos );
+			}
+			// Perform the next step of the animation
+			this.update();
+		}
+
+		return true;
+	}
+};
+
+jQuery.extend( jQuery.fx, {
+	tick: function() {
+		var timer,
+			timers = jQuery.timers,
+			i = 0;
+
+		for ( ; i < timers.length; i++ ) {
+			timer = timers[ i ];
+			// Checks the timer has not already been removed
+			if ( !timer() && timers[ i ] === timer ) {
+				timers.splice( i--, 1 );
+			}
+		}
+
+		if ( !timers.length ) {
+			jQuery.fx.stop();
+		}
+	},
+
+	interval: 13,
+
+	stop: function() {
+		clearInterval( timerId );
+		timerId = null;
+	},
+
+	speeds: {
+		slow: 600,
+		fast: 200,
+		// Default speed
+		_default: 400
+	},
+
+	step: {
+		opacity: function( fx ) {
+			jQuery.style( fx.elem, "opacity", fx.now );
+		},
+
+		_default: function( fx ) {
+			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+			} else {
+				fx.elem[ fx.prop ] = fx.now;
+			}
+		}
+	}
+});
+
+// Ensure props that can't be negative don't go there on undershoot easing
+jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
+	// exclude marginTop, marginLeft, marginBottom and marginRight from this list
+	if ( prop.indexOf( "margin" ) ) {
+		jQuery.fx.step[ prop ] = function( fx ) {
+			jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
+		};
+	}
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+	jQuery.expr.filters.animated = function( elem ) {
+		return jQuery.grep(jQuery.timers, function( fn ) {
+			return elem === fn.elem;
+		}).length;
+	};
+}
+
+// Try to restore the default display value of an element
+function defaultDisplay( nodeName ) {
+
+	if ( !elemdisplay[ nodeName ] ) {
+
+		var body = document.body,
+			elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
+			display = elem.css( "display" );
+		elem.remove();
+
+		// If the simple way fails,
+		// get element's real default display by attaching it to a temp iframe
+		if ( display === "none" || display === "" ) {
+			// No iframe to use yet, so create it
+			if ( !iframe ) {
+				iframe = document.createElement( "iframe" );
+				iframe.frameBorder = iframe.width = iframe.height = 0;
+			}
+
+			body.appendChild( iframe );
+
+			// Create a cacheable copy of the iframe document on first call.
+			// IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+			// document to it; WebKit & Firefox won't allow reusing the iframe document.
+			if ( !iframeDoc || !iframe.createElement ) {
+				iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+				iframeDoc.write( ( jQuery.support.boxModel ? "<!doctype html>" : "" ) + "<html><body>" );
+				iframeDoc.close();
+			}
+
+			elem = iframeDoc.createElement( nodeName );
+
+			iframeDoc.body.appendChild( elem );
+
+			display = jQuery.css( elem, "display" );
+			body.removeChild( iframe );
+		}
+
+		// Store the correct default display
+		elemdisplay[ nodeName ] = display;
+	}
+
+	return elemdisplay[ nodeName ];
+}
+
+
+
+
+var getOffset,
+	rtable = /^t(?:able|d|h)$/i,
+	rroot = /^(?:body|html)$/i;
+
+if ( "getBoundingClientRect" in document.documentElement ) {
+	getOffset = function( elem, doc, docElem, box ) {
+		try {
+			box = elem.getBoundingClientRect();
+		} catch(e) {}
+
+		// Make sure we're not dealing with a disconnected DOM node
+		if ( !box || !jQuery.contains( docElem, elem ) ) {
+			return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+		}
+
+		var body = doc.body,
+			win = getWindow( doc ),
+			clientTop  = docElem.clientTop  || body.clientTop  || 0,
+			clientLeft = docElem.clientLeft || body.clientLeft || 0,
+			scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
+			scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+			top  = box.top  + scrollTop  - clientTop,
+			left = box.left + scrollLeft - clientLeft;
+
+		return { top: top, left: left };
+	};
+
+} else {
+	getOffset = function( elem, doc, docElem ) {
+		var computedStyle,
+			offsetParent = elem.offsetParent,
+			prevOffsetParent = elem,
+			body = doc.body,
+			defaultView = doc.defaultView,
+			prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+			top = elem.offsetTop,
+			left = elem.offsetLeft;
+
+		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+			if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+				break;
+			}
+
+			computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+			top  -= elem.scrollTop;
+			left -= elem.scrollLeft;
+
+			if ( elem === offsetParent ) {
+				top  += elem.offsetTop;
+				left += elem.offsetLeft;
+
+				if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+					top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+					left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+				}
+
+				prevOffsetParent = offsetParent;
+				offsetParent = elem.offsetParent;
+			}
+
+			if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+				top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+				left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+			}
+
+			prevComputedStyle = computedStyle;
+		}
+
+		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+			top  += body.offsetTop;
+			left += body.offsetLeft;
+		}
+
+		if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+			top  += Math.max( docElem.scrollTop, body.scrollTop );
+			left += Math.max( docElem.scrollLeft, body.scrollLeft );
+		}
+
+		return { top: top, left: left };
+	};
+}
+
+jQuery.fn.offset = function( options ) {
+	if ( arguments.length ) {
+		return options === undefined ?
+			this :
+			this.each(function( i ) {
+				jQuery.offset.setOffset( this, options, i );
+			});
+	}
+
+	var elem = this[0],
+		doc = elem && elem.ownerDocument;
+
+	if ( !doc ) {
+		return null;
+	}
+
+	if ( elem === doc.body ) {
+		return jQuery.offset.bodyOffset( elem );
+	}
+
+	return getOffset( elem, doc, doc.documentElement );
+};
+
+jQuery.offset = {
+
+	bodyOffset: function( body ) {
+		var top = body.offsetTop,
+			left = body.offsetLeft;
+
+		if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
+			top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+			left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+		}
+
+		return { top: top, left: left };
+	},
+
+	setOffset: function( elem, options, i ) {
+		var position = jQuery.css( elem, "position" );
+
+		// set position first, in-case top/left are set even on static elem
+		if ( position === "static" ) {
+			elem.style.position = "relative";
+		}
+
+		var curElem = jQuery( elem ),
+			curOffset = curElem.offset(),
+			curCSSTop = jQuery.css( elem, "top" ),
+			curCSSLeft = jQuery.css( elem, "left" ),
+			calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+			props = {}, curPosition = {}, curTop, curLeft;
+
+		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+		if ( calculatePosition ) {
+			curPosition = curElem.position();
+			curTop = curPosition.top;
+			curLeft = curPosition.left;
+		} else {
+			curTop = parseFloat( curCSSTop ) || 0;
+			curLeft = parseFloat( curCSSLeft ) || 0;
+		}
+
+		if ( jQuery.isFunction( options ) ) {
+			options = options.call( elem, i, curOffset );
+		}
+
+		if ( options.top != null ) {
+			props.top = ( options.top - curOffset.top ) + curTop;
+		}
+		if ( options.left != null ) {
+			props.left = ( options.left - curOffset.left ) + curLeft;
+		}
+
+		if ( "using" in options ) {
+			options.using.call( elem, props );
+		} else {
+			curElem.css( props );
+		}
+	}
+};
+
+
+jQuery.fn.extend({
+
+	position: function() {
+		if ( !this[0] ) {
+			return null;
+		}
+
+		var elem = this[0],
+
+		// Get *real* offsetParent
+		offsetParent = this.offsetParent(),
+
+		// Get correct offsets
+		offset       = this.offset(),
+		parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+		// Subtract element margins
+		// note: when an element has margin: auto the offsetLeft and marginLeft
+		// are the same in Safari causing offset.left to incorrectly be 0
+		offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+		offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+		// Add offsetParent borders
+		parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+		parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+		// Subtract the two offsets
+		return {
+			top:  offset.top  - parentOffset.top,
+			left: offset.left - parentOffset.left
+		};
+	},
+
+	offsetParent: function() {
+		return this.map(function() {
+			var offsetParent = this.offsetParent || document.body;
+			while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+				offsetParent = offsetParent.offsetParent;
+			}
+			return offsetParent;
+		});
+	}
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+	var top = /Y/.test( prop );
+
+	jQuery.fn[ method ] = function( val ) {
+		return jQuery.access( this, function( elem, method, val ) {
+			var win = getWindow( elem );
+
+			if ( val === undefined ) {
+				return win ? (prop in win) ? win[ prop ] :
+					jQuery.support.boxModel && win.document.documentElement[ method ] ||
+						win.document.body[ method ] :
+					elem[ method ];
+			}
+
+			if ( win ) {
+				win.scrollTo(
+					!top ? val : jQuery( win ).scrollLeft(),
+					 top ? val : jQuery( win ).scrollTop()
+				);
+
+			} else {
+				elem[ method ] = val;
+			}
+		}, method, val, arguments.length, null );
+	};
+});
+
+function getWindow( elem ) {
+	return jQuery.isWindow( elem ) ?
+		elem :
+		elem.nodeType === 9 ?
+			elem.defaultView || elem.parentWindow :
+			false;
+}
+
+
+
+
+// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+	var clientProp = "client" + name,
+		scrollProp = "scroll" + name,
+		offsetProp = "offset" + name;
+
+	// innerHeight and innerWidth
+	jQuery.fn[ "inner" + name ] = function() {
+		var elem = this[0];
+		return elem ?
+			elem.style ?
+			parseFloat( jQuery.css( elem, type, "padding" ) ) :
+			this[ type ]() :
+			null;
+	};
+
+	// outerHeight and outerWidth
+	jQuery.fn[ "outer" + name ] = function( margin ) {
+		var elem = this[0];
+		return elem ?
+			elem.style ?
+			parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+			this[ type ]() :
+			null;
+	};
+
+	jQuery.fn[ type ] = function( value ) {
+		return jQuery.access( this, function( elem, type, value ) {
+			var doc, docElemProp, orig, ret;
+
+			if ( jQuery.isWindow( elem ) ) {
+				// 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+				doc = elem.document;
+				docElemProp = doc.documentElement[ clientProp ];
+				return jQuery.support.boxModel && docElemProp ||
+					doc.body && doc.body[ clientProp ] || docElemProp;
+			}
+
+			// Get document width or height
+			if ( elem.nodeType === 9 ) {
+				// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+				doc = elem.documentElement;
+
+				// when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
+				// so we can't use max, as it'll choose the incorrect offset[Width/Height]
+				// instead we use the correct client[Width/Height]
+				// support:IE6
+				if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
+					return doc[ clientProp ];
+				}
+
+				return Math.max(
+					elem.body[ scrollProp ], doc[ scrollProp ],
+					elem.body[ offsetProp ], doc[ offsetProp ]
+				);
+			}
+
+			// Get width or height on the element
+			if ( value === undefined ) {
+				orig = jQuery.css( elem, type );
+				ret = parseFloat( orig );
+				return jQuery.isNumeric( ret ) ? ret : orig;
+			}
+
+			// Set the width or height on the element
+			jQuery( elem ).css( type, value );
+		}, type, value, arguments.length, null );
+	};
+});
+
+
+
+
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+	define( "jquery", [], function () { return jQuery; } );
+}
+
+
+
+})( window );
diff --git a/ap/app/zte_webui/js/3rd/require-text.js b/ap/app/zte_webui/js/3rd/require-text.js
new file mode 100755
index 0000000..4c13a84
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/require-text.js
@@ -0,0 +1 @@
+(function(){var a=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"],h=/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,g=/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,c=typeof location!=="undefined"&&location.href,f=c&&location.protocol&&location.protocol.replace(/\:/,""),e=c&&location.hostname,d=c&&(location.port||void 0),b=[];define(function(){var k,j,i;typeof window!=="undefined"&&window.navigator&&window.document?j=function(m,n){var l=k.createXhr();l.open("GET",m,!0);l.onreadystatechange=function(){l.readyState===4&&n(l.responseText)};l.send(null)}:typeof process!=="undefined"&&process.versions&&process.versions.node?(i=require.nodeRequire("fs"),j=function(m,n){var l=i.readFileSync(m,"utf8");l.indexOf("\ufeff")===0&&(l=l.substring(1));n(l)}):typeof Packages!=="undefined"&&(j=function(m,r){var l=new java.io.File(m),p=java.lang.System.getProperty("line.separator"),l=new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(l),"utf-8")),q,o,n="";try{q=new java.lang.StringBuffer;(o=l.readLine())&&o.length()&&o.charAt(0)===65279&&(o=o.substring(1));for(q.append(o);(o=l.readLine())!==null;){q.append(p),q.append(o)}n=String(q.toString())}finally{l.close()}r(n)});return k={version:"0.0.0",strip:function(l){if(l){var l=l.replace(h,""),m=l.match(g);m&&(l=m[1])}else{l=""}return l},jsEscape:function(l){return l.replace(/(['\\])/g,"\\$1").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r")},createXhr:function(){var m,o,l;if(typeof XMLHttpRequest!=="undefined"){return new XMLHttpRequest}else{for(o=0;o<3;o++){l=a[o];try{m=new ActiveXObject(l)}catch(n){}if(m){a=[l];break}}}if(!m){throw Error("createXhr(): XMLHttpRequest not available")}return m},get:j,parseName:function(m){var o=!1,l=m.indexOf("."),n=m.substring(0,l),m=m.substring(l+1,m.length),l=m.indexOf("!");l!==-1&&(o=m.substring(l+1,m.length),o=o==="strip",m=m.substring(0,l));return{moduleName:n,ext:m,strip:o}},xdRegExp:/^((\w+)\:)?\/\/([^\/\\]+)/,useXhr:function(m,q,l,o){var p=k.xdRegExp.exec(m),n;if(!p){return !0}m=p[2];p=p[3];p=p.split(":");n=p[1];p=p[0];return(!m||m===q)&&(!p||p===l)&&(!n&&!p||n===o)},finishLoad:function(m,p,l,n,o){l=p?k.strip(l):l;o.isBuild&&(b[m]=l);n(l)},load:function(o,t,n,r){if(r.isBuild&&!r.inlineText){n()}else{var s=k.parseName(o),q=s.moduleName+"."+s.ext,l=t.toUrl(q),p=r&&r.text&&r.text.useXhr||k.useXhr;!c||p(l,f,e,d)?k.get(l,function(m){k.finishLoad(o,s.strip,m,n,r)}):t([q],function(m){k.finishLoad(s.moduleName+"."+s.ext,s.strip,m,n,r)})}},write:function(m,o,l){if(o in b){var n=k.jsEscape(b[o]);l.asModule(m+"!"+o,"define(function () { return '"+n+"';});\n")}},writeFile:function(m,r,l,p,q){var r=k.parseName(r),o=r.moduleName+"."+r.ext,n=l.toUrl(r.moduleName+"."+r.ext)+".js";k.load(o,l,function(){var s=function(t){return p(n,t)};s.asModule=function(u,t){return p.asModule(u,n,t)};k.write(m,o,s,q)},q)}}})})();
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/respond.js b/ap/app/zte_webui/js/3rd/respond.js
new file mode 100755
index 0000000..df51dd2
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/respond.js
@@ -0,0 +1 @@
+!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b<t.length;b++){var c=t[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!p[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(w(c.styleSheet.rawCssText,e,f),p[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!s||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}x()};y(),c.update=y,c.getEmValue=u,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/3rd/twbs.bootstrap.js b/ap/app/zte_webui/js/3rd/twbs.bootstrap.js
new file mode 100755
index 0000000..80c95e0
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/twbs.bootstrap.js
@@ -0,0 +1,2145 @@
+/*
+ * Bootstrap v3.2.0 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+/*
+ * Generated using the Bootstrap Customizer (http://v3.bootcss.com/customize/?id=b2e1a5d6b5546208291d)
+ * Config saved to config.json and https://gist.github.com/b2e1a5d6b5546208291d
+ */
+if (typeof jQuery === "undefined") { throw new Error("Bootstrap's JavaScript requires jQuery") }
+
+/* ========================================================================
+ * Bootstrap: alert.js v3.2.0
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // ALERT CLASS DEFINITION
+  // ======================
+
+  var dismiss = '[data-dismiss="alert"]'
+  var Alert   = function (el) {
+    $(el).on('click', dismiss, this.close)
+  }
+
+  Alert.VERSION = '0.0.0'
+
+  Alert.prototype.close = function (e) {
+    var $this    = $(this)
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    //var $parent = $(selector)    CVE-2016-10735
+    selector = selector === '#' ? [] : selector
+    var $parent = $(document).find(selector)
+
+    if (e) e.preventDefault()
+
+    if (!$parent.length) {
+      $parent = $this.hasClass('alert') ? $this : $this.parent()
+    }
+
+    $parent.trigger(e = $.Event('close.bs.alert'))
+
+    if (e.isDefaultPrevented()) return
+
+    $parent.removeClass('in')
+
+    function removeElement() {
+      // detach from parent, fire event then clean up data
+      $parent.detach().trigger('closed.bs.alert').remove()
+    }
+
+    $.support.transition && $parent.hasClass('fade') ?
+      $parent
+        .one('bsTransitionEnd', removeElement)
+        .emulateTransitionEnd(150) :
+      removeElement()
+  }
+
+
+  // ALERT PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.alert')
+
+      if (!data) $this.data('bs.alert', (data = new Alert(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  var old = $.fn.alert
+
+  $.fn.alert             = Plugin
+  $.fn.alert.Constructor = Alert
+
+
+  // ALERT NO CONFLICT
+  // =================
+
+  $.fn.alert.noConflict = function () {
+    $.fn.alert = old
+    return this
+  }
+
+
+  // ALERT DATA-API
+  // ==============
+
+  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: button.js v3.2.0
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // BUTTON PUBLIC CLASS DEFINITION
+  // ==============================
+
+  var Button = function (element, options) {
+    this.$element  = $(element)
+    this.options   = $.extend({}, Button.DEFAULTS, options)
+    this.isLoading = false
+  }
+
+  Button.VERSION  = '0.0.0'
+
+  Button.DEFAULTS = {
+    loadingText: 'loading...'
+  }
+
+  Button.prototype.setState = function (state) {
+    var d    = 'disabled'
+    var $el  = this.$element
+    var val  = $el.is('input') ? 'val' : 'html'
+    var data = $el.data()
+
+    state = state + 'Text'
+
+    if (data.resetText == null) $el.data('resetText', $el[val]())
+
+    $el[val](data[state] == null ? this.options[state] : data[state])
+
+    // push to event loop to allow forms to submit
+    setTimeout($.proxy(function () {
+      if (state == 'loadingText') {
+        this.isLoading = true
+        $el.addClass(d).attr(d, d)
+      } else if (this.isLoading) {
+        this.isLoading = false
+        $el.removeClass(d).removeAttr(d)
+      }
+    }, this), 0)
+  }
+
+  Button.prototype.toggle = function () {
+    var changed = true
+    var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+    if ($parent.length) {
+      var $input = this.$element.find('input')
+      if ($input.prop('type') == 'radio') {
+        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
+        else $parent.find('.active').removeClass('active')
+      }
+      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
+    }
+
+    if (changed) this.$element.toggleClass('active')
+  }
+
+
+  // BUTTON PLUGIN DEFINITION
+  // ========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.button')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+      if (option == 'toggle') data.toggle()
+      else if (option) data.setState(option)
+    })
+  }
+
+  var old = $.fn.button
+
+  $.fn.button             = Plugin
+  $.fn.button.Constructor = Button
+
+
+  // BUTTON NO CONFLICT
+  // ==================
+
+  $.fn.button.noConflict = function () {
+    $.fn.button = old
+    return this
+  }
+
+
+  // BUTTON DATA-API
+  // ===============
+
+  $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+    var $btn = $(e.target)
+    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+    Plugin.call($btn, 'toggle')
+    e.preventDefault()
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.2.0
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // CAROUSEL CLASS DEFINITION
+  // =========================
+
+  var Carousel = function (element, options) {
+    this.$element    = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this))
+    this.$indicators = this.$element.find('.carousel-indicators')
+    this.options     = options
+    this.paused      =
+    this.sliding     =
+    this.interval    =
+    this.$active     =
+    this.$items      = null
+
+    this.options.pause == 'hover' && this.$element
+      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
+      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
+  }
+
+  Carousel.VERSION  = '0.0.0'
+
+  Carousel.DEFAULTS = {
+    interval: 5000,
+    pause: 'hover',
+    wrap: true
+  }
+
+  Carousel.prototype.keydown = function (e) {
+    switch (e.which) {
+      case 37: this.prev(); break
+      case 39: this.next(); break
+      default: return
+    }
+
+    e.preventDefault()
+  }
+
+  Carousel.prototype.cycle = function (e) {
+    e || (this.paused = false)
+
+    this.interval && clearInterval(this.interval)
+
+    this.options.interval
+      && !this.paused
+      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+    return this
+  }
+
+  Carousel.prototype.getItemIndex = function (item) {
+    this.$items = item.parent().children('.item')
+    return this.$items.index(item || this.$active)
+  }
+
+  Carousel.prototype.to = function (pos) {
+    var that        = this
+    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
+
+    if (pos > (this.$items.length - 1) || pos < 0) return
+
+    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
+    if (activeIndex == pos) return this.pause().cycle()
+
+    return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
+  }
+
+  Carousel.prototype.pause = function (e) {
+    e || (this.paused = true)
+
+    if (this.$element.find('.next, .prev').length && $.support.transition) {
+      this.$element.trigger($.support.transition.end)
+      this.cycle(true)
+    }
+
+    this.interval = clearInterval(this.interval)
+
+    return this
+  }
+
+  Carousel.prototype.next = function () {
+    if (this.sliding) return
+    return this.slide('next')
+  }
+
+  Carousel.prototype.prev = function () {
+    if (this.sliding) return
+    return this.slide('prev')
+  }
+
+  Carousel.prototype.slide = function (type, next) {
+    var $active   = this.$element.find('.item.active')
+    var $next     = next || $active[type]()
+    var isCycling = this.interval
+    var direction = type == 'next' ? 'left' : 'right'
+    var fallback  = type == 'next' ? 'first' : 'last'
+    var that      = this
+
+    if (!$next.length) {
+      if (!this.options.wrap) return
+      $next = this.$element.find('.item')[fallback]()
+    }
+
+    if ($next.hasClass('active')) return (this.sliding = false)
+
+    var relatedTarget = $next[0]
+    var slideEvent = $.Event('slide.bs.carousel', {
+      relatedTarget: relatedTarget,
+      direction: direction
+    })
+    this.$element.trigger(slideEvent)
+    if (slideEvent.isDefaultPrevented()) return
+
+    this.sliding = true
+
+    isCycling && this.pause()
+
+    if (this.$indicators.length) {
+      this.$indicators.find('.active').removeClass('active')
+      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
+      $nextIndicator && $nextIndicator.addClass('active')
+    }
+
+    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
+    if ($.support.transition && this.$element.hasClass('slide')) {
+      $next.addClass(type)
+      $next[0].offsetWidth // force reflow
+      $active.addClass(direction)
+      $next.addClass(direction)
+      $active
+        .one('bsTransitionEnd', function () {
+          $next.removeClass([type, direction].join(' ')).addClass('active')
+          $active.removeClass(['active', direction].join(' '))
+          that.sliding = false
+          setTimeout(function () {
+            that.$element.trigger(slidEvent)
+          }, 0)
+        })
+        .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
+    } else {
+      $active.removeClass('active')
+      $next.addClass('active')
+      this.sliding = false
+      this.$element.trigger(slidEvent)
+    }
+
+    isCycling && this.cycle()
+
+    return this
+  }
+
+
+  // CAROUSEL PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.carousel')
+      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+      var action  = typeof option == 'string' ? option : options.slide
+
+      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+      if (typeof option == 'number') data.to(option)
+      else if (action) data[action]()
+      else if (options.interval) data.pause().cycle()
+    })
+  }
+
+  var old = $.fn.carousel
+
+  $.fn.carousel             = Plugin
+  $.fn.carousel.Constructor = Carousel
+
+
+  // CAROUSEL NO CONFLICT
+  // ====================
+
+  $.fn.carousel.noConflict = function () {
+    $.fn.carousel = old
+    return this
+  }
+
+
+  // CAROUSEL DATA-API
+  // =================
+
+  $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
+    //var href    //CVE-2016-10735
+    var $this   = $(this)
+    //var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+    var href    = $this.attr('href')
+    if (href) {
+      href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+    }
+
+    var target  = $this.attr('data-target') || href
+    var $target = $(document).find(target)
+
+    if (!$target.hasClass('carousel')) return
+    var options = $.extend({}, $target.data(), $this.data())
+    var slideIndex = $this.attr('data-slide-to')
+    if (slideIndex) options.interval = false
+
+    Plugin.call($target, options)
+
+    if (slideIndex) {
+      $target.data('bs.carousel').to(slideIndex)
+    }
+
+    e.preventDefault()
+  })
+
+  $(window).on('load', function () {
+    $('[data-ride="carousel"]').each(function () {
+      var $carousel = $(this)
+      Plugin.call($carousel, $carousel.data())
+    })
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.2.0
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // DROPDOWN CLASS DEFINITION
+  // =========================
+
+  var backdrop = '.dropdown-backdrop'
+  var toggle   = '[data-toggle="dropdown"]'
+  var Dropdown = function (element) {
+    $(element).on('click.bs.dropdown', this.toggle)
+  }
+
+  Dropdown.VERSION = '0.0.0'
+
+  Dropdown.prototype.toggle = function (e) {
+    var $this = $(this)
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    clearMenus()
+
+    if (!isActive) {
+      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+        // if mobile we use a backdrop because click events don't delegate
+        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
+      }
+
+      var relatedTarget = { relatedTarget: this }
+      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+      if (e.isDefaultPrevented()) return
+
+      $this.trigger('focus')
+
+      $parent
+        .toggleClass('open')
+        .trigger('shown.bs.dropdown', relatedTarget)
+    }
+
+    return false
+  }
+
+  Dropdown.prototype.keydown = function (e) {
+    if (!/(38|40|27)/.test(e.keyCode)) return
+
+    var $this = $(this)
+
+    e.preventDefault()
+    e.stopPropagation()
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    if (!isActive || (isActive && e.keyCode == 27)) {
+      if (e.which == 27) $parent.find(toggle).trigger('focus')
+      return $this.trigger('click')
+    }
+
+    var desc = ' li:not(.divider):visible a'
+    var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
+
+    if (!$items.length) return
+
+    var index = $items.index($items.filter(':focus'))
+
+    if (e.keyCode == 38 && index > 0)                 index--                        // up
+    if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
+    if (!~index)                                      index = 0
+
+    $items.eq(index).trigger('focus')
+  }
+
+  function clearMenus(e) {
+    if (e && e.which === 3) return
+    $(backdrop).remove()
+    $(toggle).each(function () {
+      var $parent = getParent($(this))
+      var relatedTarget = { relatedTarget: this }
+      if (!$parent.hasClass('open')) return
+      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+      if (e.isDefaultPrevented()) return
+      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+    })
+  }
+
+  function getParent($this) {
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    //var $parent = selector && $(selector)    CVE-2016-10735
+    var $parent = selector && $(document).find(selector)
+
+    return $parent && $parent.length ? $parent : $this.parent()
+  }
+
+
+  // DROPDOWN PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.dropdown')
+
+      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  var old = $.fn.dropdown
+
+  $.fn.dropdown             = Plugin
+  $.fn.dropdown.Constructor = Dropdown
+
+
+  // DROPDOWN NO CONFLICT
+  // ====================
+
+  $.fn.dropdown.noConflict = function () {
+    $.fn.dropdown = old
+    return this
+  }
+
+
+  // APPLY TO STANDARD DROPDOWN ELEMENTS
+  // ===================================
+
+  $(document)
+    .on('click.bs.dropdown.data-api', clearMenus)
+    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+    .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.2.0
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // MODAL CLASS DEFINITION
+  // ======================
+
+  var Modal = function (element, options) {
+    this.options        = options
+    this.$body          = $(document.body)
+    this.$element       = $(element)
+    this.$backdrop      =
+    this.isShown        = null
+    this.scrollbarWidth = 0
+
+    if (this.options.remote) {
+      this.$element
+        .find('.modal-content')
+        .load(this.options.remote, $.proxy(function () {
+          this.$element.trigger('loaded.bs.modal')
+        }, this))
+    }
+  }
+
+  Modal.VERSION  = '0.0.0'
+
+  Modal.DEFAULTS = {
+    backdrop: true,
+    keyboard: true,
+    show: true
+  }
+
+  Modal.prototype.toggle = function (_relatedTarget) {
+    return this.isShown ? this.hide() : this.show(_relatedTarget)
+  }
+
+  Modal.prototype.show = function (_relatedTarget) {
+    var that = this
+    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+    this.$element.trigger(e)
+
+    if (this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = true
+
+    this.checkScrollbar()
+    this.$body.addClass('modal-open')
+
+    this.setScrollbar()
+    this.escape()
+
+    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+    this.backdrop(function () {
+      var transition = $.support.transition && that.$element.hasClass('fade')
+
+      if (!that.$element.parent().length) {
+        that.$element.appendTo(that.$body) // don't move modals dom position
+      }
+
+      that.$element
+        .show()
+        .scrollTop(0)
+
+      if (transition) {
+        that.$element[0].offsetWidth // force reflow
+      }
+
+      that.$element
+        .addClass('in')
+        .attr('aria-hidden', false)
+
+      that.enforceFocus()
+
+      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+      transition ?
+        that.$element.find('.modal-dialog') // wait for modal to slide in
+          .one('bsTransitionEnd', function () {
+            that.$element.trigger('focus').trigger(e)
+          })
+          .emulateTransitionEnd(300) :
+        that.$element.trigger('focus').trigger(e)
+    })
+  }
+
+  Modal.prototype.hide = function (e) {
+    if (e) e.preventDefault()
+
+    e = $.Event('hide.bs.modal')
+
+    this.$element.trigger(e)
+
+    if (!this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = false
+
+    this.$body.removeClass('modal-open')
+
+    this.resetScrollbar()
+    this.escape()
+
+    $(document).off('focusin.bs.modal')
+
+    this.$element
+      .removeClass('in')
+      .attr('aria-hidden', true)
+      .off('click.dismiss.bs.modal')
+
+    $.support.transition && this.$element.hasClass('fade') ?
+      this.$element
+        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
+        .emulateTransitionEnd(300) :
+      this.hideModal()
+  }
+
+  Modal.prototype.enforceFocus = function () {
+    $(document)
+      .off('focusin.bs.modal') // guard against infinite focus loop
+      .on('focusin.bs.modal', $.proxy(function (e) {
+        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+          this.$element.trigger('focus')
+        }
+      }, this))
+  }
+
+  Modal.prototype.escape = function () {
+    if (this.isShown && this.options.keyboard) {
+      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
+        e.which == 27 && this.hide()
+      }, this))
+    } else if (!this.isShown) {
+      this.$element.off('keydown.dismiss.bs.modal')
+    }
+  }
+
+  Modal.prototype.hideModal = function () {
+    var that = this
+    this.$element.hide()
+    this.backdrop(function () {
+      that.$element.trigger('hidden.bs.modal')
+    })
+  }
+
+  Modal.prototype.removeBackdrop = function () {
+    this.$backdrop && this.$backdrop.remove()
+    this.$backdrop = null
+  }
+
+  Modal.prototype.backdrop = function (callback) {
+    var that = this
+    var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+    if (this.isShown && this.options.backdrop) {
+      var doAnimate = $.support.transition && animate
+
+      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+        .appendTo(this.$body)
+
+      this.$element.on('mousedown.dismiss.bs.modal', $.proxy(function (e) {
+        if (e.target !== e.currentTarget) return
+        this.options.backdrop == 'static'
+          ? this.$element[0].focus.call(this.$element[0])
+          : this.hide.call(this)
+      }, this))
+
+      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+      this.$backdrop.addClass('in')
+
+      if (!callback) return
+
+      doAnimate ?
+        this.$backdrop
+          .one('bsTransitionEnd', callback)
+          .emulateTransitionEnd(150) :
+        callback()
+
+    } else if (!this.isShown && this.$backdrop) {
+      this.$backdrop.removeClass('in')
+
+      var callbackRemove = function () {
+        that.removeBackdrop()
+        callback && callback()
+      }
+      $.support.transition && this.$element.hasClass('fade') ?
+        this.$backdrop
+          .one('bsTransitionEnd', callbackRemove)
+          .emulateTransitionEnd(150) :
+        callbackRemove()
+
+    } else if (callback) {
+      callback()
+    }
+  }
+
+  Modal.prototype.checkScrollbar = function () {
+    if (document.body.clientWidth >= window.innerWidth) return
+    this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
+  }
+
+  Modal.prototype.setScrollbar = function () {
+    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
+    if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+  }
+
+  Modal.prototype.resetScrollbar = function () {
+    this.$body.css('padding-right', '')
+  }
+
+  Modal.prototype.measureScrollbar = function () { // thx walsh
+    var scrollDiv = document.createElement('div')
+    scrollDiv.className = 'modal-scrollbar-measure'
+    this.$body.append(scrollDiv)
+    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+    this.$body[0].removeChild(scrollDiv)
+    return scrollbarWidth
+  }
+
+
+  // MODAL PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option, _relatedTarget) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.modal')
+      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+      if (typeof option == 'string') data[option](_relatedTarget)
+      else if (options.show) data.show(_relatedTarget)
+    })
+  }
+
+  var old = $.fn.modal
+
+  $.fn.modal             = Plugin
+  $.fn.modal.Constructor = Modal
+
+
+  // MODAL NO CONFLICT
+  // =================
+
+  $.fn.modal.noConflict = function () {
+    $.fn.modal = old
+    return this
+  }
+
+
+  // MODAL DATA-API
+  // ==============
+
+  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+    var $this   = $(this)
+    var href    = $this.attr('href')
+    //var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7    CVE-2016-10735
+    var target  = $this.attr('data-target') ||
+      (href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+
+    var $target = $(document).find(target)
+    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+    if ($this.is('a')) e.preventDefault()
+
+    $target.one('show.bs.modal', function (showEvent) {
+      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
+      $target.one('hidden.bs.modal', function () {
+        $this.is(':visible') && $this.trigger('focus')
+      })
+    })
+    Plugin.call($target, option, this)
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.2.0
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TOOLTIP PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Tooltip = function (element, options) {
+    this.type       =
+    this.options    =
+    this.enabled    =
+    this.timeout    =
+    this.hoverState =
+    this.$element   = null
+
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.VERSION  = '0.0.0'
+
+  Tooltip.DEFAULTS = {
+    animation: true,
+    placement: 'top',
+    selector: false,
+    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+    trigger: 'hover focus',
+    title: '',
+    delay: 0,
+    html: false,
+    container: false,
+    viewport: {
+      selector: 'body',
+      padding: 0
+    }
+  }
+
+  Tooltip.prototype.init = function (type, element, options) {
+    this.enabled   = true
+    this.type      = type
+    this.$element  = $(element)
+    this.options   = this.getOptions(options)
+    //this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)    CVE-2018-20676 & CVE-2018-20677
+    this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
+
+    var triggers = this.options.trigger.split(' ')
+
+    for (var i = triggers.length; i--;) {
+      var trigger = triggers[i]
+
+      if (trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (trigger != 'manual') {
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+      }
+    }
+
+    this.options.selector ?
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+      this.fixTitle()
+  }
+
+  Tooltip.prototype.getDefaults = function () {
+    return Tooltip.DEFAULTS
+  }
+
+  Tooltip.prototype.getOptions = function (options) {
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+    if (options.delay && typeof options.delay == 'number') {
+      options.delay = {
+        show: options.delay,
+        hide: options.delay
+      }
+    }
+
+    return options
+  }
+
+  Tooltip.prototype.getDelegateOptions = function () {
+    var options  = {}
+    var defaults = this.getDefaults()
+
+    this._options && $.each(this._options, function (key, value) {
+      if (defaults[key] != value) options[key] = value
+    })
+
+    return options
+  }
+
+  Tooltip.prototype.enter = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget).data('bs.' + this.type)
+
+    if (!self) {
+      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+      $(obj.currentTarget).data('bs.' + this.type, self)
+    }
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'in'
+
+    if (!self.options.delay || !self.options.delay.show) return self.show()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'in') self.show()
+    }, self.options.delay.show)
+  }
+
+  Tooltip.prototype.leave = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget).data('bs.' + this.type)
+
+    if (!self) {
+      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+      $(obj.currentTarget).data('bs.' + this.type, self)
+    }
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'out'
+
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'out') self.hide()
+    }, self.options.delay.hide)
+  }
+
+  Tooltip.prototype.show = function () {
+    var e = $.Event('show.bs.' + this.type)
+
+    if (this.hasContent() && this.enabled) {
+      this.$element.trigger(e)
+
+      var inDom = $.contains(document.documentElement, this.$element[0])
+      if (e.isDefaultPrevented() || !inDom) return
+      var that = this
+
+      var $tip = this.tip()
+
+      var tipId = this.getUID(this.type)
+
+      this.setContent()
+      $tip.attr('id', tipId)
+      this.$element.attr('aria-describedby', tipId)
+
+      if (this.options.animation) $tip.addClass('fade')
+
+      var placement = typeof this.options.placement == 'function' ?
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
+        this.options.placement
+
+      var autoToken = /\s?auto?\s?/i
+      var autoPlace = autoToken.test(placement)
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+      $tip
+        .detach()
+        .css({ top: 0, left: 0, display: 'block' })
+        .addClass(placement)
+        .data('bs.' + this.type, this)
+
+      //this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)    CVE-2018-20676 & CVE-2018-20677
+      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
+
+      var pos          = this.getPosition()
+      var actualWidth  = $tip[0].offsetWidth
+      var actualHeight = $tip[0].offsetHeight
+
+      if (autoPlace) {
+        var orgPlacement = placement
+        var $parent      = this.$element.parent()
+        var parentDim    = this.getPosition($parent)
+
+        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
+                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
+                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
+                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
+                    placement
+
+        $tip
+          .removeClass(orgPlacement)
+          .addClass(placement)
+      }
+
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+      this.applyPlacement(calculatedOffset, placement)
+
+      var complete = function () {
+        that.$element.trigger('shown.bs.' + that.type)
+        that.hoverState = null
+      }
+
+      $.support.transition && this.$tip.hasClass('fade') ?
+        $tip
+          .one('bsTransitionEnd', complete)
+          .emulateTransitionEnd(150) :
+        complete()
+    }
+  }
+
+  Tooltip.prototype.applyPlacement = function (offset, placement) {
+    var $tip   = this.tip()
+    var width  = $tip[0].offsetWidth
+    var height = $tip[0].offsetHeight
+
+    // manually read margins because getBoundingClientRect includes difference
+    var marginTop = parseInt($tip.css('margin-top'), 10)
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+    // we must check for NaN for ie 8/9
+    if (isNaN(marginTop))  marginTop  = 0
+    if (isNaN(marginLeft)) marginLeft = 0
+
+    offset.top  = offset.top  + marginTop
+    offset.left = offset.left + marginLeft
+
+    // $.fn.offset doesn't round pixel values
+    // so we use setOffset directly with our own function B-0
+    $.offset.setOffset($tip[0], $.extend({
+      using: function (props) {
+        $tip.css({
+          top: Math.round(props.top),
+          left: Math.round(props.left)
+        })
+      }
+    }, offset), 0)
+
+    $tip.addClass('in')
+
+    // check to see if placing tip in new offset caused the tip to resize itself
+    var actualWidth  = $tip[0].offsetWidth
+    var actualHeight = $tip[0].offsetHeight
+
+    if (placement == 'top' && actualHeight != height) {
+      offset.top = offset.top + height - actualHeight
+    }
+
+    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
+
+    if (delta.left) offset.left += delta.left
+    else offset.top += delta.top
+
+    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+    var arrowPosition       = delta.left ? 'left'        : 'top'
+    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
+
+    $tip.offset(offset)
+    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
+  }
+
+  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
+    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
+  }
+
+  Tooltip.prototype.setContent = function () {
+    var $tip  = this.tip()
+    var title = this.getTitle()
+
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+    $tip.removeClass('fade in top bottom left right')
+  }
+
+  Tooltip.prototype.hide = function () {
+    var that = this
+    var $tip = this.tip()
+    var e    = $.Event('hide.bs.' + this.type)
+
+    this.$element.removeAttr('aria-describedby')
+
+    function complete() {
+      if (that.hoverState != 'in') $tip.detach()
+      that.$element.trigger('hidden.bs.' + that.type)
+    }
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    $tip.removeClass('in')
+
+    $.support.transition && this.$tip.hasClass('fade') ?
+      $tip
+        .one('bsTransitionEnd', complete)
+        .emulateTransitionEnd(150) :
+      complete()
+
+    this.hoverState = null
+
+    return this
+  }
+
+  Tooltip.prototype.fixTitle = function () {
+    var $e = this.$element
+    if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+    }
+  }
+
+  Tooltip.prototype.hasContent = function () {
+    return this.getTitle()
+  }
+
+  Tooltip.prototype.getPosition = function ($element) {
+    $element   = $element || this.$element
+
+    var el     = $element[0]
+    var isBody = el.tagName == 'BODY'
+    var isSvg  = window.SVGElement && el instanceof window.SVGElement
+
+    var elRect    = typeof el.getBoundingClientRect == 'function' ? el.getBoundingClientRect() : null
+    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
+    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+    var outerDims = isSvg ? {} : {
+      width:  isBody ? $(window).width()  : $element.outerWidth(),
+      height: isBody ? $(window).height() : $element.outerHeight()
+    }
+
+    return $.extend({}, elRect, scroll, outerDims, elOffset)
+  }
+
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
+
+  }
+
+  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+    var delta = { top: 0, left: 0 }
+    if (!this.$viewport) return delta
+
+    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+    var viewportDimensions = this.getPosition(this.$viewport)
+
+    if (/right|left/.test(placement)) {
+      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
+      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+      if (topEdgeOffset < viewportDimensions.top) { // top overflow
+        delta.top = viewportDimensions.top - topEdgeOffset
+      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+      }
+    } else {
+      var leftEdgeOffset  = pos.left - viewportPadding
+      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+        delta.left = viewportDimensions.left - leftEdgeOffset
+      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
+        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+      }
+    }
+
+    return delta
+  }
+
+  Tooltip.prototype.getTitle = function () {
+    var title
+    var $e = this.$element
+    var o  = this.options
+
+    title = $e.attr('data-original-title')
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+    return title
+  }
+
+  Tooltip.prototype.getUID = function (prefix) {
+    do prefix += ~~(Math.random() * 1000000)
+    while (document.getElementById(prefix))
+    return prefix
+  }
+
+  Tooltip.prototype.tip = function () {
+    return (this.$tip = this.$tip || $(this.options.template))
+  }
+
+  Tooltip.prototype.arrow = function () {
+    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
+  }
+
+  Tooltip.prototype.validate = function () {
+    if (!this.$element[0].parentNode) {
+      this.hide()
+      this.$element = null
+      this.options  = null
+    }
+  }
+
+  Tooltip.prototype.enable = function () {
+    this.enabled = true
+  }
+
+  Tooltip.prototype.disable = function () {
+    this.enabled = false
+  }
+
+  Tooltip.prototype.toggleEnabled = function () {
+    this.enabled = !this.enabled
+  }
+
+  Tooltip.prototype.toggle = function (e) {
+    var self = this
+    if (e) {
+      self = $(e.currentTarget).data('bs.' + this.type)
+      if (!self) {
+        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
+        $(e.currentTarget).data('bs.' + this.type, self)
+      }
+    }
+
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+  }
+
+  Tooltip.prototype.destroy = function () {
+    clearTimeout(this.timeout)
+    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+  }
+
+
+  // TOOLTIP PLUGIN DEFINITION
+  // =========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.tooltip')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip             = Plugin
+  $.fn.tooltip.Constructor = Tooltip
+
+
+  // TOOLTIP NO CONFLICT
+  // ===================
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.2.0
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // POPOVER PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+  Popover.VERSION  = '0.0.0'
+
+  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+    placement: 'right',
+    trigger: 'click',
+    content: '',
+    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+  // NOTE: POPOVER EXTENDS tooltip.js
+  // ================================
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+  Popover.prototype.constructor = Popover
+
+  Popover.prototype.getDefaults = function () {
+    return Popover.DEFAULTS
+  }
+
+  Popover.prototype.setContent = function () {
+    var $tip    = this.tip()
+    var title   = this.getTitle()
+    var content = this.getContent()
+
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+    $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events
+      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+    ](content)
+
+    $tip.removeClass('fade top bottom left right in')
+
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+    // this manually by checking the contents.
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+  }
+
+  Popover.prototype.hasContent = function () {
+    return this.getTitle() || this.getContent()
+  }
+
+  Popover.prototype.getContent = function () {
+    var $e = this.$element
+    var o  = this.options
+
+    return $e.attr('data-content')
+      || (typeof o.content == 'function' ?
+            o.content.call($e[0]) :
+            o.content)
+  }
+
+  Popover.prototype.arrow = function () {
+    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+  }
+
+  Popover.prototype.tip = function () {
+    if (!this.$tip) this.$tip = $(this.options.template)
+    return this.$tip
+  }
+
+
+  // POPOVER PLUGIN DEFINITION
+  // =========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.popover')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.popover
+
+  $.fn.popover             = Plugin
+  $.fn.popover.Constructor = Popover
+
+
+  // POPOVER NO CONFLICT
+  // ===================
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.2.0
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TAB CLASS DEFINITION
+  // ====================
+
+  var Tab = function (element) {
+    this.element = $(element)
+  }
+
+  Tab.VERSION = '0.0.0'
+
+  Tab.prototype.show = function () {
+    var $this    = this.element
+    var $ul      = $this.closest('ul:not(.dropdown-menu)')
+    var selector = $this.data('target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    if ($this.parent('li').hasClass('active')) return
+
+    var previous = $ul.find('.active:last a')[0]
+    var e        = $.Event('show.bs.tab', {
+      relatedTarget: previous
+    })
+
+    $this.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    //var $target = $(selector)    CVE-2016-10735
+    var $target = $(document).find(selector)
+
+    this.activate($this.closest('li'), $ul)
+    this.activate($target, $target.parent(), function () {
+      $this.trigger({
+        type: 'shown.bs.tab',
+        relatedTarget: previous
+      })
+    })
+  }
+
+  Tab.prototype.activate = function (element, container, callback) {
+    var $active    = container.find('> .active')
+    var transition = callback
+      && $.support.transition
+      && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
+
+    function next() {
+      $active
+        .removeClass('active')
+        .find('> .dropdown-menu > .active')
+        .removeClass('active')
+
+      element.addClass('active')
+
+      if (transition) {
+        element[0].offsetWidth // reflow for transition
+        element.addClass('in')
+      } else {
+        element.removeClass('fade')
+      }
+
+      if (element.parent('.dropdown-menu')) {
+        element.closest('li.dropdown').addClass('active')
+      }
+
+      callback && callback()
+    }
+
+    $active.length && transition ?
+      $active
+        .one('bsTransitionEnd', next)
+        .emulateTransitionEnd(150) :
+      next()
+
+    $active.removeClass('in')
+  }
+
+
+  // TAB PLUGIN DEFINITION
+  // =====================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.tab')
+
+      if (!data) $this.data('bs.tab', (data = new Tab(this)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.tab
+
+  $.fn.tab             = Plugin
+  $.fn.tab.Constructor = Tab
+
+
+  // TAB NO CONFLICT
+  // ===============
+
+  $.fn.tab.noConflict = function () {
+    $.fn.tab = old
+    return this
+  }
+
+
+  // TAB DATA-API
+  // ============
+
+  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+    e.preventDefault()
+    Plugin.call($(this), 'show')
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.2.0
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // AFFIX CLASS DEFINITION
+  // ======================
+
+  var Affix = function (element, options) {
+    this.options = $.extend({}, Affix.DEFAULTS, options)
+
+    //this.$target = $(this.options.target) CVE-2018-20676&20677
+    var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
+
+    this.$target = target
+      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
+
+    this.$element     = $(element)
+    this.affixed      =
+    this.unpin        =
+    this.pinnedOffset = null
+
+    this.checkPosition()
+  }
+
+  Affix.VERSION  = '0.0.0'
+
+  Affix.RESET    = 'affix affix-top affix-bottom'
+
+  Affix.DEFAULTS = {
+    offset: 0,
+    target: window
+  }
+
+  Affix.prototype.getPinnedOffset = function () {
+    if (this.pinnedOffset) return this.pinnedOffset
+    this.$element.removeClass(Affix.RESET).addClass('affix')
+    var scrollTop = this.$target.scrollTop()
+    var position  = this.$element.offset()
+    return (this.pinnedOffset = position.top - scrollTop)
+  }
+
+  Affix.prototype.checkPositionWithEventLoop = function () {
+    setTimeout($.proxy(this.checkPosition, this), 1)
+  }
+
+  Affix.prototype.checkPosition = function () {
+    if (!this.$element.is(':visible')) return
+
+    var scrollHeight = $(document).height()
+    var scrollTop    = this.$target.scrollTop()
+    var position     = this.$element.offset()
+    var offset       = this.options.offset
+    var offsetTop    = offset.top
+    var offsetBottom = offset.bottom
+
+    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
+    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
+    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+    var affix = this.unpin   != null && (scrollTop + this.unpin <= position.top) ? false :
+                offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
+                offsetTop    != null && (scrollTop <= offsetTop) ? 'top' : false
+
+    if (this.affixed === affix) return
+    if (this.unpin != null) this.$element.css('top', '')
+
+    var affixType = 'affix' + (affix ? '-' + affix : '')
+    var e         = $.Event(affixType + '.bs.affix')
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    this.affixed = affix
+    this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+    this.$element
+      .removeClass(Affix.RESET)
+      .addClass(affixType)
+      .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+
+    if (affix == 'bottom') {
+      this.$element.offset({
+        top: scrollHeight - this.$element.height() - offsetBottom
+      })
+    }
+  }
+
+
+  // AFFIX PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.affix')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.affix
+
+  $.fn.affix             = Plugin
+  $.fn.affix.Constructor = Affix
+
+
+  // AFFIX NO CONFLICT
+  // =================
+
+  $.fn.affix.noConflict = function () {
+    $.fn.affix = old
+    return this
+  }
+
+
+  // AFFIX DATA-API
+  // ==============
+
+  $(window).on('load', function () {
+    $('[data-spy="affix"]').each(function () {
+      var $spy = $(this)
+      var data = $spy.data()
+
+      data.offset = data.offset || {}
+
+      if (data.offsetBottom) data.offset.bottom = data.offsetBottom
+      if (data.offsetTop)    data.offset.top    = data.offsetTop
+
+      Plugin.call($spy, data)
+    })
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: collapse.js v3.2.0
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // COLLAPSE PUBLIC CLASS DEFINITION
+  // ================================
+
+  var Collapse = function (element, options) {
+    this.$element      = $(element)
+    this.options       = $.extend({}, Collapse.DEFAULTS, options)
+    this.transitioning = null
+
+    if (this.options.parent) this.$parent = $(this.options.parent)
+    if (this.options.toggle) this.toggle()
+  }
+
+  Collapse.VERSION  = '0.0.0'
+
+  Collapse.DEFAULTS = {
+    toggle: true
+  }
+
+  Collapse.prototype.dimension = function () {
+    var hasWidth = this.$element.hasClass('width')
+    return hasWidth ? 'width' : 'height'
+  }
+
+  Collapse.prototype.show = function () {
+    if (this.transitioning || this.$element.hasClass('in')) return
+
+    var startEvent = $.Event('show.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    var actives = this.$parent && this.$parent.find('> .panel > .in')
+
+    if (actives && actives.length) {
+      var hasData = actives.data('bs.collapse')
+      if (hasData && hasData.transitioning) return
+      Plugin.call(actives, 'hide')
+      hasData || actives.data('bs.collapse', null)
+    }
+
+    var dimension = this.dimension()
+
+    this.$element
+      .removeClass('collapse')
+      .addClass('collapsing')[dimension](0)
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.$element
+        .removeClass('collapsing')
+        .addClass('collapse in')[dimension]('')
+      this.transitioning = 0
+      this.$element
+        .trigger('shown.bs.collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+    this.$element
+      .one('bsTransitionEnd', $.proxy(complete, this))
+      .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
+  }
+
+  Collapse.prototype.hide = function () {
+    if (this.transitioning || !this.$element.hasClass('in')) return
+
+    var startEvent = $.Event('hide.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    var dimension = this.dimension()
+
+    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
+
+    this.$element
+      .addClass('collapsing')
+      .removeClass('collapse in')
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.transitioning = 0
+      this.$element
+        .trigger('hidden.bs.collapse')
+        .removeClass('collapsing')
+        .addClass('collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    this.$element
+      [dimension](0)
+      .one('bsTransitionEnd', $.proxy(complete, this))
+      .emulateTransitionEnd(350)
+  }
+
+  Collapse.prototype.toggle = function () {
+    this[this.$element.hasClass('in') ? 'hide' : 'show']()
+  }
+
+
+  // COLLAPSE PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.collapse')
+      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data && options.toggle && option == 'show') option = !option
+      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.collapse
+
+  $.fn.collapse             = Plugin
+  $.fn.collapse.Constructor = Collapse
+
+
+  // COLLAPSE NO CONFLICT
+  // ====================
+
+  $.fn.collapse.noConflict = function () {
+    $.fn.collapse = old
+    return this
+  }
+
+
+  // COLLAPSE DATA-API
+  // =================
+
+  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
+    var href
+    var $this   = $(this)
+    var target  = $this.attr('data-target')
+        || e.preventDefault()
+        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+    var $target = $(target)
+    var data    = $target.data('bs.collapse')
+    var option  = data ? 'toggle' : $this.data()
+    var parent  = $this.attr('data-parent')
+    var $parent = parent && $(parent)
+
+    if (!data || !data.transitioning) {
+      if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
+      $this.toggleClass('collapsed', $target.hasClass('in'))
+    }
+
+    Plugin.call($target, option)
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.2.0
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // SCROLLSPY CLASS DEFINITION
+  // ==========================
+
+  function ScrollSpy(element, options) {
+    var process  = $.proxy(this.process, this)
+
+    this.$body          = $('body')
+    this.$scrollElement = $(element).is('body') ? $(window) : $(element)
+    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
+    this.selector       = (this.options.target || '') + ' .nav li > a'
+    this.offsets        = []
+    this.targets        = []
+    this.activeTarget   = null
+    this.scrollHeight   = 0
+
+    this.$scrollElement.on('scroll.bs.scrollspy', process)
+    this.refresh()
+    this.process()
+  }
+
+  ScrollSpy.VERSION  = '0.0.0'
+
+  ScrollSpy.DEFAULTS = {
+    offset: 10
+  }
+
+  ScrollSpy.prototype.getScrollHeight = function () {
+    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+  }
+
+  ScrollSpy.prototype.refresh = function () {
+    var offsetMethod = 'offset'
+    var offsetBase   = 0
+
+    if (!$.isWindow(this.$scrollElement[0])) {
+      offsetMethod = 'position'
+      offsetBase   = this.$scrollElement.scrollTop()
+    }
+
+    this.offsets = []
+    this.targets = []
+    this.scrollHeight = this.getScrollHeight()
+
+    var self     = this
+
+    this.$body
+      .find(this.selector)
+      .map(function () {
+        var $el   = $(this)
+        var href  = $el.data('target') || $el.attr('href')
+        var $href = /^#./.test(href) && $(href)
+
+        return ($href
+          && $href.length
+          && $href.is(':visible')
+          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
+      })
+      .sort(function (a, b) { return a[0] - b[0] })
+      .each(function () {
+        self.offsets.push(this[0])
+        self.targets.push(this[1])
+      })
+  }
+
+  ScrollSpy.prototype.process = function () {
+    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
+    var scrollHeight = this.getScrollHeight()
+    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
+    var offsets      = this.offsets
+    var targets      = this.targets
+    var activeTarget = this.activeTarget
+    var i
+
+    if (this.scrollHeight != scrollHeight) {
+      this.refresh()
+    }
+
+    if (scrollTop >= maxScroll) {
+      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
+    }
+
+    if (activeTarget && scrollTop <= offsets[0]) {
+      return activeTarget != (i = targets[0]) && this.activate(i)
+    }
+
+    for (i = offsets.length; i--;) {
+      activeTarget != targets[i]
+        && scrollTop >= offsets[i]
+        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+        && this.activate(targets[i])
+    }
+  }
+
+  ScrollSpy.prototype.activate = function (target) {
+    this.activeTarget = target
+
+    $(this.selector)
+      .parentsUntil(this.options.target, '.active')
+      .removeClass('active')
+
+    var selector = this.selector +
+        '[data-target="' + target + '"],' +
+        this.selector + '[href="' + target + '"]'
+
+    var active = $(selector)
+      .parents('li')
+      .addClass('active')
+
+    if (active.parent('.dropdown-menu').length) {
+      active = active
+        .closest('li.dropdown')
+        .addClass('active')
+    }
+
+    active.trigger('activate.bs.scrollspy')
+  }
+
+
+  // SCROLLSPY PLUGIN DEFINITION
+  // ===========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.scrollspy')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.scrollspy
+
+  $.fn.scrollspy             = Plugin
+  $.fn.scrollspy.Constructor = ScrollSpy
+
+
+  // SCROLLSPY NO CONFLICT
+  // =====================
+
+  $.fn.scrollspy.noConflict = function () {
+    $.fn.scrollspy = old
+    return this
+  }
+
+
+  // SCROLLSPY DATA-API
+  // ==================
+
+  $(window).on('load.bs.scrollspy.data-api', function () {
+    $('[data-spy="scroll"]').each(function () {
+      var $spy = $(this)
+      Plugin.call($spy, $spy.data())
+    })
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: transition.js v3.2.0
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+  // ============================================================
+
+  function transitionEnd() {
+    var el = document.createElement('bootstrap')
+
+    var transEndEventNames = {
+      WebkitTransition : 'webkitTransitionEnd',
+      MozTransition    : 'transitionend',
+      OTransition      : 'oTransitionEnd otransitionend',
+      transition       : 'transitionend'
+    }
+
+    for (var name in transEndEventNames) {
+      if (el.style[name] !== undefined) {
+        return { end: transEndEventNames[name] }
+      }
+    }
+
+    return false // explicit for ie8 (  ._.)
+  }
+
+  // http://blog.alexmaccaw.com/css-transitions
+  $.fn.emulateTransitionEnd = function (duration) {
+    var called = false
+    var $el = this
+    $(this).one('bsTransitionEnd', function () { called = true })
+    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+    setTimeout(callback, duration)
+    return this
+  }
+
+  $(function () {
+    $.support.transition = transitionEnd()
+
+    if (!$.support.transition) return
+
+    $.event.special.bsTransitionEnd = {
+      bindType: $.support.transition.end,
+      delegateType: $.support.transition.end,
+      handle: function (e) {
+        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
+      }
+    }
+  })
+
+}(jQuery);
diff --git a/ap/app/zte_webui/js/3rd/underscore.base.js b/ap/app/zte_webui/js/3rd/underscore.base.js
new file mode 100755
index 0000000..62b3c30
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/underscore.base.js
@@ -0,0 +1 @@
+(function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.hasOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="0.0.0";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}},j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])<u?i=a+1:o=a}return i},m.indexOf=r(1,m.findIndex,m.sortedIndex),m.lastIndexOf=r(-1,m.findLastIndex),m.range=function(n,t,r){null==t&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e<arguments.length;)i.push(arguments[e++]);return E(n,r,this,this,i)};return r},m.bindAll=function(n){var t,r,e=arguments.length;if(1>=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this);

diff --git a/ap/app/zte_webui/js/3rd/underscore.js b/ap/app/zte_webui/js/3rd/underscore.js
new file mode 100755
index 0000000..2f29de4
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/underscore.js
@@ -0,0 +1,3 @@
+define(["3rd/underscore.base"], function () {

+    return window._

+});

diff --git a/ap/app/zte_webui/js/3rd/webtoolkit.base64.js b/ap/app/zte_webui/js/3rd/webtoolkit.base64.js
new file mode 100755
index 0000000..8ab9944
--- /dev/null
+++ b/ap/app/zte_webui/js/3rd/webtoolkit.base64.js
@@ -0,0 +1,145 @@
+var Base64 = {
+
+	// private property
+	_basekey : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+
+	// public method for decoding
+	decode : function (input, isBinaryData) {
+		if(!input) return "";
+		var output = "";
+		var chr1, chr2, chr3;
+		var enc1, enc2, enc3, enc4;
+		var i = 0;
+
+		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+		while (i < input.length) {
+
+			enc1 = this._basekey.indexOf(input.charAt(i++));
+			enc2 = this._basekey.indexOf(input.charAt(i++));
+			enc3 = this._basekey.indexOf(input.charAt(i++));
+			enc4 = this._basekey.indexOf(input.charAt(i++));
+
+			chr1 = (enc1 << 2) | (enc2 >> 4);
+			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+			chr3 = ((enc3 & 3) << 6) | enc4;
+
+			output = output + String.fromCharCode(chr1);
+
+			if (enc3 != 64) {
+				output = output + String.fromCharCode(chr2);
+			}
+			if (enc4 != 64) {
+				output = output + String.fromCharCode(chr3);
+			}
+
+		}
+
+		if (!isBinaryData) {
+			output = Base64._utf8_decode(output);
+		}
+
+		return output;
+
+	},
+
+// public method for encoding
+	encode : function (input, isBinaryData) {
+		if(!input) return "";
+		var output = "";
+		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+		var i = 0;
+
+		if (!isBinaryData) {
+			input = Base64._utf8_encode(input);
+		}
+		
+		while (i < input.length) {
+
+			chr1 = input.charCodeAt(i++);
+			chr2 = input.charCodeAt(i++);
+			chr3 = input.charCodeAt(i++);
+
+			enc1 = chr1 >> 2;
+			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+			enc4 = chr3 & 63;
+
+			if (isNaN(chr2)) {
+				enc3 = enc4 = 64;
+			} else if (isNaN(chr3)) {
+				enc4 = 64;
+			}
+
+			output = output +
+			this._basekey.charAt(enc1) + this._basekey.charAt(enc2) +
+			this._basekey.charAt(enc3) + this._basekey.charAt(enc4);
+
+		}
+
+		return output;
+	},
+	
+// private method for UTF-8 decoding
+	_utf8_decode : function (utftext) {
+		var string = "";
+		var i = 0;
+		//var c = c1 = c2 = 0; cov_2
+		var c = 0;
+		var c1 = 0;
+		var c2 = 0;
+		
+		while ( i < utftext.length ) {
+
+			c = utftext.charCodeAt(i);
+
+			if (c < 128) {
+				string += String.fromCharCode(c);
+				i++;
+			}
+			else if((c > 191) && (c < 224)) {
+				c2 = utftext.charCodeAt(i+1);
+				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+				i += 2;
+			}
+			else {
+				c2 = utftext.charCodeAt(i+1);
+				c3 = utftext.charCodeAt(i+2);
+				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+				i += 3;
+			}
+
+		}
+
+		return string;
+	},
+	
+	// private method for UTF-8 encoding
+	_utf8_encode : function (string) {
+		string = string.replace(/\r\n/g,"\n");
+		var utftext = "";
+
+		for (var n = 0; n < string.length; n++) {
+
+			var c = string.charCodeAt(n);
+
+			if (c < 128) {
+				utftext += String.fromCharCode(c);
+			}
+			else if((c > 127) && (c < 2048)) {
+				utftext += String.fromCharCode((c >> 6) | 192);
+				utftext += String.fromCharCode((c & 63) | 128);
+			}
+			else {
+				utftext += String.fromCharCode((c >> 12) | 224);
+				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+				utftext += String.fromCharCode((c & 63) | 128);
+			}
+
+		}
+
+		return utftext;
+	}
+
+
+}
diff --git a/ap/app/zte_webui/js/com.js b/ap/app/zte_webui/js/com.js
new file mode 100755
index 0000000..3a371c8
--- /dev/null
+++ b/ap/app/zte_webui/js/com.js
@@ -0,0 +1,11142 @@
+

+define("service","underscore jquery set CryptoJS".split(" "), function (_, $, config, CryptoJS) {

+    function addTimerSomething(querys, cb) {

+        if (_.isArray(querys)) {

+            for (var i = 0; i < querys.length; i++) {

+                addQueryString(querys[i]);

+            }

+        } else {

+            addQueryString(querys);

+        }

+        addCallback(cb);

+    }

+    function removeTimerSomething(querys, cb) {

+        if (_.isArray(querys)) {

+            for (var i = 0; i < querys.length; i++) {

+                removeQueryString(querys[i]);

+            }

+        } else {

+            removeQueryString(querys);

+        }

+        removeCallback(cb);

+    }

+    function getCurretnMAC() {

+        return getUserMacAddr({}).get_user_mac_addr;

+    }

+    function getDdnsParams(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: 1,

+                cmd: "DDNS_Enable,DDNS_Mode,DDNSProvider,DDNSAccount,DDNSPassword,DDNS,DDNS_Hash_Value"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    DDNS_Enable: paramD.DDNS_Enable,

+                    DDNS_Mode: paramD.DDNS_Mode,

+                    DDNSProvider: paramD.DDNSProvider,

+                    DDNSAccount: paramD.DDNSAccount,

+                    DDNSPassword: paramD.DDNSPassword,

+                    DDNS: paramD.DDNS,

+                    DDNS_Hash_Value: paramD.DDNS_Hash_Value

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setDDNSForward() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = $.extend({}, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+   function getLoginData() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "modem_main_state,puknumber,pinnumber,blc_wan_mode,blc_wan_auto_mode,psw_fail_num_str,login_lock_time,psw_changed";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.blc_wan_mode == "AUTO") {

+                    paramD.blc_wan_mode = paramD.blc_wan_auto_mode ? paramD.blc_wan_auto_mode : 'AUTO_PPP';

+                } else {

+                    paramD.blc_wan_mode = paramD.blc_wan_mode ? paramD.blc_wan_mode : 'PPP';

+                }

+                paramD.psw_fail_num_str = paramD.psw_fail_num_str == '' ? config.MAX_LOGIN_COUNT : paramD.psw_fail_num_str;

+                paramD.login_lock_time = paramD.login_lock_time == '' ? '300' : paramD.login_lock_time;

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function login() {

+        return stuffMake(arguments, {}, prepare, deal, {

+            errorType: 'badPassword'

+        }, true);

+        function prepare(values, isPost) {

+            var obj = {

+                goformId: "LOGIN",

+                password: config.PASSWORD_ENCODE ? Base64.encode(values.password) : values.password

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && (paramD.result == "0" || paramD.result == "4")) {

+                informationAll.isLoggedIn = true;

+                return {

+                    result: true

+                };

+            } else {

+                var loginError = {};

+                switch (paramD.result) {

+                case "1":

+                    loginError = {

+                        errorType: "Login Fail"

+                    };

+                    break;

+                case "2":

+                    loginError = {

+                        errorType: "duplicateUser"

+                    };

+                    break;

+                case "3":

+                    loginError = {

+                        errorType: "badPassword"

+                    };

+                    break;

+                default:

+                    loginError = {

+                        errorType: "Login Fail"

+                    };

+                    break;

+                }

+                informationAll.isLoggedIn = false;

+                return $.extend(errUnknownObj, loginError);

+            }

+        }

+    }

+    function getLoginStatus() {

+        if (informationAll.isLoggedIn != undefined) {

+            return stuffMake(arguments, {

+                status: informationAll.isLoggedIn ? 'loggedIn' : 'loggedOut'

+            });

+        } else {

+            var resultObject = {};

+            if (!config.HAS_LOGIN) {

+                resultObject.status = 'loggedIn';

+                resultObject.errorType = 'no_login';

+                informationAll.isLoggedIn = true;

+            }

+            return stuffMake(arguments, resultObject, prepare, deal, null, false);

+        }

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "loginfo";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.loginfo || paramD.loginfo == "") {

+                var loginStatus = {};

+                switch (paramD.loginfo) {

+                case "ok":

+                    informationAll.isLoggedIn = true;

+                    loginStatus.status = "loggedIn";

+                    break;

+                default:

+                    informationAll.isLoggedIn = false;

+                    loginStatus.status = "loggedOut";

+                    break;

+                }

+                return loginStatus;

+            } else {

+                informationAll.isLoggedIn = undefined;

+                return $.extend(errUnknownObj, {

+                    errorType: "LoginStatusError"

+                });

+            }

+        }

+    }

+    function enterPIN() {

+        return stuffMake(arguments, {}, prepare, deal, {}, true);

+        function prepare(values, isPost) {

+            var obj = {};

+            obj.goformId = "ENTER_PIN";

+            obj.PinNumber = values.PinNumber;

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result === "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function enterPUK() {

+        return stuffMake(arguments, {}, prepare, deal, {}, true);

+        function prepare(values, isPost) {

+            var obj = {};

+            obj.goformId = "ENTER_PUK";

+            obj.PUKNumber = values.PUKNumber;

+            obj.PinNumber = values.PinNumber;

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result === "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }	

+

+    function getStatusInfo() {

+        if (informationAll.isLoggedIn === undefined) {

+            var loginStatus = getLoginStatus();

+            return {

+                networkType: informationAll.networkType,

+                signalImg: informationAll.signalImg,

+                networkOperator: informationAll.networkOperator,

+                spn_b1_flag: informationAll.spn_b1_flag,

+                spn_name_data: informationAll.spn_name_data,

+                spn_b2_flag: informationAll.spn_b2_flag,

+                connectStatus: informationAll.connectStatus,

+                rj45ConnectStatus: informationAll.rj45ConnectStatus,

+                ssid1AttachedNum: informationAll.ssid1AttachedNum,

+                ssid2AttachedNum: informationAll.ssid2AttachedNum,

+                wirelessDeviceNum: informationAll.ssid1AttachedNum + informationAll.ssid2AttachedNum,

+                roamingStatus: informationAll.roamingStatus,

+                wifiStatus: informationAll.wifiStatus,

+                simStatus: informationAll.simStatus,

+                pinStatus: informationAll.pinStatus,

+                batteryStatus: informationAll.batteryStatus,

+                batteryLevel: informationAll.batteryLevel,

+                batteryPers: informationAll.batteryPers,

+                batteryTime: informationAll.batteryTime,

+                ssid: informationAll.ssid,

+                authMode: informationAll.authMode,

+                data_counter: informationAll.data_counter,

+                isLoggedIn: loginStatus.status == "loggedIn",

+                newSmsReceived: informationAll.newSmsReceived,

+                smsReportReceived: informationAll.smsReportReceived,

+                smsUnreadCount: informationAll.smsUnreadCount,

+                limitVolumeEnable: informationAll.limitVolumeEnable,

+                limitVolumeType: informationAll.limitVolumeType,

+                limitVolumePercent: informationAll.limitVolumePercent,

+                limitVolumeSize: informationAll.limitVolumeSize,

+                connectWifiProfile: informationAll.connectWifiProfile,

+                connectWifiSSID: informationAll.connectWifiSSID,

+                connectWifiStatus: informationAll.connectWifiStatus,

+                multi_ssid_enable: informationAll.multi_ssid_enable,

+                roamMode: informationAll.roamMode,

+                blc_wan_mode: informationAll.blc_wan_mode,

+                current_upgrade_state: informationAll.current_upgrade_state,

+                is_mandatory: informationAll.is_mandatory,

+                new_version_state: informationAll.new_version_state,

+                allowRoamingUpdate: informationAll.allowRoamingUpdate,

+                ap_station_enable: informationAll.ap_station_enable,

+                ap_station_mode: informationAll.ap_station_mode,

+                dialMode: informationAll.dialMode,

+                fota_package_already_download: informationAll.fota_package_already_download,

+                ethWanMode: informationAll.ethWanMode,

+                fota_user_selector: informationAll.fota_user_selector,

+                defaultWanName: informationAll.defaultWanName

+            };

+        }

+        return {

+            networkType: informationAll.networkType,

+            signalImg: informationAll.signalImg,

+            networkOperator: informationAll.networkOperator,

+            spn_b1_flag: informationAll.spn_b1_flag,

+            spn_name_data: informationAll.spn_name_data,

+            spn_b2_flag: informationAll.spn_b2_flag,

+            connectStatus: informationAll.connectStatus,

+            rj45ConnectStatus: informationAll.rj45ConnectStatus,

+            ssid1AttachedNum: informationAll.ssid1AttachedNum,

+            ssid2AttachedNum: informationAll.ssid2AttachedNum,

+            wirelessDeviceNum: informationAll.ssid1AttachedNum + informationAll.ssid2AttachedNum,

+            roamingStatus: informationAll.roamingStatus,

+            wifiStatus: informationAll.wifiStatus,

+            simStatus: informationAll.simStatus,

+            pinStatus: informationAll.pinStatus,

+            batteryStatus: informationAll.batteryStatus,

+            batteryLevel: informationAll.batteryLevel,

+            batteryPers: informationAll.batteryPers,

+            batteryTime: informationAll.batteryTime,

+            ssid: informationAll.ssid,

+            authMode: informationAll.authMode,

+            data_counter: informationAll.data_counter,

+            isLoggedIn: informationAll.isLoggedIn,

+            newSmsReceived: informationAll.newSmsReceived,

+            smsReportReceived: informationAll.smsReportReceived,

+            smsUnreadCount: informationAll.smsUnreadCount,

+            limitVolumeEnable: informationAll.limitVolumeEnable,

+            limitVolumeType: informationAll.limitVolumeType,

+            limitVolumePercent: informationAll.limitVolumePercent,

+            limitVolumeSize: informationAll.limitVolumeSize,

+            connectWifiProfile: informationAll.connectWifiProfile,

+            connectWifiSSID: informationAll.connectWifiSSID,

+            connectWifiStatus: informationAll.connectWifiStatus,

+            multi_ssid_enable: informationAll.multi_ssid_enable,

+            blc_wan_mode: informationAll.blc_wan_mode,

+            roamMode: informationAll.roamMode,

+            current_upgrade_state: informationAll.current_upgrade_state,

+            is_mandatory: informationAll.is_mandatory,

+            new_version_state: informationAll.new_version_state,

+            allowRoamingUpdate: informationAll.allowRoamingUpdate,

+            ap_station_enable: informationAll.ap_station_enable,

+            ap_station_mode: informationAll.ap_station_mode,

+            dialMode: informationAll.dialMode,

+            fota_package_already_download: informationAll.fota_package_already_download,

+            ethWanMode: informationAll.ethWanMode,

+            fota_user_selector: informationAll.fota_user_selector,

+            defaultWanName: informationAll.defaultWanName

+        };

+    }

+    function getConnectionInfo() {

+        var isData = informationAll.limitVolumeType == '1';

+        var result = {

+            data_counter: informationAll.data_counter,

+            connectStatus: informationAll.connectStatus,

+            rj45ConnectStatus: informationAll.rj45ConnectStatus,

+            limitVolumeEnable: informationAll.limitVolumeEnable,

+            limitVolumeType: informationAll.limitVolumeType,

+            limitVolumePercent: informationAll.limitVolumePercent,

+            networkType: informationAll.networkType

+        };

+        if (isData) {

+            result.limitDataMonth = informationAll.limitVolumeSize;

+            result.limitTimeMonth = 0;

+        } else {

+            result.limitTimeMonth = informationAll.limitVolumeSize;

+            result.limitDataMonth = 0;

+        }

+        result.blc_wan_mode = informationAll.blc_wan_mode;

+        return result;

+    }

+    function resetNewSmsReceivedVar() {

+        informationAll.newSmsReceived = false;

+    }

+    function resetSmsReportReceivedVar() {

+        informationAll.smsReportReceived = false;

+    }

+    function getSmsCapability() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "sms_capacity_info";

+            return valueReq;

+        }

+        function deal(paramD) {

+            return {

+                nvTotal: parseInt(paramD.sms_nv_total, 10),

+                nvUsed: parseInt(paramD.sms_nv_rev_total, 10) + parseInt(paramD.sms_nv_send_total, 10) + parseInt(paramD.sms_nv_draftbox_total, 10),

+                simTotal: parseInt(paramD.sms_sim_total, 10),

+                simUsed: parseInt(paramD.sms_sim_rev_total, 10) + parseInt(paramD.sms_sim_send_total, 10) + parseInt(paramD.sms_sim_draftbox_total, 10),

+                nvReceive: parseInt(paramD.sms_nv_rev_total, 10),

+                nvSend: parseInt(paramD.sms_nv_send_total, 10),

+                nvDraft: parseInt(paramD.sms_nv_draftbox_total, 10),

+                simReceive: parseInt(paramD.sms_sim_rev_total, 10),

+                simSend: parseInt(paramD.sms_sim_send_total, 10),

+                simDraft: parseInt(paramD.sms_sim_draftbox_total, 10)

+            };

+        }

+    }

+    function connect() {

+        var callback = arguments[1];

+        var checkPoint = 0;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.notCallback = true;

+            valueReq.goformId = "CONNECT_NETWORK";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                checkPoint = new Date().getTime();

+                addCallback(checkConnectStatus);

+            } else {

+                callback({

+                    result: false

+                });

+            }

+        }

+        function checkConnectStatus(paramD) {

+            if (paramD.ppp_status == "ppp_connecting") {

+                informationAll.connectStatus = "ppp_connecting";

+            } else if (paramD.ppp_status == "ppp_connected") {

+                removeCallback(checkConnectStatus);

+                informationAll.connectStatus = "ppp_connected";

+                callback({

+                    result: true,

+                    status: informationAll.connectStatus

+                });

+            } else if (new Date().getTime() - checkPoint < 1e4) {

+                informationAll.connectStatus = "ppp_connecting";

+            } else {

+                removeCallback(checkConnectStatus);

+                callback({

+                    result: false

+                });

+            }

+        }

+    }

+    function disconnect() {

+        var callback = arguments[1];

+        var checkPoint = 0;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.notCallback = true;

+            valueReq.goformId = "DISCONNECT_NETWORK";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                checkPoint = new Date().getTime();

+                addCallback(checkDisconnectStatus);

+            } else {

+                callback({

+                    result: false

+                });

+            }

+        }

+        function checkDisconnectStatus(paramD) {

+            if (paramD.ppp_status == "ppp_disconnecting") {

+                informationAll.connectStatus = "ppp_disconnecting";

+            } else if (paramD.ppp_status == "ppp_disconnected") {

+                removeCallback(checkDisconnectStatus);

+                informationAll.connectStatus = "ppp_disconnected";

+                callback({

+                    result: true,

+                    status: informationAll.connectStatus

+                });

+            } else if (new Date().getTime() - checkPoint < 1e4) {

+                informationAll.connectStatus = "ppp_disconnecting";

+            } else {

+                removeCallback(checkDisconnectStatus);

+                callback({

+                    result: false

+                });

+            }

+        }

+    }

+    function getApnSettings() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "APN_configtmp0,APN_configtmp1,APN_configtmp2,APN_configtmp3,APN_configtmp4,APN_configtmp5,APN_configtmp6,APN_configtmp7,APN_configtmp8,APN_configtmp9," + "APN_configtmp10,APN_configtmp11,APN_configtmp12,APN_configtmp13,APN_configtmp14,APN_configtmp15,APN_configtmp16,APN_configtmp17,APN_configtmp18,APN_configtmp19," + "ipv6_APN_configtmp0,ipv6_APN_configtmp1,ipv6_APN_configtmp2,ipv6_APN_configtmp3,ipv6_APN_configtmp4,ipv6_APN_configtmp5,ipv6_APN_configtmp6,ipv6_APN_configtmp7,ipv6_APN_configtmp8,ipv6_APN_configtmp9," + "ipv6_APN_configtmp10,ipv6_APN_configtmp11,ipv6_APN_configtmp12,ipv6_APN_configtmp13,ipv6_APN_configtmp14,ipv6_APN_configtmp15,ipv6_APN_configtmp16,ipv6_APN_configtmp17,ipv6_APN_configtmp18,ipv6_APN_configtmp19," + "m_profile_name,profile_name,wan_dial,pdp_type,pdp_select,index,Current_index,apn_auto_config,ipv6_apn_auto_config," + "apn_mode,wan_apn,ppp_auth_mode,ppp_username,ppp_passtmp," + "ipv6_wan_apn,ipv6_pdp_type,ipv6_ppp_auth_mode,ipv6_ppp_username,ipv6_ppp_passtmp,apn_num_preset";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(result) {

+            if (result) {

+                return {

+                    APNs: result.APN_configtmp0 + "||" + result.APN_configtmp1 + "||" + result.APN_configtmp2 + "||" + result.APN_configtmp3 + "||" + result.APN_configtmp4 + "||"

+                    +result.APN_configtmp5 + "||" + result.APN_configtmp6 + "||" + result.APN_configtmp7 + "||" + result.APN_configtmp8 + "||" + result.APN_configtmp9 + "||"

+                    +result.APN_configtmp10 + "||" + result.APN_configtmp11 + "||" + result.APN_configtmp12 + "||" + result.APN_configtmp13 + "||" + result.APN_configtmp14 + "||"

+                    +result.APN_configtmp15 + "||" + result.APN_configtmp16 + "||" + result.APN_configtmp17 + "||" + result.APN_configtmp18 + "||" + result.APN_configtmp19,

+                    ipv6APNs: result.ipv6_APN_configtmp0 + "||" + result.ipv6_APN_configtmp1 + "||" + result.ipv6_APN_configtmp2 + "||" + result.ipv6_APN_configtmp3 + "||" + result.ipv6_APN_configtmp4 + "||"

+                    +result.ipv6_APN_configtmp5 + "||" + result.ipv6_APN_configtmp6 + "||" + result.ipv6_APN_configtmp7 + "||" + result.ipv6_APN_configtmp8 + "||" + result.ipv6_APN_configtmp9 + "||"

+                    +result.ipv6_APN_configtmp10 + "||" + result.ipv6_APN_configtmp11 + "||" + result.ipv6_APN_configtmp12 + "||" + result.ipv6_APN_configtmp13 + "||" + result.ipv6_APN_configtmp14 + "||"

+                    +result.ipv6_APN_configtmp15 + "||" + result.ipv6_APN_configtmp16 + "||" + result.ipv6_APN_configtmp17 + "||" + result.ipv6_APN_configtmp18 + "||" + result.ipv6_APN_configtmp19,

+                    apnMode: result.apn_mode,

+                    profileName: result.m_profile_name || result.profile_name,

+                    wanDial: result.wan_dial,

+                    pdpType: result.pdp_type == 'IP' ? 'IP' : result.ipv6_pdp_type,

+                    pdpSelect: result.pdp_select,

+                    index: result.index,

+                    currIndex: result.Current_index,

+                    autoApns: result.apn_auto_config,

+                    autoApnsV6: result.ipv6_apn_auto_config,

+                    wanApn: result.wan_apn,

+                    authMode: result.ppp_auth_mode.toLowerCase(),

+                    username: result.ppp_username,

+                    password: result.ppp_passtmp,

+                    dnsMode: "",

+                    dns1: "",

+                    dns2: "",

+                    wanApnV6: result.ipv6_wan_apn,

+                    authModeV6: result.ipv6_ppp_auth_mode.toLowerCase(),

+                    usernameV6: result.ipv6_ppp_username,

+                    passwordV6: result.ipv6_ppp_passtmp,

+                    dnsModeV6: "",

+                    dns1V6: "",

+                    dns2V6: "",

+                    apnNumPreset: result.apn_num_preset

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function deleteApn() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                apn_action: "delete",

+                apn_mode: "manual",

+                index: values.index

+            };

+            valueReq.goformId = "APN_PROC_EX";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function setDefaultApn() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var requestParam = {

+                goformId: "APN_PROC_EX",

+                apn_mode: values.apnMode

+            };

+            if (values.apnMode == 'manual') {

+                requestParam.apn_action = "set_default";

+                requestParam.set_default_flag = "1";

+                requestParam.pdp_type = values.pdpType;

+                requestParam.index = values.index;

+            }

+            return requestParam;

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function addOrEditApn() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "APN_PROC_EX",

+                apn_action: "save",

+                apn_mode: "manual",

+                profile_name: values.profileName,

+                wan_dial: '*99#',

+                pdp_type: values.pdpType,

+                pdp_select: 'auto',

+                index: values.index

+            };

+            if (values.pdpType == "IP") {

+                $.extend(valueReq, {

+                    wan_apn: values.wanApn,

+                    ppp_auth_mode: values.authMode,

+                    ppp_username: values.username,

+                    ppp_passtmp: values.password,

+                });

+            } else if (values.pdpType == "IPv6") {

+                $.extend(valueReq, {

+                    ipv6_wan_apn: values.wanApnV6,

+                    ipv6_ppp_auth_mode: values.authModeV6,

+                    ipv6_ppp_username: values.usernameV6,

+                    ipv6_ppp_passtmp: values.passwordV6

+                });

+            } else {

+                $.extend(valueReq, {

+                    wan_apn: values.wanApn,

+                    ppp_auth_mode: values.authMode,

+                    ppp_username: values.username,

+                    ppp_passtmp: values.password,

+                    dns_mode: values.dnsMode,

+                    prefer_dns_manual: values.dns1,

+                    standby_dns_manual: values.dns2,

+                    ipv6_wan_apn: values.wanApnV6,

+                    ipv6_ppp_auth_mode: values.authModeV6,

+                    ipv6_ppp_username: values.usernameV6,

+                    ipv6_ppp_passtmp: values.passwordV6

+                });

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    var timerQueryString = ["modem_main_state", "pin_status", "blc_wan_mode", "blc_wan_auto_mode", "loginfo", "fota_new_version_state", "fota_current_upgrade_state", "fota_upgrade_selector", "network_provider", "is_mandatory", "sta_count", "m_sta_count"];

+    var loginTimerQueryString = ["signalbar", "network_type", "sub_network_type", "ppp_status", "rj45_state", "EX_SSID1", "sta_ip_status", "EX_wifi_profile", "m_ssid_enable", "wifi_cur_state", "SSID1", "simcard_roam", "lan_ipaddr", "battery_charging", "battery_vol_percent", "battery_pers", "spn_name_data", "spn_b1_flag", "spn_b2_flag", "realtime_tx_bytes", "realtime_rx_bytes", "realtime_time", "realtime_tx_thrpt", "realtime_rx_thrpt", "monthly_rx_bytes", "monthly_tx_bytes", "traffic_alined_delta", "monthly_time", "date_month", "data_volume_limit_switch", "data_volume_limit_size", "data_volume_alert_percent", "data_volume_limit_unit", "roam_setting_option", "upg_roam_switch", "fota_package_already_download", 'ssid', 'dial_mode', 'ethwan_mode', 'default_wan_name'];

+    if (config.HAS_SMS) {

+        $.merge(loginTimerQueryString, ["sms_received_flag", "sts_received_flag", 'sms_unread_num']);

+    }

+    var timerCallbackStack = [];

+    var timerCallbacks = [timerUpdateStatus];

+    function timerUpdater() {

+        if (!updateTimerFlag) {

+            setTimeout(function () {

+                timerUpdater();

+            }, 1000);

+            return;

+        }

+        var queryParams = checkTimerUpdaterParameters();

+        reqAsync(queryParams, function (paramD) {

+            for (var i = 0; i < timerCallbacks.length; i++) {

+                if (typeof timerCallbacks[i] === "function") {

+                    timerCallbacks[i](paramD);

+                }

+            }

+            $.merge(timerCallbacks, timerCallbackStack);

+            timerCallbackStack = [];

+            setTimeout(function () {

+                timerUpdater();

+            }, 1000);

+        }, function () {

+            timerUpdaterErrorCallback();

+            setTimeout(function () {

+                timerUpdater();

+            }, 1000);

+        }, false);

+    }

+    function checkTimerUpdaterParameters() {

+        var queryParams = {

+            multi_data: 1,

+        };

+        if (window.location.hash && window.location.hash != '#entry' && informationAll.isLoggedIn) {

+            if (config.HAS_SMS) {

+                queryParams.sms_received_flag_flag = 0;

+                queryParams.sts_received_flag_flag = 0;

+            }

+            if (loginTimerQueryString.length > 0 && _.indexOf(timerQueryString, loginTimerQueryString[0]) == -1) {

+                $.each(loginTimerQueryString, function (i, n) {

+                    timerQueryString.push(n);

+                });

+            }

+        } else {

+            if (loginTimerQueryString.length > 0 && _.indexOf(timerQueryString, loginTimerQueryString[0]) != -1) {

+                timerQueryString = _.without(timerQueryString, loginTimerQueryString);

+            }

+        }

+        queryParams.cmd = timerQueryString.join(",");

+        return queryParams;

+    }

+    function addCallback(cb) {

+        if (_.indexOf(timerCallbackStack, cb) == -1) {

+            timerCallbackStack.push(cb);

+        }

+    }

+    function removeCallback(cb) {

+        timerCallbacks = _.without(timerCallbacks, cb);

+        if (timerCallbacks.length == 0) {

+            timerCallbacks.push(timerUpdateStatus);

+        }

+        return timerCallbackStack;

+    }

+    function addQueryString(query) {

+        if (_.indexOf(timerQueryString, query) == -1) {

+            timerQueryString.push(query);

+        }

+    }

+    function removeQueryString(query) {

+        timerQueryString = _.without(timerQueryString, query);

+        return timerQueryString;

+    }

+    function timerUpdateStatus(paramD) {

+        informationAll.defaultWanName = paramD.default_wan_name;

+        informationAll.signalImg = typeof paramD.signalbar == 'undefined' ? '0' : paramD.signalbar;

+        informationAll.networkType = paramD.sub_network_type ? paramD.sub_network_type : (paramD.network_type ? paramD.network_type : '');

+        if (informationAll.networkType.toLowerCase().indexOf("limited_service") != -1 || informationAll.networkType.toLowerCase().indexOf("limited service") != -1) {

+            informationAll.networkType = "limited_service";

+        } else if (informationAll.networkType.toLowerCase().indexOf("no_service") != -1 || informationAll.networkType.toLowerCase().indexOf("no service") != -1) {

+            informationAll.networkType = "no_service";

+        }

+        informationAll.networkOperator = paramD.network_provider ? paramD.network_provider : '';

+        informationAll.spn_b1_flag = paramD.spn_b1_flag;

+        informationAll.spn_b2_flag = paramD.spn_b2_flag;

+        informationAll.spn_name_data = paramD.spn_name_data;

+        informationAll.connectStatus = typeof paramD.ppp_status == 'undefined' ? 'ppp_disconnected' : paramD.ppp_status;

+        informationAll.rj45ConnectStatus = (typeof paramD.rj45_state == 'undefined' || paramD.rj45_state == '') ? 'dead' : paramD.rj45_state;

+        informationAll.ethWanMode = paramD.ethwan_mode;

+        informationAll.ssid1AttachedNum = paramD.sta_count == "" ? 0 : parseInt(paramD.sta_count, 10);

+        informationAll.ssid2AttachedNum = paramD.m_sta_count == "" ? 0 : parseInt(paramD.m_sta_count, 10);

+        informationAll.roamingStatus = getRoamStatus(informationAll.networkType, paramD.modem_main_state, paramD.simcard_roam);

+        informationAll.wifiStatus = paramD.wifi_cur_state == "1";

+        informationAll.simStatus = paramD.modem_main_state;

+        informationAll.pinStatus = paramD.pin_status;

+        var needMinutes = 3 * 60 * 60;

+        var batteryLevel = (paramD.battery_vol_percent && paramD.battery_vol_percent.length > 0) ? paramD.battery_vol_percent : 100;

+        informationAll.batteryPers = paramD.battery_pers;

+        var remainMinutes = Math.round(needMinutes * (1 - batteryLevel / 100));

+        informationAll.batteryStatus = (typeof paramD.battery_charging == 'undefined') ? '0' : paramD.battery_charging;

+        informationAll.batteryLevel = batteryLevel;

+        informationAll.batteryTime = remainMinutes.toString();

+        informationAll.data_counter = {

+            uploadRate: paramD.realtime_tx_thrpt == '' ? 0 : paramD.realtime_tx_thrpt,

+            downloadRate: paramD.realtime_rx_thrpt == '' ? 0 : paramD.realtime_rx_thrpt,

+            currentSent: paramD.realtime_tx_bytes == '' ? 0 : paramD.realtime_tx_bytes,

+            currentReceived: paramD.realtime_rx_bytes == '' ? 0 : paramD.realtime_rx_bytes,

+            currentConnectedTime: paramD.realtime_time == '' ? 0 : paramD.realtime_time,

+            monthlySent: paramD.monthly_tx_bytes == '' ? 0 : paramD.monthly_tx_bytes,

+            monthlyReceived: paramD.monthly_rx_bytes == '' ? 0 : paramD.monthly_rx_bytes,

+            traffic_alined_delta: paramD.traffic_alined_delta == '' ? 0 : paramD.traffic_alined_delta,

+            monthlyConnectedTime: paramD.monthly_time == '' ? 0 : paramD.monthly_time,

+            month: paramD.date_month == '' ? 1 : paramD.date_month

+        };

+        informationAll.ssid = paramD.SSID1;

+        informationAll.authMode = paramD.AuthMode;

+        informationAll.isLoggedIn = config.HAS_LOGIN ? paramD.loginfo == "ok" : true;

+        if (config.HAS_SMS) {

+            if (!informationAll.newSmsReceived) {

+                informationAll.newSmsReceived = paramD.sms_received_flag > 0;

+            }

+            if (!informationAll.smsReportReceived) {

+                informationAll.smsReportReceived = paramD.sts_received_flag > 0;

+            }

+            if (typeof paramD.sms_dev_unread_num != "undefined") {

+                informationAll.smsUnreadCount = config.SMS_UNREAD_NUM_INCLUDE_SIM ? parseInt(paramD.sms_dev_unread_num | 0, 10) + parseInt(paramD.sms_sim_unread_num | 0, 10) : parseInt(paramD.sms_dev_unread_num | 0, 10);

+            } else {

+                informationAll.smsUnreadCount = parseInt(paramD.sms_unread_num | 0, 10)

+            }

+        }

+        if (paramD.data_volume_limit_switch == '1') {

+            informationAll.limitVolumeEnable = true;

+            informationAll.limitVolumeType = paramD.data_volume_limit_unit == 'data' ? '1' : '0';

+            informationAll.limitVolumePercent = paramD.data_volume_alert_percent;

+            if (paramD.data_volume_limit_unit == 'data') {

+                var limitMonth = paramD.data_volume_limit_size.split("_");

+                informationAll.limitVolumeSize = limitMonth[0] * limitMonth[1] * 1024 * 1024;

+            } else {

+                informationAll.limitVolumeSize = paramD.data_volume_limit_size * 60 * 60;

+            }

+        } else {

+            informationAll.limitVolumeEnable = false;

+            informationAll.limitVolumeType = '1';

+            informationAll.limitVolumePercent = '100';

+            informationAll.limitVolumeSize = '0';

+        }

+        informationAll.connectWifiProfile = paramD.EX_wifi_profile;

+        informationAll.connectWifiSSID = paramD.EX_SSID1;

+        informationAll.connectWifiStatus = paramD.sta_ip_status;

+        informationAll.multi_ssid_enable = paramD.m_ssid_enable;

+        informationAll.roamMode = paramD.roam_setting_option;

+        if (paramD.blc_wan_mode == "AUTO") {

+            informationAll.blc_wan_mode = paramD.blc_wan_auto_mode ? paramD.blc_wan_auto_mode : 'AUTO_PPP';

+        } else {

+            informationAll.blc_wan_mode = paramD.blc_wan_mode ? paramD.blc_wan_mode : 'PPP';

+        }

+        informationAll.new_version_state = paramD.fota_new_version_state == "has_critical" || paramD.fota_new_version_state == "has_optional" || paramD.fota_new_version_state == "already_has_pkg";

+        informationAll.current_upgrade_state = paramD.fota_current_upgrade_state;

+        if (informationAll.current_upgrade_state == "verify_failed") {

+            informationAll.current_upgrade_state = "upgrade_pack_error";

+        }

+        informationAll.fota_user_selector = paramD.fota_upgrade_selector;

+        informationAll.is_mandatory = paramD.is_mandatory == "1" || paramD.fota_new_version_state == "has_critical";

+        informationAll.allowRoamingUpdate = paramD.upg_roam_switch;

+        informationAll.dialMode = paramD.dial_mode;

+        informationAll.fota_package_already_download = paramD.fota_package_already_download;

+    }

+    function timerUpdaterErrorCallback() {

+        informationAll.batteryStatus = '0';

+    }

+    function getRoamStatus(networkType, modemState, simcardRoam) {

+        if (("" == $.trim(networkType)) || "no_service" == networkType.toLowerCase() || "limited_service" == networkType.toLowerCase() || "modem_sim_undetected" == modemState || "modem_waitpin" == modemState || "modem_waitpuk" == modemState) {

+            return false;

+        }

+        if ("Internal" == simcardRoam || "International" == simcardRoam) {

+            return true;

+        } else {

+            return false;

+        }

+    }

+    $(document).ready(function () {

+        setTimeout(function () {

+            timerUpdater();

+        }, 0);

+    });

+    function setNetwork(strNetworkNumber, nRat, nSubAct, callback) {

+        if ((typeof(strNetworkNumber) !== "string") || (strNetworkNumber === "") || (typeof(nRat) !== "number") || (isNaN(nRat))) {

+            if (typeof(callback) === "function") {

+                callback(false);

+                return;

+            }

+        }

+        var nRat1 = -1;

+        if (nRat === 0) {

+            nRat1 = 0;

+        } else if (nRat === 2) {

+            nRat1 = 2;

+        } else if (nRat == 7) {

+            nRat1 = 7;

+        } else {

+            nRat1 = -1;

+        }

+        if (-1 === nRat1) {

+            if (typeof(callback) === "function") {

+                callback(false);

+                return;

+            }

+        }

+        var SubAct;

+        if (nSubAct.toString() == "NaN") {

+            SubAct = "";

+        } else {

+            SubAct = nSubAct;

+        }

+        reqAsync({

+            goformId: "SET_NETWORK",

+            NetworkNumber: strNetworkNumber,

+            Rat: nRat,

+            nSubrat: SubAct

+        }, function (paramD) {

+            if (paramD && paramD.result == "success") {

+                var flag;

+                var counter = 0;

+                var timer = setInterval(function () {

+                    var obj = reqSync({

+                        cmd: 'm_netselect_result',

+                    }, false);

+                    if (!obj) {

+                        callback(false);

+                        return;

+                    }

+                    if (obj.m_netselect_result == "manual_success") {

+                        flag = "1";

+                        window.clearInterval(timer);

+                        callback(true);

+                    } else if (obj.m_netselect_result == "manual_fail") {

+                        flag = "0";

+                        window.clearInterval(timer);

+                        callback(false);

+                    } else if (counter < 120) {

+                        counter++;

+                    } else {

+                        window.clearInterval(timer);

+                        callback(false);

+                    }

+                }, 1000);

+            } else {

+                callback(false);

+            }

+        }, function (paramD) {

+            callback(false);

+        }, true);

+    }

+    function savePhoneBook() {

+        var callback = arguments[1];

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.notCallback = true;

+            valueReq.goformId = "PBM_CONTACT_ADD";

+            valueReq.location = values.location;

+            valueReq.name = encodeMessage(values.name);

+            valueReq.mobilephone_num = values.mobile_phone_number;

+            if (valueReq.location == 1) {

+                valueReq.add_index_pc = values.index;

+                valueReq.homephone_num = values.home_phone_number;

+                valueReq.officephone_num = values.office_phone_number;

+                valueReq.email = encodeMessage(values.mail);

+                valueReq.groupchoose = values.group;

+                if (!valueReq.groupchoose) {

+                    valueReq.groupchoose = "common";

+                }

+            } else {

+                valueReq.edit_index = values.index;

+            }

+            if (values.delId != undefined) {

+                valueReq.delId = values.delId;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                addTimerSomething("pbm_write_flag", checkSavePhoneBook);

+            } else {

+                callback(paramD);

+            }

+        }

+        function checkSavePhoneBook(paramD) {

+            checkPbmWriteFlag(paramD, callback, checkSavePhoneBook);

+        }

+    }

+    function checkPbmWriteFlag(paramD, callback, fn) {

+        if (paramD.pbm_write_flag == "0") {

+            removeTimerSomething("pbm_write_flag", fn);

+            callback({

+                result: "success"

+            });

+        } else if (paramD.pbm_write_flag == "6" || paramD.pbm_write_flag == "7" || paramD.pbm_write_flag == "8" || paramD.pbm_write_flag == "9" || paramD.pbm_write_flag == "10" || paramD.pbm_write_flag == "11" || paramD.pbm_write_flag == "14") {

+            removeTimerSomething("pbm_write_flag", fn);

+            callback({

+                result: "fail"

+            });

+        } else {}

+    }

+    function deletePhoneBooks() {

+        var callback = arguments[1];

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.notCallback = true;

+            valueReq.goformId = "PBM_CONTACT_DEL";

+            valueReq.del_option = "delete_num";

+            valueReq.delete_id = values.indexs.join(",");

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                addTimerSomething("pbm_write_flag", checkDeletePhoneBooks);

+            } else {

+                callback(paramD);

+            }

+        }

+        function checkDeletePhoneBooks(paramD) {

+            checkPbmWriteFlag(paramD, callback, checkDeletePhoneBooks);

+        }

+    }

+    function deleteAllPhoneBooks() {

+        var callback = arguments[1];

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.notCallback = true;

+            valueReq.goformId = "PBM_CONTACT_DEL";

+            valueReq.del_option = "delete_all";

+            valueReq.del_all_location = values.location;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                addTimerSomething("pbm_write_flag", checkDeleteAllPhoneBooks);

+            } else {

+                callback(paramD);

+            }

+        }

+        function checkDeleteAllPhoneBooks(paramD) {

+            checkPbmWriteFlag(paramD, callback, checkDeleteAllPhoneBooks);

+        }

+    }

+    function deleteAllPhoneBooksByGroup() {

+        var callback = arguments[1];

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.notCallback = true;

+            valueReq.goformId = "PBM_CONTACT_DEL";

+            valueReq.del_option = "delete_all_by_group";

+            valueReq.del_all_location = 3;

+            valueReq.del_group = values.group;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                addTimerSomething("pbm_write_flag", checkDeleteAllPhoneBooksByGroup);

+            } else {

+                callback(paramD);

+            }

+        }

+        function checkDeleteAllPhoneBooksByGroup(paramD) {

+            checkPbmWriteFlag(paramD, callback, checkDeleteAllPhoneBooksByGroup);

+        }

+    }

+    function setConnectionMode() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SET_CONNECTION_MODE";

+            valueReq.ConnectionMode = values.connectionMode;

+            valueReq.roam_setting_option = values.isAllowedRoaming;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                callback(paramD);

+            }

+        }

+    }

+    function getConnectionMode() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "ConnectionMode";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.connectionMode = paramD.connectionMode;

+                result.isAllowedRoaming = paramD.autoConnectWhenRoaming;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function _getPhoneBooks(array, location) {

+        if (array[0].data_per_page == 0) {

+            return {

+                "pbm_data": []

+            };

+        }

+        return stuffMake(array, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.mem_store = location;

+            if (location == 2) {

+                valueReq.cmd = "pbm_data_total";

+            } else {

+                valueReq.cmd = "pbm_data_info";

+            }

+            valueReq.page = values.page;

+            valueReq.data_per_page = values.data_per_page;

+            valueReq.orderBy = values.orderBy;

+            valueReq.isAsc = values.isAsc;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.pbm_data) {

+                var books = [];

+                $.each(paramD.pbm_data, function (i) {

+                    books.push({

+                        pbm_id: paramD.pbm_data[i].pbm_id,

+                        pbm_location: paramD.pbm_data[i].pbm_location,

+                        pbm_number: paramD.pbm_data[i].pbm_number,

+                        pbm_anr: paramD.pbm_data[i].pbm_anr,

+                        pbm_anr1: paramD.pbm_data[i].pbm_anr1,

+                        pbm_group: paramD.pbm_data[i].pbm_group,

+                        pbm_name: decodeMessage(paramD.pbm_data[i].pbm_name),

+                        pbm_email: decodeMessage(paramD.pbm_data[i].pbm_email)

+                    });

+                });

+                return {

+                    pbm_data: books

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getPhoneBooksByGroup() {

+        if (arguments[0].data_per_page == 0) {

+            return {

+                "pbm_data": []

+            };

+        }

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "pbm_data_total";

+            valueReq.mem_store = 3;

+            valueReq.pbm_group = values.group;

+            valueReq.page = values.page;

+            valueReq.data_per_page = values.data_per_page;

+            valueReq.orderBy = values.orderBy;

+            valueReq.isAsc = values.isAsc;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.pbm_data) {

+                var books = [];

+                $.each(paramD.pbm_data, function (i) {

+                    books.push({

+                        pbm_id: paramD.pbm_data[i].pbm_id,

+                        pbm_location: paramD.pbm_data[i].pbm_location,

+                        pbm_number: paramD.pbm_data[i].pbm_number,

+                        pbm_anr: paramD.pbm_data[i].pbm_anr,

+                        pbm_anr1: paramD.pbm_data[i].pbm_anr1,

+                        pbm_group: paramD.pbm_data[i].pbm_group,

+                        pbm_name: decodeMessage(paramD.pbm_data[i].pbm_name),

+                        pbm_email: decodeMessage(paramD.pbm_data[i].pbm_email)

+                    });

+                });

+                return {

+                    pbm_data: books

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getDevicePhoneBooks() {

+        return _getPhoneBooks(arguments, 1);

+    }

+    function getSIMPhoneBooks() {

+        return _getPhoneBooks(arguments, 0);

+    }

+    function getPhoneBooks() {

+        return _getPhoneBooks(arguments, 2);

+    }

+    function getPhoneBookReady() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "pbm_init_flag";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getPhoneBookCapacity(array, isSIM) {

+        return stuffMake(array, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "pbm_capacity_info";

+            if (isSIM) {

+                valueReq.pbm_location = "pbm_sim";

+            } else {

+                valueReq.pbm_location = "pbm_native";

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSIMPhoneBookCapacity() {

+        var paramD = getPhoneBookCapacity(arguments, true);

+        return {

+            simPbmTotalCapacity: parseInt(paramD.pbm_sim_max_record_num),

+            simPbmUsedCapacity: parseInt(paramD.pbm_sim_used_record_num),

+            simType: paramD.pbm_sim_type,

+            maxNameLen: parseInt(paramD.pbm_sim_max_name_len),

+            maxNumberLen: parseInt(paramD.pbm_sim_max_number_len) > 40 ? 40 : parseInt(paramD.pbm_sim_max_number_len)

+        };

+    }

+    function getDevicePhoneBookCapacity() {

+        var paramD = getPhoneBookCapacity(arguments, false);

+        return {

+            pcPbmTotalCapacity: parseInt(paramD.pbm_dev_max_record_num),

+            pcPbmUsedCapacity: parseInt(paramD.pbm_dev_used_record_num)

+        };

+    }

+    function getAttachedCableDevices() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var obj = {

+                cmd: "lan_station_list"

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            var deviceArr = [];

+            var attachedDevices = paramD.lan_station_list || paramD.station_list;

+            for (var i = 0; attachedDevices && i < attachedDevices.length; i++) {

+                var obj = {};

+                obj.macAddress = attachedDevices[i].mac_addr;

+                var hostname = attachedDevices[i].hostname;

+                obj.hostName = hostname == "" ? $.i18n.prop("unknown") : hostname;

+                obj.ipAddress = attachedDevices[i].ip_addr;

+                deviceArr.push(obj);

+            }

+            return {

+                attachedDevices: deviceArr

+            };

+        }

+    }

+    function getCurrentlyAttachedDevicesInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var obj = {

+                cmd: "station_list"

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            var deviceArr = [];

+            var attachedDevices = paramD.station_list;

+            for (var i = 0; attachedDevices && i < attachedDevices.length; i++) {

+                var obj = {};

+                obj.macAddress = attachedDevices[i].mac_addr;

+                var hostname = attachedDevices[i].hostname;

+                obj.hostName = hostname == "" ? $.i18n.prop("unknown") : hostname;

+                obj.ipAddress = attachedDevices[i].ip_addr;

+                deviceArr.push(obj);

+            }

+            return {

+                attachedDevices: deviceArr

+            };

+        }

+    }	

+

+    function setLanguage() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SET_WEB_LANGUAGE";

+            valueReq.Language = values.Language;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getLanguage() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "Language";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.Language = (paramD && paramD.Language) ? paramD.Language : "en";

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }	

+

+    function setBearerPreference() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SET_BEARER_PREFERENCE";

+            valueReq.BearerPreference = values.strBearerPreference;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function scanForNetwork(callback) {

+        $.post("/reqproc/proc_post", {

+            goformId: "SCAN_NETWORK"

+        }, function (paramD) {

+            if (paramD.result == "success") {

+                checkScanStatus();

+            } else {

+                callback(false, []);

+            }

+        }, "json").error(function () {

+            callback(false, []);

+        });

+        function checkScanStatus() {

+            $.getJSON("/reqproc/proc_get", {

+                cmd: "m_netselect_status",

+                "_": new Date().getTime()

+            }, function (paramD) {

+                if (paramD.m_netselect_status == "manual_selecting") {

+                    setTimeout(checkScanStatus, 1000);

+                } else {

+                    $.getJSON("/reqproc/proc_get", {

+                        cmd: "m_netselect_contents",

+                        "_": new Date().getTime()

+                    }, function (paramD2) {

+                        if (trim(paramD2.m_netselect_contents) != "") {

+                            parseScanResult(paramD2.m_netselect_contents);

+                        } else {

+                            callback(false, []);

+                        }

+                    }).error(function () {

+                        callback(false, []);

+                    });

+                }

+            }).error(function () {

+                callback(false, []);

+            });

+        }

+        function parseScanResult(result) {

+            var pattern = /([^,;]*),([^,]*),([^,]*),([^,]*),([^,;]*)/g;

+            var listNetwork = [];

+            var mts;

+            var unit = result.split(";");

+            var unitString = "";

+            for (i = 0; i < unit.length; i++) {

+                var unitLength = unit[i].split(",").length;

+                if (unitLength == 4) {

+                    unitString += unit[i] + ",NON;";

+                } else {

+                    unitString += unit[i] + ";";

+                }

+            }

+            while (mts = pattern.exec(unitString)) {

+                if (mts != null) {

+                    listNetwork.push({

+                        strShortName: mts[2].replace(/\"/g, ''),

+                        strNumeric: mts[3].replace(/\D/g, ''),

+                        nRat: parseInt(mts[4], 10),

+                        nState: parseInt(mts[1], 10),

+                        SubAct: parseInt(mts[5], 10)

+                    });

+                }

+            }

+            callback(true, listNetwork);

+        }

+    }

+	    function getNetSelectInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "current_network_mode,m_netselect_save,net_select_mode,m_netselect_contents,net_select,ppp_status,modem_main_state";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.current_network_mode = paramD.current_network_mode;

+                result.net_select_mode = paramD.net_select_mode;

+                result.m_netselect_save = paramD.m_netselect_save;

+                result.m_netselect_contents = paramD.m_netselect_contents;

+                result.net_select = paramD.net_select;

+                result.ppp_status = paramD.ppp_status;

+                result.modem_main_state = paramD.modem_main_state;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }	

+ 

+    function getSMSMessages() {

+        return stuffMake(arguments, {}, prepare, deal, {}, false);

+        function prepare(values, isPost) {

+            var obj = {

+                cmd: "sms_data_total",

+                page: values.page,

+                data_per_page: config.SMS_DATABASE_SORT_SUPPORT ? values.smsCount : 500,

+                mem_store: values.nMessageStoreType,

+                tags: values.tags,

+                order_by: values.orderBy

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.messages && paramD.messages.length > 0) {

+                return {

+                    messages: parseMessages(paramD.messages)

+                };

+            } else {

+                return {

+                    messages: []

+                };

+            }

+        }

+    }

+    function parseMessages(messages, isReport) {

+        var result = [];

+        for (var i = 0; i < messages.length; i++) {

+            if (!config.SHOW_UN_COMPLETE_CONCAT_SMS && typeof messages[i].received_all_concat_sms != "undefined" && messages[i].received_all_concat_sms == '0') {

+                continue;

+            }

+            var oneMessage = {};

+            oneMessage.id = messages[i].id;

+            oneMessage.number = messages[i].number;

+            oneMessage.content = isReport ? messages[i].content : decodeMessageContent(messages[i].content);

+            oneMessage.time = transTime('20' + messages[i].date);

+            oneMessage.isNew = messages[i].tag == "1";

+            oneMessage.groupId = messages[i].draft_group_id;

+            oneMessage.tag = messages[i].tag;

+            oneMessage.receivedAll = messages[i].received_all_concat_sms == '1';

+            result.push(oneMessage);

+        }

+        if (!config.SMS_DATABASE_SORT_SUPPORT) {

+            var ids = [];

+            var tmpResult = [];

+            for (var i = result.length; i--; ) {

+                var n = result[i];

+                var idx = $.inArray(n.id, ids);

+                if (idx == -1) {

+                    ids.push(n.id);

+                    tmpResult.push(n);

+                } else {

+                    if (n.content.length > tmpResult[idx].content.length) {

+                        tmpResult[idx] = n;

+                    }

+                }

+            }

+            return _.sortBy(tmpResult, function (n) {

+                return 0 - n.id;

+            });

+        } else {

+            return result;

+        }

+    }

+    function decodeMessageContent(msgContent) {

+        return decodeMessage(escapeMessage(msgContent));

+    }

+    function sendSMS() {

+        var callback = arguments[1];

+        var errorCabllback = arguments[2] ? arguments[2] : callback;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = {

+                goformId: "SEND_SMS",

+                notCallback: true,

+                Number: values.number,

+                sms_time: getCurrentTimeString(),

+                MessageBody: escapeMessage(encodeMessage(values.message)),

+                ID: values.id,

+                encode_type: getEncodeType(values.message).encodeType

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (!paramD) {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "sendFail",

+                        errorText: "send_fail_try_again"

+                    }));

+                return;

+            }

+            if (paramD.result == "success") {

+                setTimeout(function () {

+                    getSmsStatusInfo({

+                        smsCmd: 4,

+                        errorType: "sendFail",

+                        errorText: "send_fail_try_again"

+                    }, callback, errorCabllback);

+                }, 1000);

+            } else {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "sendFail",

+                        errorText: "send_fail_try_again"

+                    }));

+            }

+        }

+    }

+    function saveSMS() {

+        var callback = arguments[1];

+        var errorCabllback = arguments[2] ? arguments[2] : callback;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = {

+                notCallback: true,

+                goformId: "SAVE_SMS",

+                SMSMessage: escapeMessage(encodeMessage(values.message)),

+                SMSNumber: values.numbers.join(";") + ";",

+                Index: values.index,

+                encode_type: getEncodeType(values.message).encodeType,

+                sms_time: values.currentTimeString,

+                draft_group_id: values.groupId

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (!paramD) {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "saveFail",

+                        errorText: "save_fail"

+                    }));

+                return;

+            }

+            if (paramD.result == "success") {

+                getSmsStatusInfo({

+                    smsCmd: 5,

+                    errorType: "saveFail",

+                    errorText: "save_fail"

+                }, callback, errorCabllback);

+            } else {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "saveFail",

+                        errorText: "save_fail"

+                    }));

+            }

+        }

+    }

+    function deleteAllMessages() {

+        var callback = arguments[1];

+        var errorCabllback = arguments[2] ? arguments[2] : callback;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = {

+                goformId: "ALL_DELETE_SMS",

+                notCallback: true,

+                which_cgi: values.location

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (!paramD) {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "deleteFail",

+                        errorText: "delete_fail_try_again"

+                    }));

+                return;

+            }

+            if (paramD.result == "success") {

+                addTimerSomething("sms_cmd_status_info", checkDeleteStatus);

+            } else {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "deleteFail",

+                        errorText: "delete_fail_try_again"

+                    }));

+            }

+        }

+        function checkDeleteStatus(paramD) {

+            var status = paramD.sms_cmd_status_info;

+            if (status == "2") {

+                removeTimerSomething("sms_cmd_status_info", checkDeleteStatus);

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "deleteFail",

+                        errorText: "delete_fail_try_again"

+                    }));

+            } else if (status == "3") {

+                removeTimerSomething("sms_cmd_status_info", checkDeleteStatus);

+                callback({

+                    result: true

+                });

+            }

+        }

+    }

+    function deleteMessage() {

+        var callback = arguments[1];

+        var errorCabllback = arguments[2] ? arguments[2] : callback;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var msgIds = values.ids.join(";") + ";";

+            var obj = {

+                goformId: "DELETE_SMS",

+                msg_id: msgIds,

+                notCallback: true

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (!paramD) {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "deleteFail",

+                        errorText: "delete_fail_try_again"

+                    }));

+                return;

+            }

+            if (paramD.result == "success") {

+                getSmsStatusInfo({

+                    smsCmd: 6,

+                    errorType: "deleteFail",

+                    errorText: "delete_fail_try_again"

+                }, callback, errorCabllback);

+            } else {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "deleteFail",

+                        errorText: "delete_fail_try_again"

+                    }));

+            }

+        }

+    }

+    function getSmsStatusInfo(obj, callback, errorCabllback) {

+        reqAsync({

+            cmd: "sms_cmd_status_info",

+            sms_cmd: obj.smsCmd,

+        }, function (paramD) {

+            if (paramD) {

+                var status = paramD.sms_cmd_status_result;

+                if (status == "2") {

+                    errorCabllback($.extend(errUnknownObj, {

+                            errorType: obj.errorType,

+                            errorText: obj.errorText

+                        }));

+                } else if (status == "3") {

+                    callback({

+                        result: "success"

+                    });

+                } else {

+                    window.setTimeout(function () {

+                        getSmsStatusInfo(obj, callback, errorCabllback);

+                    }, 1000);

+                }

+            } else {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: obj.errorType,

+                        errorText: obj.errorText

+                    }));

+            }

+        }, function (paramD) {

+            errorCabllback($.extend(errUnknownObj, {

+                    errorType: obj.errorType,

+                    errorText: obj.errorText

+                }));

+        }, false);

+    }

+    function getSMSReady() {

+        if (config.smsIsReady) {

+            var callback = arguments[1];

+            if (callback) {

+                return callback({

+                    "sms_cmd": "1",

+                    "sms_cmd_status_result": "3"

+                });

+            } else {

+                return {

+                    "sms_cmd": "1",

+                    "sms_cmd_status_result": "3"

+                };

+            }

+        } else {

+            return stuffMake(arguments, {}, prepare, deal, null, false);

+        }

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "sms_cmd_status_info";

+            valueReq.sms_cmd = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.sms_cmd_status_result == "3") {

+                    config.smsIsReady = true;

+                }

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSmsRead() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var msgIds = values.ids.join(";");

+            if (values.ids.length > 0) {

+                msgIds += ";";

+            }

+            var obj = {

+                goformId: "SET_MSG_READ",

+                msg_id: msgIds,

+                tag: 0

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function getSMSDeliveryReport() {

+        return stuffMake(arguments, {}, prepare, deal, {}, false);

+        function prepare(values, isPost) {

+            var obj = {

+                cmd: "sms_status_rpt_data",

+                page: values.page,

+                data_per_page: values.smsCount

+            };

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    messages: parseMessages(paramD.messages, true)

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function logout() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = $.extend({}, values);

+            obj.goformId = "LOGOUT";

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                informationAll.isLoggedIn = false;

+                return {

+                    result: true

+                };

+            } else {

+                return $.extend(errUnknownObj, {

+                    errorType: "loggedOutError"

+                });

+            }

+        }

+    }

+    function changeManageInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = {};

+            obj.newPassword = config.PASSWORD_ENCODE ? Base64.encode(values.newValue) : values.newValue;

+            obj.oldPassword = config.PASSWORD_ENCODE ? Base64.encode(values.oldValue) : values.oldValue;

+            obj.goformId = "CHANGE_PASSWORD";

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result === "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return $.extend(errUnknownObj, {

+                    errorType: "badPassword"

+                });

+            }

+        }

+    }

+    function getPinData() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "pinnumber,pin_status,puknumber";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function enablePin() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = {};

+            obj.goformId = "ENABLE_PIN";

+            obj.OldPinNumber = values.oldPin;

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result === "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function disablePin() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = {};

+            obj.goformId = "DISABLE_PIN";

+            obj.OldPinNumber = values.oldPin;

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result === "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function changePin() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var obj = {};

+            obj.goformId = "ENABLE_PIN";

+            obj.OldPinNumber = values.oldPin;

+            obj.NewPinNumber = values.newPin;

+            return obj;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result === "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function getLanInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "lan_ipaddr,lan_netmask,mac_address,dhcpEnabled,dhcpStart,dhcpEnd,dhcpLease_hour";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.ipAddress = paramD.lan_ipaddr;

+                result.subnetMask = paramD.lan_netmask;

+                result.macAddress = paramD.mac_address;

+                result.dhcpServer = paramD.dhcpEnabled;

+                result.dhcpStart = paramD.dhcpStart;

+                result.dhcpEnd = paramD.dhcpEnd;

+                result.dhcpLease = parseInt(paramD.dhcpLease_hour, 10);

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setLanInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "DHCP_SETTING";

+            valueReq.lanIp = values.ipAddress;

+            valueReq.lanNetmask = values.subnetMask;

+            valueReq.lanDhcpType = values.dhcpServer == "1" ? "SERVER" : "DISABLE";

+            if (valueReq.lanDhcpType == "SERVER") {

+                valueReq.dhcpStart = values.dhcpStart;

+                valueReq.dhcpEnd = values.dhcpEnd;

+                valueReq.dhcpLease = values.dhcpLease;

+            }

+            valueReq.dhcp_reboot_flag = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSmsSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "sms_parameter_info";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.centerNumber = paramD.sms_para_sca;

+                result.memStroe = paramD.sms_para_mem_store;

+                result.deliveryReport = paramD.sms_para_status_report;

+                switch (parseInt(paramD.sms_para_validity_period, 10)) {

+                case 143:

+                    result.validity = "twelve_hours";

+                    break;

+                case 167:

+                    result.validity = "one_day";

+                    break;

+                case 173:

+                    result.validity = "one_week";

+                    break;

+                case 244:

+                    result.validity = "largest";

+                    break;

+                case 255:

+                    result.validity = "largest";

+                    break;

+                default:

+                    result.validity = "twelve_hours";

+                    break;

+                }

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSmsSetting() {

+        var callback = arguments[1];

+        var errorCabllback = arguments[2] ? arguments[2] : callback;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SET_MESSAGE_CENTER";

+            valueReq.save_time = values.validity;

+            valueReq.MessageCenter = values.centerNumber;

+            valueReq.status_save = values.deliveryReport;

+            valueReq.save_location = 'native';

+            valueReq.notCallback = true;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (!paramD) {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "smsSettingFail",

+                        errorText: "error_info"

+                    }));

+                return;

+            }

+            if (paramD.result == "success") {

+                getSmsStatusInfo({

+                    smsCmd: 3,

+                    errorType: "smsSettingFail",

+                    errorText: "error_info"

+                }, callback, errorCabllback);

+            } else {

+                errorCabllback($.extend(errUnknownObj, {

+                        errorType: "deleteFail",

+                        errorText: "delete_fail_try_again"

+                    }));

+            }

+        }

+    }

+    function restoreFactorySettings() {

+        var preErrorObj = {};

+        if (config.HAS_PARENTAL_CONTROL && config.currentUserInChildGroup != false) {

+            preErrorObj = {

+                errorType: 'no_auth'

+            };

+        }

+        return stuffMake(arguments, preErrorObj, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "RESTORE_FACTORY_SETTINGS";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function checkRestoreStatus(successCallback) {

+        var valueReq = {};

+        valueReq.cmd = "restore_flag";

+        valueReq.multi_data = 1;

+        reqAsync(valueReq, function (paramD) {

+            if (paramD && paramD.restore_flag === "1") {

+                successCallback();

+            } else {

+                setTimeout(function () {

+                    checkRestoreStatus(successCallback);

+                }, 5000);

+            }

+        }, function () {

+            setTimeout(function () {

+                checkRestoreStatus(successCallback);

+            }, 5000);

+        }, false);

+    }

+    function getWpsInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "wifi_wps_index,WscModeOption,AuthMode,wifi_cur_state,EncrypType,wps_mode,WPS_SSID,m_ssid_enable,SSID1,m_SSID,m_EncrypType,m_AuthMode,wifi_sta_connection";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.wpsFlag = paramD.WscModeOption;

+                result.authMode = paramD.AuthMode;

+                result.wpsType = paramD.wps_mode;

+                result.radioFlag = paramD.wifi_cur_state == "1" ? "1" : "0";

+                result.encrypType = paramD.EncrypType;

+                result.wpsSSID = paramD.WPS_SSID;

+                result.ssidEnable = paramD.m_ssid_enable;

+                result.ssid = paramD.SSID1;

+                result.multiSSID = paramD.m_SSID;

+                result.m_encrypType = paramD.m_EncrypType;

+                result.wifi_wps_index = paramD.wifi_wps_index;

+                result.AuthMode = paramD.AuthMode;

+                result.m_AuthMode = paramD.m_AuthMode;

+                result.ap_station_enable = paramD.wifi_sta_connection;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function openWps() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "WIFI_WPS_SET";

+            valueReq.WPS_SSID = values.wpsSSID;

+            valueReq.wps_mode = values.wpsType;

+            valueReq.wifi_wps_index = values.wpsIndex;

+            if (valueReq.wps_mode == 'PIN') {

+                valueReq.wps_pin = values.wpsPin;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function openWps_5g() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "WIFI_M_WPS_SET";

+            valueReq.m_WPS_SSID = values.wpsSSID;

+            valueReq.m_wps_mode = values.wpsType;

+            valueReq.m_wifi_wps_index = values.wpsIndex;

+            if (valueReq.m_wps_mode == 'PIN') {

+                valueReq.m_wps_pin = values.wpsPin;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSleepMode() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "Sleep_interval";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.sleepMode = paramD.Sleep_interval;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSleepMode() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SET_WIFI_SLEEP_INFO";

+            valueReq.sysIdleTimeToSleep = values.sleepMode;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSysSecurity() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "RemoteManagement,WANPingFilter";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.remoteFlag = paramD.RemoteManagement == "1" ? "1" : "0";

+                result.pingFlag = paramD.WANPingFilter == "1" ? "1" : "0";

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSysSecurity() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "FW_SYS";

+            valueReq.remoteManagementEnabled = values.remoteFlag;

+            valueReq.pingFrmWANFilterEnabled = values.pingFlag;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getPortForward() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "PortForwardEnable,PortForwardRules_0,PortForwardRules_1,PortForwardRules_2,PortForwardRules_3,PortForwardRules_4,PortForwardRules_5,PortForwardRules_6,PortForwardRules_7,PortForwardRules_8,PortForwardRules_9";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.portForwardEnable = paramD.PortForwardEnable;

+                var rules = [];

+                if (paramD.PortForwardRules_0 != "") {

+                    rules.push([0, paramD.PortForwardRules_0]);

+                }

+                if (paramD.PortForwardRules_1 != "") {

+                    rules.push([1, paramD.PortForwardRules_1]);

+                }

+                if (paramD.PortForwardRules_2 != "") {

+                    rules.push([2, paramD.PortForwardRules_2]);

+                }

+                if (paramD.PortForwardRules_3 != "") {

+                    rules.push([3, paramD.PortForwardRules_3]);

+                }

+                if (paramD.PortForwardRules_4 != "") {

+                    rules.push([4, paramD.PortForwardRules_4]);

+                }

+                if (paramD.PortForwardRules_5 != "") {

+                    rules.push([5, paramD.PortForwardRules_5]);

+                }

+                if (paramD.PortForwardRules_6 != "") {

+                    rules.push([6, paramD.PortForwardRules_6]);

+                }

+                if (paramD.PortForwardRules_7 != "") {

+                    rules.push([7, paramD.PortForwardRules_7]);

+                }

+                if (paramD.PortForwardRules_8 != "") {

+                    rules.push([8, paramD.PortForwardRules_8]);

+                }

+                if (paramD.PortForwardRules_9 != "") {

+                    rules.push([9, paramD.PortForwardRules_9]);

+                }

+                result.portForwardRules = parsePortForwardRules(rules);

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+        function parsePortForwardRules(paramD) {

+            var rules = [];

+            if (paramD && paramD.length > 0) {

+                for (var i = 0; i < paramD.length; i++) {

+                    var aRule = {};

+                    var elements = paramD[i][1].split(",");

+                    aRule.index = paramD[i][0];

+                    aRule.ipAddress = elements[0];

+                    aRule.portRange = elements[1] + ' - ' + elements[2];

+                    aRule.protocol = transProtocol(elements[3]);

+                    aRule.comment = elements[4];

+                    rules.push(aRule);

+                }

+            }

+            return rules;

+        }

+    }

+    function setPortForward() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "FW_FORWARD_ADD";

+            valueReq.ipAddress = values.ipAddress;

+            valueReq.portStart = values.portStart;

+            valueReq.portEnd = values.portEnd;

+            valueReq.protocol = values.protocol;

+            valueReq.comment = values.comment;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function deleteForwardRules() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "FW_FORWARD_DEL";

+            valueReq.delete_id = values.indexs.join(';') + ";";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function enableVirtualServer() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "VIRTUAL_SERVER";

+            valueReq.PortForwardEnable = values.portForwardEnable;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function wifiDecode(fact1,fact2,encode_aes) {//wifiDecode(paramD.rnum_js,paramD.imei,paramD.WPAPSK1_enaes,paramD.m_WPAPSK1_enaes);

+        var kstr = fact1 + fact2 + "FFFFFFFFFFFFFFFFFFFFFFFF";

+        var kstr_final;

+	var kiv_final;

+

+        kstr_final = kstr.substring(0, 24);

+	kiv_final = kstr.substring(0, 16);

+

+        var tkey = CryptoJS.enc.Latin1.parse(kstr_final);

+	var tiv = CryptoJS.enc.Latin1.parse(kiv_final);

+        var decdata = CryptoJS.AES.decrypt(encode_aes, tkey, {

+            iv: tiv,

+            mode: CryptoJS.mode.CBC,

+            padding: CryptoJS.pad.ZeroPadding

+        }).toString(CryptoJS.enc.Utf8);

+

+        return decdata;

+    }

+    function getQuickSettingInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            var wpask = config.PASSWORD_ENCODE ? ",WPAPSK1_encode" : ",imei,rnum_js,WPAPSK1_enaes";

+            valueReq.cmd = "pdp_type,ipv6_pdp_type,wifi_cur_state,SSID1,HideSSID,AuthMode,WscModeOption,ppp_status,apn_index,ipv6_apn_index,ipv6_APN_index,m_profile_name,apn_mode,EncrypType,DefaultKeyID,Key1Str1,Key2Str1,Key3Str1,Key4Str1" + wpask + ",APN_configtmp0,APN_configtmp1,APN_configtmp2,APN_configtmp3,APN_configtmp4,APN_configtmp5,APN_configtmp6,APN_configtmp7,APN_configtmp8,APN_configtmp9,APN_configtmp10,APN_configtmp11,APN_configtmp12,APN_configtmp13,APN_configtmp14,APN_configtmp15,APN_configtmp16,APN_configtmp17,APN_configtmp18,APN_configtmp19" + ",ipv6_APN_configtmp0,ipv6_APN_configtmp1,ipv6_APN_configtmp2,ipv6_APN_configtmp3,ipv6_APN_configtmp4,ipv6_APN_configtmp5,ipv6_APN_configtmp6,ipv6_APN_configtmp7,ipv6_APN_configtmp8,ipv6_APN_configtmp9,ipv6_APN_configtmp10,ipv6_APN_configtmp11,ipv6_APN_configtmp12,ipv6_APN_configtmp13,ipv6_APN_configtmp14,ipv6_APN_configtmp15,ipv6_APN_configtmp16,ipv6_APN_configtmp17,ipv6_APN_configtmp18,ipv6_APN_configtmp19";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (config.PASSWORD_ENCODE) {

+                    paramD.WPAPSK1 = Base64.decode(paramD.WPAPSK1_encode);

+                } else {

+		    paramD.WPAPSK1 = wifiDecode(paramD.rnum_js,paramD.imei,paramD.WPAPSK1_enaes);

+		}

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setQuickSetting4IPv6() {

+        stuffMakeAndCheckServerIsOnline(arguments, prepare, deal);

+        function prepare(values) {

+            var valueReq = {

+                goformId: "QUICK_SETUP_EX",

+                index: values.apn_index,

+                pdp_type: values.pdp_type,

+                apn_mode: values.apnMode,

+                profile_name: values.profile_name,

+                wan_apn: values.wan_apn,

+                ppp_auth_mode: values.ppp_auth_mode,

+                ppp_username: values.ppp_username,

+                ppp_passtmp: values.ppp_passtmp,

+                ipv6_wan_apn: values.ipv6_wan_apn,

+                ipv6_ppp_auth_mode: values.ipv6_ppp_auth_mode,

+                ipv6_ppp_username: values.ipv6_ppp_username,

+                ipv6_ppp_passtmp: values.ipv6_ppp_passtmp,

+                SSID_name: values.SSID_name,

+                SSID_Broadcast: values.SSID_Broadcast,

+                Encryption_Mode_hid: values.Encryption_Mode_hid,

+                security_shared_mode: values.security_shared_mode,

+                WPA_PreShared_Key: config.PASSWORD_ENCODE ? Base64.encode(values.WPA_PreShared_Key) : values.WPA_PreShared_Key,

+                wep_default_key: values.wep_default_key,

+                WPA_ENCRYPTION_hid: values.WPA_ENCRYPTION_hid

+            }

+            valueReq.wep_key_1 = values.wep_key_1;

+            valueReq.wep_key_2 = values.wep_key_2;

+            valueReq.wep_key_3 = values.wep_key_3;

+            valueReq.wep_key_4 = values.wep_key_4;

+            if (values.wep_default_key == '1') {

+                valueReq.WEP2Select = values.WEP2Select;

+            } else if (values.wep_default_key == '2') {

+                valueReq.WEP3Select = values.WEP3Select;

+            } else if (values.wep_default_key == '3') {

+                valueReq.WEP4Select = values.WEP4Select;

+            } else {

+                valueReq.WEP1Select = values.WEP1Select;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return $.extend(errUnknownObj, {

+                    errorType: "SetSetUpError"

+                });

+            }

+        }

+    }

+    function stuffMakeAndCheckServerIsOnline(arg, prepare, deal) {

+        var isServerOnline = false;

+        var isCallbackExecuted = false;

+        var values = prepare(arg[0]);

+        var callback = arg[1];

+        var successCallback = function (paramD) {

+            isServerOnline = true;

+            if (!isCallbackExecuted && callback) {

+                callback(deal(paramD));

+            }

+            isCallbackExecuted = true;

+        };

+        var errorMethod = arg[2];

+        var errorCallback = function () {

+            isServerOnline = true;

+            if (errorMethod) {

+                errorMethod();

+            }

+        };

+        reqAsync(values, successCallback, errorCallback, true);

+        addTimeout(function () {

+            if (isServerOnline == false) {

+                var timer = addInterval(function () {

+                    if (isServerOnline == false) {

+                        getLanguage({}, function (paramD) {

+                            window.clearInterval(timer);

+                            successCallback({

+                                result: "success"

+                            });

+                        });

+                    }

+                }, 1000);

+            }

+        }, 5000);

+    }

+    function getSDConfiguration() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "sdcard_mode_option,sd_card_state,HTTP_SHARE_STATUS,HTTP_SHARE_WR_AUTH,HTTP_SHARE_FILE",

+                multi_data: 1

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var fileToShare;

+                if ("mmc2" == paramD.HTTP_SHARE_FILE || "/mmc2" == paramD.HTTP_SHARE_FILE || "/mmc2/" == paramD.HTTP_SHARE_FILE) {

+                    fileToShare = "1";

+                } else {

+                    fileToShare = "0";

+                }

+                var result = {

+                    sd_mode: paramD.sdcard_mode_option == "1" ? "0" : "1",

+                    sd_status: paramD.sd_card_state,

+                    share_status: paramD.HTTP_SHARE_STATUS == "Enabled" ? "1" : "0",

+                    share_auth: paramD.HTTP_SHARE_WR_AUTH == "readOnly" ? "0" : "1",

+                    file_to_share: fileToShare,

+                    share_file: paramD.HTTP_SHARE_FILE

+                };

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSdCardMode() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "HTTPSHARE_MODE_SET",

+                mode_set: values.mode == "0" ? "http_share_mode" : "usb_mode"

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return {

+                    result: 'success'

+                };

+            } else if (paramD && paramD.result == 'processing') {

+                return {

+                    result: 'processing'

+                };

+            } else {

+                return {

+                    result: false

+                };

+            }

+        }

+    }

+    function checkFileExists() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "GOFORM_HTTPSHARE_CHECK_FILE",

+                path_SD_CARD: values.path

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.result == "no_sdcard") {

+                    return {

+                        status: "no_sdcard"

+                    };

+                } else if (paramD.result == "noexist") {

+                    return {

+                        status: "noexist"

+                    };

+                } else if (paramD.result == "processing") {

+                    return {

+                        status: "processing"

+                    };

+                } else {

+                    return {

+                        status: "exist"

+                    };

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getFileList() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "HTTPSHARE_ENTERFOLD",

+                path_SD_CARD: values.path,

+                indexPage: values.index

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.result == 'failure') {

+                    return $.extend(errUnknownObj, {

+                        errorType: "get_file_list_failure"

+                    });

+                } else if (paramD.result == "no_sdcard") {

+                    return $.extend(errUnknownObj, {

+                        errorType: "no_sdcard"

+                    });

+                } else {

+                    return parseSdCardFile(paramD.result);

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+        function parseSdCardFile(result) {

+            var fileInfo = {};

+            fileInfo.totalRecord = result.totalRecord;

+            var fileArr = [];

+            var details = result.fileInfo;

+            for (var i = 0; details && i < details.length; i++) {

+                if (details[i].fileName == "") {

+                    continue;

+                }

+                var obj = {};

+                obj.fileName = details[i].fileName;

+                obj.attribute = details[i].attribute;

+                obj.size = details[i].size;

+                obj.lastUpdateTime = details[i].lastUpdateTime;

+                fileArr.push(obj);

+            }

+            fileInfo.details = fileArr;

+            return fileInfo;

+        }

+    }

+    function fileRename() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var d = new Date();

+            var currentTime = d.getTime();

+            var zoneOffsetSeconds = d.getTimezoneOffset() * 60;

+            return {

+                goformId: "HTTPSHARE_FILE_RENAME",

+                path_SD_CARD: values.path,

+                OLD_NAME_SD_CARD: values.oldPath,

+                NEW_NAME_SD_CARD: values.newPath,

+                path_SD_CARD_time: transUnixTime(currentTime),

+                path_SD_CARD_time_unix: Math.round((currentTime - zoneOffsetSeconds * 1000) / 1e3)

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.result == "success") {

+                    return {

+                        result: true

+                    };

+                } else if (paramD.result == "no_sdcard") {

+                    return $.extend(errUnknownObj, {

+                        errorType: "no_sdcard"

+                    });

+                } else if (paramD.result == "noexist") {

+                    return $.extend(errUnknownObj, {

+                        errorType: "no_exist"

+                    });

+                } else if (paramD.result == "processing") {

+                    return $.extend(errUnknownObj, {

+                        errorType: "sd_file_processing_cant_rename"

+                    });

+                } else {

+                    return {

+                        result: false

+                    };

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSdMemorySizes() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "HTTPSHARE_GETCARD_VALUE"

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (!paramD || (paramD.result && paramD.result == "no_sdcard")) {

+                return $.extend(errUnknownObj, {

+                    errorType: "no_sdcard"

+                });

+            } else {

+                return {

+                    totalMemorySize: paramD.sd_card_total_size == "" ? 0 : paramD.sd_card_total_size * 32 * 1024,

+                    availableMemorySize: paramD.sd_card_avi_space == "" ? 0 : paramD.sd_card_avi_space * 32 * 1024

+                };

+            }

+        }

+    }

+    function deleteFilesAndFolders() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var currentTime = new Date().getTime();

+            var valueReq = {

+                goformId: "HTTPSHARE_DEL",

+                path_SD_CARD: values.path,

+                name_SD_CARD: values.names,

+                path_SD_CARD_time: transUnixTime(currentTime),

+                path_SD_CARD_time_unix: Math.round(currentTime / 1e3)

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD.result && paramD.result == "failure") {

+                return {

+                    status: "failure"

+                };

+            } else if (paramD.result && paramD.result == "no_sdcard") {

+                return {

+                    status: "no_sdcard"

+                };

+            } else if (paramD.result && paramD.result == "processing") {

+                return {

+                    status: "processing"

+                };

+            } else if (paramD.result && paramD.result == "success") {

+                return {

+                    status: "success"

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function createFolder() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var d = new Date();

+            var currentTime = d.getTime();

+            var zoneOffsetSeconds = d.getTimezoneOffset() * 60;

+            return {

+                goformId: "HTTPSHARE_NEW",

+                path_SD_CARD: values.path,

+                path_SD_CARD_time: transUnixTime(currentTime),

+                path_SD_CARD_time_unix: Math.round((currentTime - zoneOffsetSeconds * 1000) / 1e3)

+            };

+        }

+        function deal(paramD) {

+            if (paramD.result && paramD.result == "failure") {

+                return $.extend(errUnknownObj, {

+                    errorType: "create_folder_failure"

+                });

+            } else if (paramD.result && paramD.result == "no_sdcard") {

+                return $.extend(errUnknownObj, {

+                    errorType: "no_sdcard"

+                });

+            } else if (paramD.result && paramD.result == "success") {

+                return {

+                    result: true

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSdCardSharing() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "HTTPSHARE_AUTH_SET",

+                HTTP_SHARE_STATUS: values.share_status == "1" ? "Enabled" : "Disabled",

+                HTTP_SHARE_WR_AUTH: values.share_auth == "1" ? "readWrite" : "readOnly",

+                HTTP_SHARE_FILE: values.share_file

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.result == "no_sdcard") {

+                    return $.extend(errUnknownObj, {

+                        errorType: "no_sdcard"

+                    });

+                } else {

+                    return {

+                        result: true

+                    };

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getPortFilter() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "IPPortFilterEnable,DefaultFirewallPolicy,IPPortFilterRules_0,IPPortFilterRules_1,IPPortFilterRules_2,IPPortFilterRules_3,IPPortFilterRules_4,IPPortFilterRules_5,IPPortFilterRules_6,IPPortFilterRules_7,IPPortFilterRules_8,IPPortFilterRules_9";

+            valueReq.cmd += ",IPPortFilterRulesv6_0,IPPortFilterRulesv6_1,IPPortFilterRulesv6_2,IPPortFilterRulesv6_3,IPPortFilterRulesv6_4,IPPortFilterRulesv6_5,IPPortFilterRulesv6_6,IPPortFilterRulesv6_7,IPPortFilterRulesv6_8,IPPortFilterRulesv6_9";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.portFilterEnable = paramD.IPPortFilterEnable;

+                result.defaultPolicy = paramD.DefaultFirewallPolicy;

+                var rules = [];

+                if (paramD.IPPortFilterRules_0 != "") {

+                    rules.push([0, paramD.IPPortFilterRules_0]);

+                }

+                if (paramD.IPPortFilterRules_1 != "") {

+                    rules.push([1, paramD.IPPortFilterRules_1]);

+                }

+                if (paramD.IPPortFilterRules_2 != "") {

+                    rules.push([2, paramD.IPPortFilterRules_2]);

+                }

+                if (paramD.IPPortFilterRules_3 != "") {

+                    rules.push([3, paramD.IPPortFilterRules_3]);

+                }

+                if (paramD.IPPortFilterRules_4 != "") {

+                    rules.push([4, paramD.IPPortFilterRules_4]);

+                }

+                if (paramD.IPPortFilterRules_5 != "") {

+                    rules.push([5, paramD.IPPortFilterRules_5]);

+                }

+                if (paramD.IPPortFilterRules_6 != "") {

+                    rules.push([6, paramD.IPPortFilterRules_6]);

+                }

+                if (paramD.IPPortFilterRules_7 != "") {

+                    rules.push([7, paramD.IPPortFilterRules_7]);

+                }

+                if (paramD.IPPortFilterRules_8 != "") {

+                    rules.push([8, paramD.IPPortFilterRules_8]);

+                }

+                if (paramD.IPPortFilterRules_9 != "") {

+                    rules.push([9, paramD.IPPortFilterRules_9]);

+                }

+                result.portFilterRules = parsePortFilterRules(rules, "IPv4");

+                var v6Rules = [];

+                if (paramD.IPPortFilterRulesv6_0 != "") {

+                    v6Rules.push([10, paramD.IPPortFilterRulesv6_0]);

+                }

+                if (paramD.IPPortFilterRulesv6_1 != "") {

+                    v6Rules.push([11, paramD.IPPortFilterRulesv6_1]);

+                }

+                if (paramD.IPPortFilterRulesv6_2 != "") {

+                    v6Rules.push([12, paramD.IPPortFilterRulesv6_2]);

+                }

+                if (paramD.IPPortFilterRulesv6_3 != "") {

+                    v6Rules.push([13, paramD.IPPortFilterRulesv6_3]);

+                }

+                if (paramD.IPPortFilterRulesv6_4 != "") {

+                    v6Rules.push([14, paramD.IPPortFilterRulesv6_4]);

+                }

+                if (paramD.IPPortFilterRulesv6_5 != "") {

+                    v6Rules.push([15, paramD.IPPortFilterRulesv6_5]);

+                }

+                if (paramD.IPPortFilterRulesv6_6 != "") {

+                    v6Rules.push([16, paramD.IPPortFilterRulesv6_6]);

+                }

+                if (paramD.IPPortFilterRulesv6_7 != "") {

+                    v6Rules.push([17, paramD.IPPortFilterRulesv6_7]);

+                }

+                if (paramD.IPPortFilterRulesv6_8 != "") {

+                    v6Rules.push([18, paramD.IPPortFilterRulesv6_8]);

+                }

+                if (paramD.IPPortFilterRulesv6_9 != "") {

+                    v6Rules.push([19, paramD.IPPortFilterRulesv6_9]);

+                }

+                result.portFilterRules = _.union(result.portFilterRules, parsePortFilterRules(v6Rules, "IPv6"));

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+        function parsePortFilterRules(paramD, ipTypeTmp) {

+            var rules = [];

+            if (paramD && paramD.length > 0) {

+                for (var i = 0; i < paramD.length; i++) {

+                    var aRule = {};

+                    var elements = paramD[i][1].split(",");

+                    aRule.index = paramD[i][0];

+                    aRule.macAddress = elements[11];

+                    aRule.destIpAddress = elements[4] == "any/0" ? "" : elements[4];

+                    aRule.sourceIpAddress = elements[0] == "any/0" ? "" : elements[0];

+                    aRule.destPortRange = elements[6] == '0' ? '' : elements[6] + " - " + elements[7];

+                    aRule.sourcePortRange = elements[2] == '0' ? '' : elements[2] + " - " + elements[3];

+                    aRule.action = elements[9] == 1 ? "filter_accept" : "filter_drop";

+                    aRule.protocol = transProtocol(elements[8]);

+                    aRule.comment = elements[10];

+                    aRule.ipType = ipTypeTmp;

+                    rules.push(aRule);

+                }

+            }

+            return rules;

+        }

+    }

+    function setPortFilterBasic() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "BASIC_SETTING";

+            valueReq.portFilterEnabled = values.portFilterEnable;

+            valueReq.defaultFirewallPolicy = values.defaultPolicy;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setPortFilter() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "ADD_IP_PORT_FILETER_V4V6";

+            valueReq.ip_version = values.ipType;

+            valueReq.mac_address = values.macAddress;

+            valueReq.dip_address = values.destIpAddress;

+            valueReq.sip_address = values.sourceIpAddress;

+            valueReq.dFromPort = values.destPortStart;

+            valueReq.dToPort = values.destPortEnd;

+            valueReq.sFromPort = values.sourcePortStart;

+            valueReq.sToPort = values.sourcePortEnd;

+            valueReq.action = values.action;

+            valueReq.protocol = values.protocol;

+            valueReq.comment = values.comment;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function deleteFilterRules() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            var deleteIds = _.filter(values.indexs, function (item) {

+                return item.length == 1;

+            });

+            valueReq.goformId = "DEL_IP_PORT_FILETER_V4V6";

+            var deletev6Ids = [];

+            _.each(values.indexs, function (item) {

+                if (item.length == 2) {

+                    deletev6Ids.push(item.substring(1));

+                }

+            });

+            valueReq.delete_id_v6 = deletev6Ids.length > 0 ? deletev6Ids.join(';') + ";" : "";

+            valueReq.delete_id = deleteIds.length > 0 ? deleteIds.join(';') + ";" : "";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getWifiAdvance() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "WirelessMode,CountryCode,Channel,HT_MCS,wifi_band,wifi_11n_cap,MAX_Access_num,m_MAX_Access_num,MAX_Station_num,wifi_sta_connection";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {

+                    mode: paramD.WirelessMode,

+                    countryCode: paramD.CountryCode,

+                    channel: paramD.Channel,

+                    rate: paramD.HT_MCS,

+                    wifiBand: paramD.wifi_band == 'a' ? 'a' : 'b',

+                    bandwidth: paramD.wifi_11n_cap,

+                    MAX_Station_num: $.isNumeric(paramD.MAX_Station_num) ? paramD.MAX_Station_num : config.MAX_STATION_NUMBER,

+                    MAX_Access_num: paramD.MAX_Access_num,

+                    m_MAX_Access_num: paramD.m_MAX_Access_num,

+                    ap_station_enable: paramD.wifi_sta_connection

+                };

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setWifiAdvance() {

+        stuffMakeAndCheckServerIsOnline(arguments, prepare, deal);

+        function prepare(values) {

+            var valueReq = {

+                goformId: "SET_WIFI_INFO",

+                wifiMode: values.mode,

+                countryCode: values.countryCode,

+                MAX_Access_num: values.station,

+                m_MAX_Access_num: values.m_station

+            };

+            if (config.WIFI_BAND_SUPPORT) {

+                valueReq.wifi_band = values.wifiBand;

+            }

+            if (config.WIFI_BAND_SUPPORT && values.wifiBand == 'a') {

+                valueReq.selectedChannel = 'auto';

+            } else {

+                valueReq.selectedChannel = values.channel;

+                valueReq.abg_rate = values.rate;

+            }

+            if (config.WIFI_BANDWIDTH_SUPPORT) {

+                valueReq.wifi_11n_cap = values.bandwidth;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getDeviceInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+	    var wpask = config.PASSWORD_ENCODE ? "WPAPSK1_encode,m_WPAPSK1_encode," : "rnum_js,WPAPSK1_enaes,m_WPAPSK1_enaes,";

+            var valueReq = {

+                cmd: "wifi_coverage,m_ssid_enable,imei,network_type,sub_network_type,rssi,rscp,lte_rsrp,imsi,sim_imsi,cr_version,hw_version,MAX_Access_num," + wpask + "SSID1,AuthMode,m_SSID,m_AuthMode,m_HideSSID,m_MAX_Access_num,lan_ipaddr," + "mac_address,msisdn,LocalDomain,wan_ipaddr,static_wan_ipaddr,ipv6_wan_ipaddr,ipv6_pdp_type,pdp_type,ppp_status,sta_ip_status,rj45_state,ethwan_mode",

+                multi_data: 1

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    ssid: paramD.SSID1,

+                    authMode: paramD.AuthMode,

+                    passPhrase: config.PASSWORD_ENCODE ? Base64.decode(paramD.WPAPSK1_encode) : wifiDecode(paramD.rnum_js,paramD.imei,paramD.WPAPSK1_enaes),

+                    m_ssid: paramD.m_SSID,

+                    m_AuthMode: paramD.m_AuthMode,

+                    m_passPhrase: config.PASSWORD_ENCODE ? Base64.decode(paramD.m_WPAPSK1_encode) : wifiDecode(paramD.rnum_js,paramD.imei,paramD.m_WPAPSK1_enaes),

+                    m_max_access_num: paramD.m_MAX_Access_num,

+                    multi_ssid_enable: paramD.m_ssid_enable,

+                    ipAddress: paramD.lan_ipaddr,

+                    wanIpAddress: paramD.wan_ipaddr,

+                    staticWanIpAddress: paramD.static_wan_ipaddr,

+                    ipv6WanIpAddress: paramD.ipv6_wan_ipaddr,

+                    ipv6PdpType: paramD.ipv6_pdp_type,

+                    macAddress: paramD.mac_address,

+                    simSerialNumber: paramD.msisdn,

+                    lanDomain: paramD.LocalDomain,

+                    imei: paramD.imei,

+                    signal: convertSignal(paramD),

+                    imsi: paramD.imsi || paramD.sim_imsi,

+                    sw_version: paramD.cr_version,

+                    hw_version: paramD.hw_version,

+                    max_access_num: paramD.MAX_Access_num,

+                    wifiRange: paramD.wifi_coverage,

+                    pdpType: paramD.pdp_type,

+                    rj45ConnectStatus: (typeof paramD.rj45_state == 'undefined' || paramD.rj45_state == '') ? 'dead' : paramD.rj45_state,

+                    blc_wan_mode: informationAll.blc_wan_mode,

+                    connectStatus: paramD.ppp_status,

+                    wifiConStatus: paramD.sta_ip_status,

+                    ethwan_mode: paramD.ethwan_mode.toUpperCase()

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getDeviceInfoLow() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "imei,rnum_js",

+                multi_data: 1

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var kstr = paramD.rnum_js + paramD.imei + "FFFFFFFFFFFFFFFFFFFFFFFF";

+                var kstr_final;

+		var kiv_final;

+

+                kstr_final = kstr.substring(0, 24);

+		kiv_final = kstr.substring(0, 16);

+

+                return {

+                    skey: kstr_final,

+		    siv: kiv_final

+            	};

+            } else {

+				

+	        return {

+                    skey: "FFFFFFFFFFFFFFFFFFFFFFFF",

+		    siv: "FFFFFFFFFFFFFFFF"

+            	};

+            }

+        }

+    }

+    function getWifiRange() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "wifi_coverage";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.wifiRangeMode = paramD.wifi_coverage;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setWifiRange() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SET_WIFI_COVERAGE";

+            valueReq.wifi_coverage = values.wifiRangeMode;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getUpnpSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "upnpEnabled";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.upnpSetting = paramD.upnpEnabled == "1" ? "1" : "0";

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setUpnpSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "UPNP_SETTING";

+            valueReq.upnp_setting_option = values.upnpSetting;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getDmzSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "DMZEnable,DMZIPAddress";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.dmzSetting = paramD.DMZEnable == "1" ? "1" : "0";

+                result.ipAddress = paramD.DMZIPAddress;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setDmzSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "DMZ_SETTING";

+            valueReq.DMZEnabled = values.dmzSetting;

+            if (valueReq.DMZEnabled == '1') {

+                valueReq.DMZIPAddress = values.ipAddress;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getPortMap() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "PortMapEnable,PortMapRules_0,PortMapRules_1,PortMapRules_2,PortMapRules_3,PortMapRules_4,PortMapRules_5,PortMapRules_6,PortMapRules_7,PortMapRules_8,PortMapRules_9",

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.portMapEnable = paramD.PortMapEnable;

+                var rules = [];

+                if (paramD.PortMapRules_0 != "") {

+                    rules.push([0, paramD.PortMapRules_0]);

+                }

+                if (paramD.PortMapRules_1 != "") {

+                    rules.push([1, paramD.PortMapRules_1]);

+                }

+                if (paramD.PortMapRules_2 != "") {

+                    rules.push([2, paramD.PortMapRules_2]);

+                }

+                if (paramD.PortMapRules_3 != "") {

+                    rules.push([3, paramD.PortMapRules_3]);

+                }

+                if (paramD.PortMapRules_4 != "") {

+                    rules.push([4, paramD.PortMapRules_4]);

+                }

+                if (paramD.PortMapRules_5 != "") {

+                    rules.push([5, paramD.PortMapRules_5]);

+                }

+                if (paramD.PortMapRules_6 != "") {

+                    rules.push([6, paramD.PortMapRules_6]);

+                }

+                if (paramD.PortMapRules_7 != "") {

+                    rules.push([7, paramD.PortMapRules_7]);

+                }

+                if (paramD.PortMapRules_8 != "") {

+                    rules.push([8, paramD.PortMapRules_8]);

+                }

+                if (paramD.PortMapRules_9 != "") {

+                    rules.push([9, paramD.PortMapRules_9]);

+                }

+                result.portMapRules = parsePortMapRules(rules);

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+        function parsePortMapRules(paramD) {

+            var rules = [];

+            if (paramD && paramD.length > 0) {

+                for (var i = 0; i < paramD.length; i++) {

+                    var aRule = {};

+                    var elements = paramD[i][1].split(",");

+                    aRule.index = paramD[i][0];

+                    aRule.sourcePort = elements[1];

+                    aRule.destIpAddress = elements[0];

+                    aRule.destPort = elements[2];

+                    aRule.protocol = transProtocol(elements[3]);

+                    aRule.comment = elements[4];

+                    rules.push(aRule);

+                }

+            }

+            return rules;

+        }

+    }

+    function setPortMap() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "ADD_PORT_MAP";

+            valueReq.portMapEnabled = values.portMapEnable;

+            valueReq.fromPort = values.sourcePort;

+            valueReq.ip_address = values.destIpAddress;

+            valueReq.toPort = values.destPort;

+            valueReq.protocol = values.protocol;

+            valueReq.comment = values.comment;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function enablePortMap() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "ADD_PORT_MAP";

+            valueReq.portMapEnabled = values.portMapEnable;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function deleteMapRules() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "DEL_PORT_MAP";

+            valueReq.delete_id = values.indexs.join(';') + ";";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getTrafficAlertInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                cmd: "data_volume_limit_switch,data_volume_limit_unit,data_volume_limit_size,data_volume_alert_percent,monthly_tx_bytes,monthly_rx_bytes,monthly_time,traffic_alined_delta",

+                multi_data: 1

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var isData = paramD.data_volume_limit_unit == 'data';

+                var result = {

+                    dataLimitChecked: paramD.data_volume_limit_switch,

+                    dataLimitTypeChecked: isData ? '1' : '0',

+                    limitDataMonth: isData ? paramD.data_volume_limit_size : '0',

+                    alertDataReach: isData ? paramD.data_volume_alert_percent : '0',

+                    limitTimeMonth: isData ? '0' : paramD.data_volume_limit_size,

+                    alertTimeReach: isData ? '0' : paramD.data_volume_alert_percent,

+                    monthlySent: paramD.monthly_tx_bytes == '' ? 0 : paramD.monthly_tx_bytes,

+                    monthlyReceived: paramD.monthly_rx_bytes == '' ? 0 : paramD.monthly_rx_bytes,

+                    monthlyConnectedTime: paramD.monthly_time == '' ? 0 : paramD.monthly_time,

+                    traffic_alined_delta: paramD.traffic_alined_delta == '' ? 0 : paramD.traffic_alined_delta

+                };

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setTrafficAlertInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var isData = values.dataLimitTypeChecked == '1';

+            var valueReq = {

+                goformId: "DATA_LIMIT_SETTING",

+                data_volume_limit_switch: values.dataLimitChecked

+            };

+            if (values.dataLimitChecked == '1') {

+                valueReq.data_volume_limit_unit = isData ? 'data' : 'time';

+                valueReq.data_volume_limit_size = isData ? values.limitDataMonth : values.limitTimeMonth;

+                valueReq.data_volume_alert_percent = isData ? values.alertDataReach : values.alertTimeReach;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getUSSDResponse() {

+        var callback = arguments[1];

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            if (values.sendOrReply == "send") {

+                return {

+                    goformId: "USSD_PROCESS",

+                    USSD_operator: values.operator,

+                    USSD_send_number: values.strUSSDCommand,

+                    notCallback: true

+                };

+            } else if (values.sendOrReply == "reply") {

+                return {

+                    goformId: "USSD_PROCESS",

+                    USSD_operator: values.operator,

+                    USSD_reply_number: values.strUSSDCommand,

+                    notCallback: true

+                };

+            }

+        }

+        function deal(paramD) {

+            if (!paramD) {

+                callback(false, "ussd_fail");

+                return;

+            }

+            if (paramD.result == "success") {

+                callbackTemp = callback;

+                getResponse();

+            } else {

+                callback(false, "ussd_fail");

+            }

+        }

+    }

+    function getResponse() {

+        $.ajax({

+            url: "/reqproc/proc_get",

+            data: {

+                cmd: "ussd_write_flag"

+            },

+            cache: false,

+            async: true,

+            dataType: "json",

+            success: function (result) {

+                if (result.ussd_write_flag == "1") {

+                    callbackTemp(false, "ussd_no_service");

+                } else if (result.ussd_write_flag == "4" || result.ussd_write_flag == "unknown" || result.ussd_write_flag == "3") {

+                    callbackTemp(false, "ussd_timeout");

+                } else if (result.ussd_write_flag == "15") {

+                    setTimeout(getResponse, 1000);

+                } else if (result.ussd_write_flag == "10") {

+                    callbackTemp(false, "ussd_retry");

+                } else if (result.ussd_write_flag == "99") {

+                    callbackTemp(false, "ussd_unsupport");

+                } else if (result.ussd_write_flag == "41") {

+                    callbackTemp(false, "operation_not_supported");

+                } else if (result.ussd_write_flag == "2") {

+                    callbackTemp(false, "network_terminated");

+                } else if (result.ussd_write_flag == "16") {

+                    $.ajax({

+                        url: "/reqproc/proc_get",

+                        data: {

+                            cmd: "ussd_data_info"

+                        },

+                        dataType: "json",

+                        async: true,

+                        cache: false,

+                        success: function (paramD) {

+                            var content = {};

+                            content.data = paramD.ussd_data;

+                            content.ussd_action = paramD.ussd_action;

+                            content.ussd_dcs = paramD.ussd_dcs;

+                            callbackTemp(true, content);

+                        },

+                        error: function () {

+                            callbackTemp(false, "ussd_info_error");

+                        }

+                    });

+                } else {

+                    callbackTemp(false, "ussd_fail");

+                }

+            },

+            error: function () {

+                callbackTemp(false, "ussd_fail");

+            }

+        });

+    }

+    function USSDReplyCancel(callback) {

+        $.ajax({

+            url: "/reqproc/proc_post",

+            data: {

+                goformId: "USSD_PROCESS",

+                USSD_operator: "ussd_cancel"

+            },

+            cache: false,

+            dataType: "json",

+            success: function (paramD) {

+                if (paramD.result == "success") {

+                    getCancelResponse();

+                } else {

+                    callback(false);

+                }

+            }

+        });

+        function getCancelResponse() {

+            $.ajax({

+                url: "/reqproc/proc_get",

+                data: {

+                    cmd: "ussd_write_flag"

+                },

+                cache: false,

+                async: true,

+                dataType: "json",

+                success: function (result) {

+                    if (result.ussd_write_flag == "15") {

+                        setTimeout(getCancelResponse, 1000);

+                    } else if (result.ussd_write_flag == "13") {

+                        callback(true);

+                    } else {

+                        callback(false);

+                    }

+                },

+                error: function () {

+                    callback(false);

+                }

+            });

+        }

+    }

+    function unlockNetwork() {

+        var callback = arguments[1];

+        var checkPoint = 0;

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            return {

+                goformId: "UNLOCK_NETWORK",

+                notCallback: true,

+                unlock_network_code: values.unlock_network_code

+            };

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                addCallback(checkUnlockNetworkStatus);

+            } else {

+                callback({

+                    result: 'fail'

+                });

+            }

+        }

+        function checkUnlockNetworkStatus() {

+            if (checkPoint > 5) {

+                removeCallback(checkUnlockNetworkStatus);

+                callback({

+                    result: 'fail'

+                });

+            } else if (informationAll.simStatus != 'modem_imsi_waitnck') {

+                removeCallback(checkUnlockNetworkStatus);

+                callback({

+                    result: 'success'

+                });

+            }

+            checkPoint++;

+        }

+    }

+    function getNetworkUnlockTimes() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                cmd: "unlock_nck_time"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setUpdateInfoWarning() {

+        var callback = arguments[1];

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            return {

+                goformId: "SET_UPGRADE_NOTICE",

+                upgrade_notice_flag: values.upgrade_notice_flag,

+                notCallback: true

+            };

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                callback(true);

+            } else {

+                callback(false);

+            }

+        }

+    }

+    function getUpdateInfoWarning() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                cmd: "upgrade_notice_flag"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getAPStationBasic() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: 1,

+                cmd: "wifi_sta_connection,pswan_priority,wifiwan_priority,ethwan_priority"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    ap_station_enable: paramD.wifi_sta_connection,

+                    ap_station_mode: parseInt(paramD.wifiwan_priority, 10) > parseInt(paramD.pswan_priority, 10) ? "wifi_pref" : "dial_pref"

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setAPStationBasic() {

+        var tmp = arguments[0];

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            return {

+                goformId: "WIFI_STA_CONTROL",

+                wifi_sta_connection: values.ap_station_enable

+            };

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                informationAll.ap_station_enable = tmp.ap_station_enable == 1;

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function refreshAPStationStatus() {

+        return getAPStationBasic({}, function (paramD) {

+            informationAll.ap_station_enable = paramD.ap_station_enable == 1;

+            informationAll.ap_station_mode = paramD.ap_station_mode;

+        });

+    }

+    function getHotspotList() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var cmdStr = "wifi_profile_num,wifi_profile";

+            for (var i = 1; i < config.AP_STATION_LIST_LENGTH; i++) {

+                cmdStr = cmdStr + ",wifi_profile" + i;

+            }

+            return {

+                multi_data: 1,

+                cmd: cmdStr

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var wifiList = [];

+                for (var i = 0; i < config.AP_STATION_LIST_LENGTH; i++) {

+                    var wifiStr = "";

+                    if (i == 0) {

+                        wifiStr = paramD.wifi_profile;

+                    } else {

+                        wifiStr = paramD["wifi_profile" + i];

+                    }

+                    var wifiArray = wifiStr.split(";");

+                    for (var j = 0; j < wifiArray.length; j++) {

+                        var item = wifiArray[j].split(",");

+                        if (!item[0]) {

+                            break;

+                        }

+                        var wifiJson = {

+                            profileName: item[0],

+                            fromProvider: item[1],

+                            connectStatus: item[2],

+                            signal: item[3],

+                            ssid: item[4],

+                            authMode: item[5],

+                            encryptType: item[6],

+                            password: item[7] == "0" ? "" : item[7],

+                            keyID: item[8],

+                            mac: item[9]

+                        };

+                        wifiList.push(wifiJson);

+                    }

+                }

+                return {

+                    hotspotList: wifiList

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function searchHotspot() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            return {

+                goformId: "WLAN_SET_STA_REFRESH"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSearchHotspotList() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: 1,

+                cmd: "scan_finish,EX_APLIST,EX_APLIST1"

+            }

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.scan_finish == "0") {

+                    return {

+                        scan_finish: "0",

+                        hotspotList: []

+                    };

+                }

+                if (paramD.scan_finish == "2") {

+                    return {

+                        scan_finish: "2",

+                        hotspotList: []

+                    };

+                }

+                var wifiList = [];

+                for (var i = 0; i <= 1; i++) {

+                    var wifiStr;

+                    if (i == 0) {

+                        wifiStr = paramD.EX_APLIST;

+                    } else {

+                        wifiStr = paramD.EX_APLIST1;

+                    }

+                    var wifiArray = wifiStr.split(";");

+                    for (var j = 0; j < wifiArray.length; j++) {

+                        var item = wifiArray[j].split(",");

+                        if (!item[0]) {

+                            break;

+                        }

+                        var wifiJson = {

+                            fromProvider: item[0],

+                            connectStatus: item[1],

+                            ssid: item[2],

+                            signal: item[3],

+                            channel: item[4],

+                            authMode: item[5],

+                            encryptType: item[6],

+                            mac: item[7]

+                        }

+                        wifiList.push(wifiJson);

+                    }

+                }

+                return {

+                    scan_finish: "1",

+                    hotspotList: wifiList

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function creatHotspotString(hotspot) {

+        var tmp = [];

+        tmp.push(hotspot.profileName);

+        tmp.push(hotspot.fromProvider || "0");

+        tmp.push(hotspot.connectStatus || "0");

+        tmp.push(hotspot.signal);

+        tmp.push(hotspot.ssid);

+        tmp.push(hotspot.authMode);

+        tmp.push(hotspot.encryptType);

+        tmp.push(hotspot.password || "0");

+        tmp.push(hotspot.keyID);

+        tmp.push(hotspot.mac);

+        return tmp.join(",");

+    }

+    function saveHotspot() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var apList = values.apList;

+            var action = "modify";

+            if (values.profileName == "") {

+                action = "add";

+                var newName = (jQuery.fn.jquery + Math.random()).replace(/\D/g, "");

+                values.profileName = newName;

+                apList.push({

+                    profileName: newName,

+                    fromProvider: "0",

+                    connectStatus: "0",

+                    signal: values.signal,

+                    ssid: values.ssid,

+                    authMode: values.authMode,

+                    encryptType: values.encryptType,

+                    password: values.password || "0",

+                    keyID: values.keyID,

+                    mac: values.mac

+                });

+            }

+            var wifi = {

+                "profile0": []

+            };

+            for (var i = 1; i < config.AP_STATION_LIST_LENGTH; i++) {

+                wifi["profile" + i] = [];

+            }

+            var activeHotspotStr = "";

+            for (var i = 0; i < apList.length; i++) {

+                var hotspotStr = "";

+                if (values.profileName == apList[i].profileName) {

+                    hotspotStr = creatHotspotString(values);

+                    activeHotspotStr = hotspotStr;

+                } else {

+                    hotspotStr = creatHotspotString(apList[i]);

+                }

+                var index = parseInt(i % 10);

+                wifi["profile" + index].push(hotspotStr);

+            }

+            var profileParams = {

+                wifi_profile: wifi.profile0.join(";")

+            };

+            for (var i = 1; i < config.AP_STATION_LIST_LENGTH; i++) {

+                profileParams["wifi_profile" + i] = wifi["profile" + i].join(";");

+            }

+            var valueReq = $.extend({

+                goformId: "WIFI_SPOT_PROFILE_UPDATE",

+                wifi_profile_num: apList.length,

+                wifi_update_profile: activeHotspotStr,

+                action: action

+            }, profileParams);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function deleteHotspot() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var apList = values.apList;

+            var wifi = {

+                "profile0": []

+            };

+            for (var i = 1; i < config.AP_STATION_LIST_LENGTH; i++) {

+                wifi["profile" + i] = [];

+            }

+            var foundDelete = false;

+            var activeHotspotStr = "";

+            for (var i = 0; i < apList.length; i++) {

+                var hotspotStr = creatHotspotString(apList[i]);

+                if (apList[i].profileName == values.profileName) {

+                    foundDelete = true;

+                    activeHotspotStr = hotspotStr;

+                    continue;

+                }

+                var idIndex = i;

+                if (foundDelete) {

+                    idIndex = i - 1;

+                }

+                var index = parseInt(idIndex % 10);

+                wifi["profile" + index].push(hotspotStr);

+            }

+            var num = foundDelete ? apList.length - 1 : apList.length;

+            var profileParams = {

+                wifi_profile: wifi.profile0.join(";")

+            };

+            for (var i = 1; i < config.AP_STATION_LIST_LENGTH; i++) {

+                profileParams["wifi_profile" + i] = wifi["profile" + i].join(";");

+            }

+            var valueReq = $.extend({

+                goformId: "WIFI_SPOT_PROFILE_UPDATE",

+                wifi_profile_num: num,

+                wifi_update_profile: activeHotspotStr,

+                action: "delete"

+            }, profileParams);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function connectHotspot() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            return {

+                goformId: "WLAN_SET_STA_CON",

+                EX_SSID1: values.EX_SSID1,

+                EX_AuthMode: values.EX_AuthMode,

+                EX_EncrypType: values.EX_EncrypType,

+                EX_DefaultKeyID: values.EX_DefaultKeyID,

+                EX_WEPKEY: values.EX_WEPKEY,

+                EX_WPAPSK1: values.EX_WPAPSK1,

+                EX_wifi_profile: values.EX_wifi_profile,

+                EX_mac: values.EX_mac

+            };

+        }

+        function deal(paramD) {

+            if (paramD && (paramD.result == "success" || paramD.result == "processing")) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function disconnectHotspot() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            return {

+                goformId: "WLAN_SET_STA_DISCON"

+            };

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getOpMode() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: 1,

+                cmd: "blc_wan_mode,blc_wan_auto_mode,loginfo,ppp_status,rj45_state,ethwan_mode"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                if (paramD.blc_wan_mode == 'AUTO') {

+                    result.blc_wan_mode = paramD.blc_wan_auto_mode ? paramD.blc_wan_auto_mode : 'AUTO_PPP';

+                } else {

+                    result.blc_wan_mode = paramD.blc_wan_mode ? paramD.blc_wan_mode : 'PPP';

+                }

+                result.loginfo = paramD.loginfo;

+                result.ppp_status = paramD.ppp_status;

+                result.rj45_state = (typeof paramD.rj45_state == 'undefined' || paramD.rj45_state == '') ? 'dead' : paramD.rj45_state;

+                result.ethwan_mode = paramD.ethwan_mode.toUpperCase();

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getRj45PlugState() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                cmd: "rj45_plug"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.rj45_plug = paramD.rj45_plug == "" ? "wan_lan_off" : paramD.rj45_plug;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function checkOpMode(opmode, rj45state) {

+        if (config.RJ45_SUPPORT) {

+            if (rj45state == "dead" || rj45state == "") {

+                return 'PPP';

+            } else if (!opmode || opmode == "undefined") {

+                if (rj45state == "working") {

+                    return 'PPPOE';

+                } else {

+                    return 'PPP';

+                }

+            } else {

+                return opmode;

+            }

+        } else {

+            return 'PPP';

+        }

+    }

+    function SetOperationMode(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({

+                goformId: "OPERATION_MODE"

+            }, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getPppoeParams() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: 1,

+                cmd: "opms_wan_auto_mode,ethwan_mode,pppoe_username,pppoe_cc,ethwan_dialmode,ppp_status,static_wan_ipaddr,static_wan_netmask,static_wan_gateway,static_wan_primary_dns,static_wan_secondary_dns,rj45_state,lan_ipaddr,lan_netmask"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    opms_wan_auto_mode: paramD.opms_wan_auto_mode,

+                    ethwan_mode: paramD.ethwan_mode.toUpperCase(),

+                    pppoe_username: paramD.pppoe_username,

+                    pppoe_cc: paramD.pppoe_cc,

+                    ethwan_dialmode: paramD.ethwan_dialmode == "manual" ? "manual_dial" : "auto_dial",

+                    ppp_status: paramD.ppp_status,

+                    static_wan_ipaddr: paramD.static_wan_ipaddr,

+                    static_wan_netmask: paramD.static_wan_netmask,

+                    static_wan_gateway: paramD.static_wan_gateway,

+                    static_wan_primary_dns: paramD.static_wan_primary_dns,

+                    static_wan_secondary_dns: paramD.static_wan_secondary_dns,

+                    rj45_state: (typeof paramD.rj45_state == 'undefined' || paramD.rj45_state == '') ? 'dead' : paramD.rj45_state,

+                    lan_ipaddr: paramD.lan_ipaddr,

+                    lan_netmask: paramD.lan_netmask

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setPppoeDialMode(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({

+                notCallback: true

+            }, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD.result == "success") {

+                callback({

+                    result: true

+                });

+            } else {

+                callback({

+                    result: false

+                });

+            }

+        }

+    }

+    function getSntpParams(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: 1,

+                cmd: "sntp_year,sntp_month,sntp_day,sntp_hour,sntp_minute,sntp_second,sntp_time_set_mode,sntp_static_server0,sntp_static_server1,sntp_static_server2,sntp_server0,sntp_server1,sntp_server2,sntp_server3,sntp_server4,sntp_server5,sntp_server6,sntp_server7,sntp_server8,sntp_server9,sntp_other_server0,sntp_other_server1,sntp_other_server2,sntp_timezone,sntp_timezone_index,sntp_dst_enable,ppp_status,sntp_process_result,rj45_state"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var sntp_servers = getSntpServers(paramD);

+                return {

+                    sntp_year: paramD.sntp_year,

+                    sntp_month: paramD.sntp_month,

+                    sntp_day: paramD.sntp_day,

+                    sntp_hour: paramD.sntp_hour,

+                    sntp_minute: paramD.sntp_minute,

+                    sntp_second: paramD.sntp_second,

+                    sntp_time_set_mode: paramD.sntp_time_set_mode,

+                    sntp_servers: sntp_servers,

+                    sntp_server0: paramD.sntp_server0,

+                    sntp_server1: paramD.sntp_server1,

+                    sntp_server2: paramD.sntp_server2,

+                    sntp_static_server0: paramD.sntp_static_server0,

+                    sntp_static_server1: paramD.sntp_static_server1,

+                    sntp_static_server2: paramD.sntp_static_server2,

+                    sntp_other_server0: paramD.sntp_other_server0,

+                    sntp_other_server1: paramD.sntp_other_server1,

+                    sntp_other_server2: paramD.sntp_other_server2,

+                    sntp_timezone: paramD.sntp_timezone,

+                    sntp_timezone_index: paramD.sntp_timezone_index ? paramD.sntp_timezone_index : "0",

+                    sntp_dst_enable: paramD.sntp_dst_enable,

+                    ppp_status: paramD.ppp_status,

+                    blc_wan_mode: informationAll.blc_wan_mode,

+                    sntp_process_result: paramD.sntp_process_result,

+                    rj45_state: (typeof paramD.rj45_state == 'undefined' || paramD.rj45_state == '') ? 'dead' : paramD.rj45_state

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+        function getSntpServers(paramD) {

+            var serverArray = [];

+            for (var i = 0; i < 3; i++) {

+                var tmp = "sntp_static_server" + (i).toString();

+                if (paramD[tmp] != "") {

+                    var obj = {};

+                    obj.name = paramD[tmp];

+                    obj.value = paramD[tmp];

+                    serverArray.push(obj);

+                }

+            }

+            var otherArray = [{

+                    name: "Other",

+                    value: "Other"

+                }, {

+                    name: "NONE",

+                    value: ""

+                }

+            ];

+            for (var j = 0; j < 2; j++) {

+                serverArray.push(otherArray[j]);

+            }

+            return serverArray;

+        }

+    }

+    function setSNTPDate(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({}, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSntpSetting(values, callback) {

+        var valueReq = $.extend({}, values); {

+            $.post("reqproc/proc_post", valueReq, function (paramD) {

+                if (paramD && paramD.result == "success") {

+                    if (values.manualsettime == "auto") {

+                        setTimeout(checkSyncStatus, 2000);

+                        callback(paramD);

+                    } else {

+                        callback(true);

+                    }

+                } else if (paramD && paramD.result == "processing") {

+                    callback(paramD);

+                } else {

+                    callback(false);

+                }

+            }, "json");

+        }

+        function checkSyncStatus() {

+            $.ajax({

+                url: "reqproc/proc_get",

+                dataType: "json",

+                data: {

+                    cmd: "sntp_process_result"

+                },

+                cache: false,

+                async: false,

+                success: function (paramD) {

+                    if (paramD.sntp_process_result == "failure") {

+                        callback(false);

+                    } else if (paramD.sntp_process_result == "success") {

+                        callback(true);

+                    } else {

+                        setTimeout(checkSyncStatus, 2000);

+                    }

+                },

+                error: function () {

+                    callback(false);

+                }

+            });

+        }

+    }

+    function addUrlFilterRule(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({}, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getUrlFilterList() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                cmd: "websURLFilters"

+            };

+        }

+        function deal(paramD) {

+            var urlFilterRules = [];

+            if (paramD) {

+                if (paramD.websURLFilters.length == 0) {

+                    return {

+                        urlFilterRules: []

+                    };

+                } else {

+                    var tempArray = paramD.websURLFilters.split(";");

+                    for (var i = 0; i < tempArray.length; i++) {

+                        var aRule = {};

+                        aRule.index = i;

+                        aRule.url = tempArray[i];

+                        urlFilterRules.push(aRule);

+                    }

+                    return {

+                        urlFilterRules: urlFilterRules

+                    };

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function deleteSelectedRules(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({}, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getWdsInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: "1",

+                cmd: "wifi_wds_mode,wifi_wds_ssid,wifi_wds_AuthMode,wifi_wds_EncrypType,wifi_wds_WPAPSK1,wifi_cur_state "

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    currentMode: paramD.wifi_wds_mode,

+                    wdsSSID: paramD.wifi_wds_ssid,

+                    wdsAuthMode: paramD.wifi_wds_AuthMode,

+                    wdsEncrypType: paramD.wifi_wds_EncrypType,

+                    wdsWPAPSK1: paramD.wifi_wds_WPAPSK1,

+                    RadioOff: paramD.wifi_cur_state == "1" ? "1" : "0"

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setWDS(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({}, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSyslogInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: "1",

+                cmd: "syslog_mode,debug_level"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    currentMode: paramD.syslog_mode,

+                    debugLevel: paramD.debug_level

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setSysLog(values, callback) {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({}, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getMacFilterInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            return {

+                multi_data: "1",

+                cmd: "ACL_mode,wifi_mac_black_list,wifi_hostname_black_list,wifi_cur_state,user_ip_addr,client_mac_address,wifi_mac_white_list"

+            };

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    ACL_mode: paramD.ACL_mode,

+                    wifi_mac_black_list: paramD.wifi_mac_black_list,

+                    wifi_hostname_black_list: paramD.wifi_hostname_black_list,

+                    RadioOff: paramD.wifi_cur_state == "1" ? "1" : "0",

+                    user_ip_addr: paramD.user_ip_addr,

+                    client_mac_address: paramD.client_mac_address,

+                    wifi_mac_white_list: paramD.wifi_mac_white_list

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setMacFilter() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            var valueReq = $.extend({

+                goformId: 'WIFI_MAC_FILTER',

+            }, values);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getFastbootSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values) {

+            return {

+                cmd: "mgmt_quicken_power_on,need_hard_reboot,need_sim_pin",

+                multi_data: 1

+            };

+        }

+        function deal(paramD) {

+            return {

+                fastbootEnabled: paramD.mgmt_quicken_power_on == '1' ? '1' : '0',

+                need_hard_reboot: paramD.need_hard_reboot,

+                need_sim_pin: paramD.need_sim_pin == 'yes' ? 'yes' : 'no'

+            };

+        }

+    }

+    function setFastbootSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values) {

+            return {

+                goformId: "MGMT_CONTROL_POWER_ON_SPEED",

+                mgmt_quicken_power_on: values.fastbootEnabled

+            };

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function turnOffDevice() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "TURN_OFF_DEVICE";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function restart() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "REBOOT_DEVICE";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getNewVersionState() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "fota_new_version_state,fota_current_upgrade_state,fota_package_already_download";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var hasNewVersion = (paramD.fota_new_version_state == 'has_critical' || paramD.fota_new_version_state == 'has_optional' || paramD.fota_new_version_state == 'already_has_pkg');

+                paramD.hasNewVersion = hasNewVersion;

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getMandatory() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            if (config.UPGRADE_TYPE == "OTA") {

+                valueReq.cmd = "is_mandatory";

+            } else {

+                valueReq.cmd = "fota_new_version_state";

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (config.UPGRADE_TYPE == "OTA") {

+                    return {

+                        "is_mandatory": paramD.is_mandatory == "1"

+                    };

+                } else {

+                    return {

+                        "is_mandatory": paramD.fota_new_version_state == "has_critical"

+                    };

+                }

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getUpgradeResult() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "upgrade_result";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getCurrentUpgradeState() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "fota_current_upgrade_state";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                paramD.current_upgrade_state = paramD.fota_current_upgrade_state;

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getPackSizeInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "fota_pkg_total_size,fota_dl_pkg_size";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setUpgradeSelectOp() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "IF_UPGRADE";

+            valueReq.select_op = values.selectOp;

+            if (valueReq.select_op == 'check') {

+                valueReq.ota_manual_check_roam_state = 1;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getOTAUpdateSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "fota_updateMode,fota_updateIntervalDay,fota_allowRoamingUpdate";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return {

+                    updateMode: paramD.fota_updateMode,

+                    updateIntervalDay: paramD.fota_updateIntervalDay,

+                    allowRoamingUpdate: paramD.fota_allowRoamingUpdate

+                };

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setOTAUpdateSetting() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SetUpgAutoSetting";

+            valueReq.UpgMode = values.updateMode;

+            valueReq.UpgIntervalDay = values.updateIntervalDay;

+            valueReq.UpgRoamPermission = values.allowRoamingUpdate;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getOTAlastCheckTime() {

+        return getParams({

+            nv: ['dm_last_check_time']

+        }, arguments[1], arguments[2]);

+    }

+    function getSignalStrength() {

+        return getParams({

+            nv: ['network_type', 'sub_network_type', 'rssi', 'rscp', 'lte_rsrp']

+        }, arguments[1], arguments[2]);

+    }

+    function clearUpdateResult() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "RESULT_RESTORE";

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function childGroupList() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "childGroupList"

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && (paramD.childGroupList || paramD.devices)) {

+                return paramD;

+            } else {

+                return {

+                    devices: []

+                };

+            }

+        }

+    }

+    function addChildGroup() {

+        return stuffMake(arguments, config.currentUserInChildGroup == false ? {}

+             : {

+            errorType: 'no_auth'

+        }, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "ADD_DEVICE",

+                mac: values.macAddress

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function removeChildGroup() {

+        return stuffMake(arguments, config.currentUserInChildGroup == false ? {}

+             : {

+            errorType: 'no_auth'

+        }, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "DEL_DEVICE",

+                mac: values.mac

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function checkCurrentUserInChildGroup(devices) {

+        if (typeof config.currentUserInChildGroup == "undefined") {

+            var childGroupDevice = [];

+            if (typeof devices != "undefined") {

+                childGroupDevice = devices;

+            } else {

+                childGroupDevice = childGroupList({}).devices;

+            }

+            var userMacAddr = getUserMacAddr({}).get_user_mac_addr;

+            var found = _.find(childGroupDevice, function (item) {

+                return item.mac == userMacAddr;

+            });

+            config.currentUserInChildGroup = typeof found != 'undefined';

+            return {

+                result: typeof found != 'undefined'

+            };

+        }

+        return {

+            result: config.currentUserInChildGroup

+        };

+    }

+    function getUserMacAddr() {

+        return getParams({

+            nv: 'get_user_mac_addr'

+        }, arguments[1], arguments[2]);

+    }

+    function getHostNameList() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "hostNameList"

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && (paramD.hostNameList || paramD.devices)) {

+                return paramD;

+            } else {

+                return {

+                    devices: []

+                };

+            }

+        }

+    }

+    function editHostName() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "EDIT_HOSTNAME",

+                mac: values.mac,

+                hostname: values.hostname

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getSiteWhiteList() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "site_white_list"

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && (paramD.site_white_list || paramD.siteList)) {

+                return paramD;

+            } else {

+                return {

+                    siteList: []

+                };

+            }

+        }

+    }

+    function removeSiteWhite() {

+        return stuffMake(arguments, config.currentUserInChildGroup == false ? {}

+             : {

+            errorType: 'no_auth'

+        }, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "REMOVE_WHITE_SITE",

+                ids: values.ids.join(',')

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function saveSiteWhite() {

+        return stuffMake(arguments, config.currentUserInChildGroup == false ? {}

+             : {

+            errorType: 'no_auth'

+        }, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "ADD_WHITE_SITE",

+                name: values.name,

+                site: values.site

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getTimeLimited() {

+        var defaultResult = {

+            '0': [],

+            '1': [],

+            '2': [],

+            '3': [],

+            '4': [],

+            '5': [],

+            '6': []

+        };

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "time_limited"

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return parseTimeLimited(paramD);

+            } else {

+                return defaultResult;

+            }

+        }

+        function parseTimeLimited(paramD) {

+            if (paramD.time_limited == '') {

+                return {

+                    time_limited: []

+                };

+            }

+            var weeks = paramD.time_limited.split(';');

+            _.each(weeks, function (week) {

+                var weekTime = week.split('+');

+                if (weekTime.length == 2) {

+                    defaultResult[weekTime[0]] = weekTime[1].split(',');

+                }

+            });

+            return defaultResult;

+        }

+    }

+    function saveTimeLimited() {

+        return stuffMake(arguments, config.currentUserInChildGroup == false ? {}

+             : {

+            errorType: 'no_auth'

+        }, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "SAVE_TIME_LIMITED",

+                time_limited: values.time

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getTsw() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "openEnable,closeEnable,openTime,closeTime",

+                multi_data: '1'

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                if (paramD.openTime.indexOf(':') != -1) {

+                    var open = paramD.openTime.split(':');

+                    paramD.openH = leftInsert(open[0], 2, '0');

+                    paramD.openM = leftInsert(open[1], 2, '0');

+                } else {

+                    paramD.openH = '06';

+                    paramD.openM = '00';

+                }

+                if (paramD.closeTime.indexOf(':') != -1) {

+                    var close = paramD.closeTime.split(':');

+                    paramD.closeH = leftInsert(close[0], 2, '0');

+                    paramD.closeM = leftInsert(close[1], 2, '0');

+                } else {

+                    paramD.closeH = '22';

+                    paramD.closeM = '00';

+                }

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function saveTsw() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "SAVE_TSW",

+                openEnable: values.openEnable,

+                closeEnable: values.closeEnable

+            };

+            if (values.openEnable == '1') {

+                valueReq.openTime = values.openTime;

+                valueReq.closeTime = values.closeTime;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else if (paramD && paramD.result == 'failure') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function trafficCalibration() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {

+                goformId: "FLOW_CALIBRATION_MANUAL",

+                calibration_way: values.way,

+                time: values.way == 'time' ? values.value : 0,

+                data: values.way == 'data' ? values.value : 0

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == 'success') {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getParams() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            if (_.isArray(values.nv)) {

+                valueReq.cmd = values.nv.join(',');

+                valueReq.multi_data = 1;

+            } else {

+                valueReq.cmd = values.nv;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getRedirectData() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "vwim_mc_state,traffic_overrun,detect_new_version";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.vwim_mc_state = paramD.vwim_mc_state;

+                result.traffic_overrun = paramD.traffic_overrun;

+                result.detect_new_version = paramD.detect_new_version;

+                result.blc_wan_mode = informationAll.blc_wan_mode;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function clearRedirectFlag() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "CLEAR_REDIRECT_FLAG";

+            valueReq.flag_id = values.redirectFlags;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getV4Switch() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "lock_zone_enable,pin_interlock_and_V4_lock";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setV4Switch() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "PIN_LOCK_V4_ENCODE";

+            valueReq.pin_interlock_and_V4_lock = values.pin_interlock_and_V4_lock;

+            valueReq.TspLock_key_data = values.TspLock_key_data;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getCellId() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "cell_id_list,global_cell_id,network_type,sub_network_type,cell_not_correct";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setCellIdSwitch() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "LOCK_ZONE";

+            valueReq.lock_zone_enable = values.lock_zone_enable;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD && paramD.result == "success") {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getUpdateType() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {

+                cmd: "update_type"

+            };

+            return valueReq;

+        }

+        function deal(paramD) {

+            return {

+                update_type: paramD.update_type ? paramD.update_type : "mifi_fota"

+            }

+        }

+    }

+    function getSecurityInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.cmd = "AuthMode,passPhrase";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {};

+                result.AuthMode = paramD.AuthMode;

+                result.passPhrase = config.PASSWORD_ENCODE ? Base64.decode(paramD.passPhrase) : paramD.passPhrase;

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    //can delete

+    function setSecurityInfo() {

+        return stuffMake(arguments, {}, prepare, deal, null, true);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            valueReq.goformId = "SET_WIFI_SECURITY_INFO";

+            valueReq.AuthMode = values.AuthMode;

+            if (valueReq.AuthMode == "WPAPSKWPA2PSK") {

+                valueReq.passPhrase = config.PASSWORD_ENCODE ? Base64.encode(values.passPhrase) : values.passPhrase;

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }	

+    function setWifiBasic() {

+        stuffMakeAndCheckServerIsOnline(arguments, prepare, deal);

+        function prepare(values) {

+            var valueReq = {

+                goformId: "SET_WIFI_SSID1_SETTINGS",

+                ssid: values.SSID,

+                broadcastSsidEnabled: values.broadcast,

+                MAX_Access_num: values.station,

+                security_mode: values.AuthMode,

+                cipher: values.cipher,

+                NoForwarding: values.NoForwarding,

+                show_qrcode_flag: values.show_qrcode_flag

+            };

+            if (config.WIFI_WEP_SUPPORT) {

+                valueReq.wep_default_key = values.wep_default_key;

+                valueReq.wep_key_1 = values.wep_key_1;

+                valueReq.wep_key_2 = values.wep_key_2;

+                valueReq.wep_key_3 = values.wep_key_3;

+                valueReq.wep_key_4 = values.wep_key_4;

+                if (values.wep_default_key == '1') {

+                    valueReq.WEP2Select = values.WEP2Select;

+                } else if (values.wep_default_key == '2') {

+                    valueReq.WEP3Select = values.WEP3Select;

+                } else if (values.wep_default_key == '3') {

+                    valueReq.WEP4Select = values.WEP4Select;

+                } else {

+                    valueReq.WEP1Select = values.WEP1Select;

+                }

+            }

+            if (values.AuthMode == "WPAPSK" || values.AuthMode == "WPA2PSK" || values.AuthMode == "WPAPSKWPA2PSK" || values.AuthMode == "WPA3Personal" || values.AuthMode == "WPA2WPA3") {

+                valueReq.security_shared_mode = values.cipher;

+                valueReq.passphrase = config.PASSWORD_ENCODE ? Base64.encode(values.passPhrase) : values.passPhrase;

+            } else if (values.AuthMode == "SHARED") {

+                valueReq.security_shared_mode = "WEP";

+                valueReq.security_mode = "SHARED";

+            } else {

+                if (values.encryptType == "WEP") {

+                    valueReq.security_shared_mode = "WEP";

+                    valueReq.security_mode = "OPEN";

+                } else {

+                    valueReq.security_shared_mode = "NONE";

+                }

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function setWifiBasic4SSID2() {

+        stuffMakeAndCheckServerIsOnline(arguments, prepare, deal);

+        function prepare(values) {

+            var valueReq = {

+                goformId: "SET_WIFI_SSID2_SETTINGS",

+                m_SSID: values.m_SSID,

+                m_HideSSID: values.m_broadcast,

+                m_MAX_Access_num: values.m_station,

+                m_AuthMode: values.m_AuthMode,

+                cipher: values.m_cipher,

+                m_NoForwarding: values.m_NoForwarding,

+                m_show_qrcode_flag: values.m_show_qrcode_flag

+            };

+            if (config.WIFI_WEP_SUPPORT) {

+                valueReq.m_DefaultKeyID = values.m_wep_default_key;

+                valueReq.m_Key1Str1 = values.m_wep_key_1;

+                valueReq.m_Key2Str1 = values.m_wep_key_2;

+                valueReq.m_Key3Str1 = values.m_wep_key_3;

+                valueReq.m_Key4Str1 = values.m_wep_key_4;

+                if (values.m_wep_default_key == '1') {

+                    valueReq.m_Key2Type = values.m_WEP2Select;

+                } else if (values.m_wep_default_key == '2') {

+                    valueReq.m_Key3Type = values.m_WEP3Select;

+                } else if (values.m_wep_default_key == '3') {

+                    valueReq.m_Key4Type = values.m_WEP4Select;

+                } else {

+                    valueReq.m_Key1Type = values.m_WEP1Select;

+                }

+            }

+            if (values.m_AuthMode == "WPAPSK" || values.m_AuthMode == "WPA2PSK" || values.m_AuthMode == "WPAPSKWPA2PSK" || values.m_AuthMode == "WPA3Personal" || values.m_AuthMode == "WPA2WPA3") {

+                valueReq.m_EncrypType = values.m_cipher;

+                valueReq.m_WPAPSK1 = config.PASSWORD_ENCODE ? Base64.encode(values.m_passPhrase) : values.m_passPhrase;

+            } else if (values.m_AuthMode == "SHARED") {

+                valueReq.m_EncrypType = "WEP";

+                valueReq.m_security_mode = "SHARED";

+            } else {

+                if (values.m_encryptType == "WEP") {

+                    valueReq.m_EncrypType = "WEP";

+                    valueReq.m_security_mode = "OPEN";

+                } else {

+                    valueReq.m_EncrypType = "NONE";

+                }

+            }

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function getWifiBasic() {

+        return stuffMake(arguments, {}, prepare, deal, null, false);

+        function prepare(values, isPost) {

+            var valueReq = {};

+            var wpapsk = config.PASSWORD_ENCODE ? "WPAPSK1_encode,m_WPAPSK1_encode," : "imei,rnum_js,WPAPSK1_enaes,m_WPAPSK1_enaes,";

+            valueReq.cmd = "m_ssid_enable,wifi_cur_state,NoForwarding,m_NoForwarding," + wpapsk + "MAX_Station_num," + "SSID1,AuthMode,HideSSID,MAX_Access_num,show_qrcode_flag,EncrypType,Key1Str1,Key2Str1,Key3Str1,Key4Str1,DefaultKeyID," + "m_SSID,m_AuthMode,m_HideSSID,m_MAX_Access_num,m_EncrypType,m_show_qrcode_flag,m_DefaultKeyID,m_Key1Str1,m_Key2Str1,m_Key3Str1,m_Key4Str1,rotationFlag,wifi_sta_connection";

+            valueReq.multi_data = 1;

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                var result = {

+                    wifi_enable: paramD.wifi_cur_state == "1" ? "1" : "0",

+                    multi_ssid_enable: paramD.m_ssid_enable,

+                    MAX_Station_num: $.isNumeric(paramD.MAX_Station_num) ? paramD.MAX_Station_num : config.MAX_STATION_NUMBER,

+                    AuthMode: paramD.AuthMode,

+                    SSID: paramD.SSID1,

+                    broadcast: paramD.HideSSID,

+                    apIsolation: paramD.NoForwarding,

+                    passPhrase: config.PASSWORD_ENCODE ? Base64.decode(paramD.WPAPSK1_encode) : wifiDecode(paramD.rnum_js,paramD.imei,paramD.WPAPSK1_enaes),

+                    MAX_Access_num: paramD.MAX_Access_num,

+                    cipher: paramD.EncrypType == "TKIP" ? "0" : paramD.EncrypType == "AES" ? 1 : 2,

+                    encryptType: paramD.EncrypType,

+                    show_qrcode_flag: paramD.show_qrcode_flag == "1" ? true : false,

+                    keyID: paramD.DefaultKeyID,

+                    Key1Str1: paramD.Key1Str1,

+                    Key2Str1: paramD.Key2Str1,

+                    Key3Str1: paramD.Key3Str1,

+                    Key4Str1: paramD.Key4Str1,

+                    m_SSID: paramD.m_SSID,

+                    m_broadcast: paramD.m_HideSSID,

+                    m_apIsolation: paramD.m_NoForwarding,

+                    m_MAX_Access_num: paramD.m_MAX_Access_num,

+                    m_AuthMode: paramD.m_AuthMode,

+                    m_passPhrase: config.PASSWORD_ENCODE ? Base64.decode(paramD.m_WPAPSK1_encode) : wifiDecode(paramD.rnum_js,paramD.imei,paramD.m_WPAPSK1_enaes),

+                    m_cipher: paramD.m_EncrypType == "TKIP" ? "0" : paramD.m_EncrypType == "AES" ? 1 : 2,

+                    m_show_qrcode_flag: paramD.m_show_qrcode_flag == "1" ? true : false,

+                    m_encryptType: paramD.m_EncrypType,

+                    m_keyID: paramD.m_DefaultKeyID,

+                    m_Key1Str1: paramD.m_Key1Str1,

+                    m_Key2Str1: paramD.m_Key2Str1,

+                    m_Key3Str1: paramD.m_Key3Str1,

+                    m_Key4Str1: paramD.m_Key4Str1,

+                    rotationFlag: paramD.rotationFlag,

+                    ap_station_enable: paramD.wifi_sta_connection

+                };

+                return result;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }	

+    function setWifiBasicMultiSSIDSwitch() {

+        stuffMakeAndCheckServerIsOnline(arguments, prepare, deal);

+        function prepare(values) {

+            var paraTemp = values;

+            if (values.wifiEnabled == '0') {

+                paraTemp = {

+                    wifiEnabled: values.wifiEnabled

+                }

+            }

+            var valueReq = $.extend({

+                goformId: "SET_WIFI_INFO",

+            }, paraTemp);

+            return valueReq;

+        }

+        function deal(paramD) {

+            if (paramD) {

+                return paramD;

+            } else {

+                return errUnknownObj;

+            }

+        }

+    }

+    function stuffMake(array, result, prepare, dealMethod, errorObject, isPost) {

+        var values = array[0],

+        callback = array[1],

+        errorCallback = array[2];

+        var objectToReturn;

+        if (result && typeof result.errorType === 'string') {

+            objectToReturn = $.extend(errUnknownObj, result);

+            if (!callback) {

+                return objectToReturn;

+            }

+            doCallback(objectToReturn, callback, errorCallback);

+        } else {

+            objectToReturn = $.extend({}, result);

+            var valueReq;

+            if (prepare) {

+                valueReq = prepare(values, isPost);

+            } else {

+                valueReq = values;

+            }

+            if (!callback) {

+                if (valueReq && (valueReq.cmd || valueReq.goformId)) {

+                    var r = reqSync(valueReq, isPost);

+                    if (dealMethod) {

+                        objectToReturn = $.extend({}, dealMethod(r));

+                    } else {

+                        objectToReturn = r;

+                    }

+                }

+                return objectToReturn;

+            } else {

+                if (valueReq && (valueReq.cmd || valueReq.goformId)) {

+                    reqAsync(valueReq, function (paramD) {

+                        if (dealMethod) {

+                            objectToReturn = $.extend({}, dealMethod(paramD));

+                        } else {

+                            objectToReturn = $.extend({}, paramD);

+                        }

+                        if (!valueReq.notCallback) {

+                            doCallback(objectToReturn, callback, errorCallback);

+                        }

+                    }, function () {

+                        if (errorObject) {

+                            objectToReturn = $.extend(errUnknownObj, errorObject);

+                        } else {

+                            objectToReturn = $.extend(errUnknownObj, {

+                                errorType: 'Unknown'

+                            });

+                        }

+                        doCallback(objectToReturn, callback, errorCallback);

+                    }, isPost);

+                } else {

+                    doCallback(objectToReturn, callback, errorCallback);

+                }

+            }

+        }

+        function doCallback(resultToReturn, callback, errorCallback) {

+            errorCallback = errorCallback ? errorCallback : callback;

+            if (isErrorObject(resultToReturn)) {

+                switch (resultToReturn.errorType) {

+                case 'cellularNetworkError':

+                case 'deviceError':

+                case 'wifiConnectionError':

+                    window.receivedNonSpecificError(resultToReturn);

+                    break;

+                default:

+                    errorCallback(resultToReturn);

+                }

+            } else {

+                callback(resultToReturn);

+            }

+        }

+    }	

+    function reqSync(values, isPost) {

+        return reqAJAX(values, null, null, false, isPost);

+    }

+    function reqAsync(values, successCallback, errorCallback, isPost) {

+        reqAJAX(values, successCallback, errorCallback, true, isPost);

+    }

+    function getString(values){

+    var regexp = /^[A-z0-9]+$/;

+    var matches = values.match(regexp);

+    if (matches == null){

+        return "error";

+    } else {

+        return values;

+    }

+    }

+    function reqAJAX(values, successCallback, errorCallback, async, isPost) {

+        var result = null;

+        $.ajax({

+            type: !!isPost ? "POST" : "GET",

+            url: isPost ? "/reqproc/proc_post" : values.cmd ? "/reqproc/proc_get" : "/reqproc/proc_post",

+            data: values,

+            dataType: "json",

+            async: !!async,

+            cache: false,

+            error: function (paramD) {

+                if (async) {

+                    errorCallback(paramD);

+                } else if (paramD.status == 200) {

+                    result = jQuery.parseJSON('(' + getString(paramD.responseText) + ')');

+                }

+            },

+            success: function (paramD) {

+                if (async) {

+                    successCallback(paramD);

+                } else {

+                    result = paramD;

+                }

+            }

+        });

+        if (!async) {

+            return result;

+        }

+    }

+	    var informationAll = {

+        networkType: "",

+        signalImg: "0",

+        spn_b1_flag: "1",

+        spn_name_data: "",

+        spn_b2_flag: "1",

+        networkOperator: "China Mobile",

+        connectStatus: "ppp_disconnected",

+        rj45ConnectStatus: "rj45_dead",

+        attachedDevices: [],

+        ssid1AttachedNum: 0,

+        ssid2AttachedNum: 0,

+        data_counter: {

+            uploadRate: 0,

+            downloadRate: 0,

+            totalSent: 0,

+            totalReceived: 0,

+            totalConnectedTime: 0,

+            currentSent: 0,

+            currentReceived: 0,

+            currentConnectedTime: 0,

+            monthlySent: 0,

+            monthlyReceived: 0,

+            monthlyConnectedTime: 0,

+            month: ''

+        },

+        newSmsReceived: false,

+        smsReportReceived: false,

+        smsUnreadCount: "0",

+        isLoggedIn: undefined,

+        limitVolumeEnable: false,

+        limitVolumeType: '1',

+        limitVolumePercent: "100",

+        limitVolumeSize: "0",

+        allowRoamingUpdate: "0",

+        blc_wan_mode: "",

+        ap_station_enable: undefined,

+        ap_station_mode: undefined,

+        dialMode: '',

+        ethWanMode: 'AUTO',

+        fota_user_selector: '',

+        defaultWanName: ""

+    };

+    var errUnknownObj = {

+        errorType: 'UnknownError',

+        errorId: '123',

+        errorText: 'UnknownError'

+    };

+    var updateTimerFlag = true;	

+    return {

+        clearRedirectFlag: clearRedirectFlag,

+        connect: connect,

+        disconnect: disconnect,

+        getSIMPhoneBookCapacity: getSIMPhoneBookCapacity,

+        getDevicePhoneBookCapacity: getDevicePhoneBookCapacity,

+		getDevicePhoneBooks: getDevicePhoneBooks,

+        getSIMPhoneBooks: getSIMPhoneBooks,

+        getPhoneBooks: getPhoneBooks,

+        getPhoneBookReady: getPhoneBookReady,

+        getPhoneBooksByGroup: getPhoneBooksByGroup,

+        deletePhoneBooks: deletePhoneBooks,

+        deleteAllPhoneBooks: deleteAllPhoneBooks,

+        deleteAllPhoneBooksByGroup: deleteAllPhoneBooksByGroup,		

+        savePhoneBook: savePhoneBook,

+        deleteAllMessages: deleteAllMessages,

+        deleteMessage: deleteMessage,

+        setSmsRead: setSmsRead,

+        sendSMS: sendSMS,

+        saveSMS: saveSMS,

+        getSMSReady: getSMSReady,

+        getSMSMessages: getSMSMessages,

+        getSMSDeliveryReport: getSMSDeliveryReport,

+        getSmsCapability: getSmsCapability,

+        resetNewSmsReceivedVar: resetNewSmsReceivedVar,

+        resetSmsReportReceivedVar: resetSmsReportReceivedVar,

+        getSmsSetting: getSmsSetting,

+        setSmsSetting: setSmsSetting,

+		getAttachedCableDevices: getAttachedCableDevices,

+		getCurrentlyAttachedDevicesInfo: getCurrentlyAttachedDevicesInfo,

+		getConnectionInfo: getConnectionInfo,

+        getRedirectData: getRedirectData,

+        getLanguage: getLanguage,

+        setLanguage: setLanguage,

+        getNetSelectInfo: getNetSelectInfo,		

+        getSecurityInfo: getSecurityInfo,

+        setSecurityInfo: setSecurityInfo,

+        getStatusInfo: getStatusInfo,

+        getConnectionMode: getConnectionMode,

+        setConnectionMode: setConnectionMode,

+        getWifiBasic: getWifiBasic,

+        setWifiBasic: setWifiBasic,

+        setWifiBasic4SSID2: setWifiBasic4SSID2,

+        setWifiBasicMultiSSIDSwitch: setWifiBasicMultiSSIDSwitch, 

+        getWpsInfo: getWpsInfo,

+        openWps: openWps,

+        getSleepMode: getSleepMode,

+        setSleepMode: setSleepMode,

+        getWifiAdvance: getWifiAdvance,

+        setWifiAdvance: setWifiAdvance,

+        getWifiRange: getWifiRange,

+        setWifiRange: setWifiRange,

+		

+        getLoginStatus: getLoginStatus,

+        getLoginData: getLoginData,

+        login: login,

+        logout: logout, 

+        changeManageInfo: changeManageInfo,

+        getPinData: getPinData,

+        enablePin: enablePin,

+        disablePin: disablePin,

+        changePin: changePin,

+		enterPIN: enterPIN,

+        enterPUK: enterPUK,

+        getLanInfo: getLanInfo,

+        setLanInfo: setLanInfo,       

+        getApnSettings: getApnSettings,

+        deleteApn: deleteApn,

+        setDefaultApn: setDefaultApn,

+        addOrEditApn: addOrEditApn,

+        getQuickSettingInfo: getQuickSettingInfo,

+        setQuickSetting4IPv6: setQuickSetting4IPv6,

+        scanForNetwork: scanForNetwork,

+        setBearerPreference: setBearerPreference,

+        editHostName: editHostName,

+        getSiteWhiteList: getSiteWhiteList,

+        removeSiteWhite: removeSiteWhite,

+        saveSiteWhite: saveSiteWhite,

+        setNetwork: setNetwork,

+        getUpnpSetting: getUpnpSetting,

+        setUpnpSetting: setUpnpSetting,

+        getDmzSetting: getDmzSetting,

+        setDmzSetting: setDmzSetting,

+        getDeviceInfo: getDeviceInfo,

+        getDeviceInfoLow: getDeviceInfoLow,

+        getPortForward: getPortForward,

+        setPortForward: setPortForward,

+        getPortFilter: getPortFilter,

+        setPortFilterBasic: setPortFilterBasic,

+        setPortFilter: setPortFilter,

+        deleteFilterRules: deleteFilterRules,

+        getPortMap: getPortMap,

+        setPortMap: setPortMap,

+        enablePortMap: enablePortMap,

+        deleteMapRules: deleteMapRules,

+        getTrafficAlertInfo: getTrafficAlertInfo,

+        setTrafficAlertInfo: setTrafficAlertInfo,

+        getCurrentUpgradeState: getCurrentUpgradeState,

+        setUpgradeSelectOp: setUpgradeSelectOp,

+        addTimerThings: addTimerSomething,

+        removeTimerThings: removeTimerSomething,

+        getPackSizeInfo: getPackSizeInfo,

+        getMandatory: getMandatory,

+        getOTAUpdateSetting: getOTAUpdateSetting,

+        setOTAUpdateSetting: setOTAUpdateSetting,

+        getSignalStrength: getSignalStrength,

+        getOTAlastCheckTime: getOTAlastCheckTime,

+        clearUpdateResult: clearUpdateResult,

+        refreshAPStationStatus: refreshAPStationStatus,

+        getSntpParams: getSntpParams,

+        setSntpSetting: setSntpSetting,

+        setSNTPDate: setSNTPDate,

+        restoreFactorySettings: restoreFactorySettings,

+        checkRestoreStatus: checkRestoreStatus,

+        getSysSecurity: getSysSecurity,

+        setSysSecurity: setSysSecurity,

+        deleteForwardRules: deleteForwardRules,

+        enableVirtualServer: enableVirtualServer,

+        getSDConfiguration: getSDConfiguration,

+        setSdCardMode: setSdCardMode,

+        checkFileExists: checkFileExists,

+        getFileList: getFileList,

+        fileRename: fileRename,

+        getSdMemorySizes: getSdMemorySizes,

+        deleteFilesAndFolders: deleteFilesAndFolders,

+        createFolder: createFolder,

+        setSdCardSharing: setSdCardSharing,

+        setUpdateInfoWarning: setUpdateInfoWarning,

+        getUpdateInfoWarning: getUpdateInfoWarning,

+        getAPStationBasic: getAPStationBasic,

+        setAPStationBasic: setAPStationBasic,

+        getWdsInfo: getWdsInfo,

+        setWDS: setWDS,

+        addUrlFilterRule: addUrlFilterRule,

+        getUrlFilterList: getUrlFilterList,

+        deleteSelectedRules: deleteSelectedRules,

+        getMacFilterInfo: getMacFilterInfo,

+        setMacFilter: setMacFilter,

+        getFastbootSetting: getFastbootSetting,

+        setFastbootSetting: setFastbootSetting,

+        turnOffDevice: turnOffDevice,

+        restart: restart,

+        updateTimerFlag: updateTimerFlag,

+        childGroupList: childGroupList,

+        addChildGroup: addChildGroup,

+        removeChildGroup: removeChildGroup,

+        checkCurrentUserInChildGroup: checkCurrentUserInChildGroup,

+        getTimeLimited: getTimeLimited,

+        saveTimeLimited: saveTimeLimited,

+        getHostNameList: getHostNameList,

+        getHotspotList: getHotspotList,

+        searchHotspot: searchHotspot,

+        getSearchHotspotList: getSearchHotspotList,

+        saveHotspot: saveHotspot,

+        deleteHotspot: deleteHotspot,

+        connectHotspot: connectHotspot,

+        disconnectHotspot: disconnectHotspot,

+        getOpMode: getOpMode,

+        getRj45PlugState: getRj45PlugState,

+        SetOperationMode: SetOperationMode,

+        getPppoeParams: getPppoeParams,

+        setPppoeDialMode: setPppoeDialMode,

+        getTsw: getTsw,

+        saveTsw: saveTsw,

+        trafficCalibration: trafficCalibration,

+        getParams: getParams,

+        getNewVersionState: getNewVersionState,

+        getUpgradeResult: getUpgradeResult,

+        getV4Switch: getV4Switch,

+        setV4Switch: setV4Switch,

+        getCellId: getCellId,

+        setCellIdSwitch: setCellIdSwitch,

+        getDdnsParams: getDdnsParams,

+        setDDNSForward: setDDNSForward,

+        getUpdateType: getUpdateType,

+        getCurretnMAC: getCurretnMAC,

+        getUSSDResponse: getUSSDResponse,

+        USSDReplyCancel: USSDReplyCancel,

+        getNetworkUnlockTimes: getNetworkUnlockTimes,

+        unlockNetwork: unlockNetwork,	

+        getSyslogInfo: getSyslogInfo,

+        setSysLog: setSysLog,		

+    };

+});

+

+ // RouterÉèÖÃ

+

+define("adm_lan","jquery knockout set service".split(" "),

+

+    function ($, ko, config, service) {

+	

+    var originfrmLan = "";

+	

+    // »ñȡ·ÓÉÉèÖÃÏà¹ØÐÅÏ¢

+    function getLanInfo() {

+        return service.getLanInfo();

+    }	

+	

+    function hex(val) {

+        var h = (val - 0).toString(16);

+        if (h.length == 1)

+            h = '0' + h;

+        return h.toUpperCase();

+    }	

+	

+    function LanViewModel() {

+        var target = this;

+

+        var info = getLanInfo();

+

+        target.dhcpStart = ko.observable(info.dhcpStart);

+        target.dhcpEnd   = ko.observable(info.dhcpEnd);

+        target.dhcpLease = ko.observable(info.dhcpLease);		

+		

+        target.ipAddress  = ko.observable(info.ipAddress);

+        target.subnetMask = ko.observable(info.subnetMask);

+        target.dhcpServer = ko.observable(info.dhcpServer);

+

+		target.macAddress = ko.observable(info.macAddress);

+        target.showMacAddress = ko.observable(config.SHOW_MAC_ADDRESS);

+		

+        target.hasWifi        = ko.observable(config.HAS_WIFI);

+        target.hasUssd        = config.HAS_USSD;

+        target.hasDdns        = config.DDNS_SUPPORT;

+	

+        target.hasUpdateCheck = config.HAS_UPDATE_CHECK;

+				

+        target.clear = function () {

+            clearTimer();

+            init();

+            clearValidateMsg();

+        };		

+		

+        target.refreshStatus = function () {

+            var connInfo = service.getConnectionInfo();

+            if (connInfo.connectStatus == 'ppp_disconnected') {

+                $('input', '#frmLan').each(function () {

+                    $(this).attr("disabled", false);

+                });

+            } else {

+                $('input', '#frmLan').each(function () {

+                    $(this).attr("disabled", true);

+                });

+

+                clearValidateMsg();

+            }

+        };

+

+        // ÉèÖÃÏìÓ¦º¯Êý£¬½øÐÐÉèÖñ£´æ

+        target.saveAct = function () {

+            showLoading();

+            var params = {

+                ipAddress:  target.ipAddress(),

+                subnetMask: target.subnetMask(),

+                dhcpServer: target.dhcpServer(),

+                dhcpStart:  target.dhcpStart(),

+                dhcpEnd:    target.dhcpEnd(),

+                dhcpLease:  target.dhcpLease()

+            };

+			

+            service.setLanInfo(params, function (result) {

+                if (result.result == "success") {

+                    successOverlay();

+                    target.clear();

+                } else {

+                    errorOverlay();

+                }

+            });

+        };		

+

+        // ÉèÖÃÏìÓ¦º¯Êý£¬½øÐÐÉèÖñ£´æ

+        target.save = function () {

+            var frmLanObj = $('#frmLan').serialize();

+            if (frmLanObj == originfrmLan) {

+                showAlert("setting_no_change");

+                return false;

+            }

+            if (config.RJ45_SUPPORT) {

+                var pppObj = service.getPppoeParams();

+                if (sf_isValidate_StaticIP(pppObj.static_wan_ipaddr, target.ipAddress(), target.subnetMask())) {

+                    showAlert("lan_tip_staticip_notsame");

+                    return false;

+                }

+            }

+            showConfirm("lan_confirm_reopen", function () {

+                target.saveAct();

+            });

+        };

+

+            target.refreshStatus();

+            // dhcpServerÇл»ÏìÓ¦º¯Êý

+            target.dhcpServerHandler = function () {

+                $("#txtIpAddress").parent().find(".error").hide();

+                $("#txtIpAddress").show();

+                return true;

+            };

+        addTimeout(function () {

+            originfrmLan = $('#frmLan').serialize();

+        }, 500);

+    }

+

+			

+    function sf_opAnd4Byte(i_v1, i_v2) {

+        var index;

+        var var1 = [];

+        var var2 = [];

+        var result='0x';

+

+        for (index=2,index_tmp=0; index<10; index+=2,index_tmp++) {

+            var1[index_tmp]='0x'+i_v1.substring(index,index+2);

+            var2[index_tmp]='0x'+i_v2.substring(index,index+2);

+        }

+

+        for (index=0; index<4; index++) {

+            result = result + hex(var1[index]&var2[index]);

+        }

+

+        return result - 0;

+    }

+

+    // ½çÃæÏà¹Ø±íµ¥Ð£Ñ鹿Ôò	

+    $.validator.addMethod("dhcp_check", function (i_value, i_element, i_parameter) {

+        var dhcpIp =  i_parameter == "start" ?  $('#txtDhcpIpPoolStart').val() : $('#txtDhcpIpPoolEnd').val();

+        var result = sf_isValidate_Gateway($('#txtIpAddress').val(), $('#txtSubnetMask').val(), dhcpIp);

+        return this.optional(i_element) || result;

+    });

+

+    $.validator.addMethod("dhcpCompare", function (i_value, i_element, i_parameter) {

+        var result;

+        if(i_parameter == "#txtDhcpIpPoolStart") {

+            result = sf_isValidate_StartEndIp($('#txtIpAddress').val(), $('#txtSubnetMask').val(), $(i_parameter).val(), i_value);

+        }

+        else {

+            result = sf_isValidate_StartEndIp($('#txtIpAddress').val(), $('#txtSubnetMask').val(), i_value, $(i_parameter).val());

+        }

+        return result != 1;

+    });

+

+    $.validator.addMethod("ipRange", function (i_value, i_element, i_parameter) {

+        var DHCP_flag = false;

+        if($('#dhcpEnable').is(':checked')){

+            DHCP_flag = true;

+        }

+        var result = sf_isValidate_StartEndIp(i_value, $('#txtSubnetMask').val(), $('#txtDhcpIpPoolStart').val(), $('#txtDhcpIpPoolEnd').val(), DHCP_flag);

+        return result != 2;

+    });

+	

+    $.validator.addMethod("subnetmask_check", function (i_value, i_element, i_parameter) {

+        var result = sf_isValidate_Netmask(i_value);

+        return this.optional(i_element) || result;

+    });	

+	

+

+    // ¾²Ì¬ÓÐЧIPУÑ麯Êý

+    function sf_isValidate_StaticIP(i_ip, i_lanIp, i_lanMask){

+            if(!i_ip || !i_lanIp || !i_lanMask){//¸÷²ÎÊý²»ÄÜΪ¿Õ

+                return false;

+            }

+		

+		       //ÓëÄÚÍøIPÏàµÈ

+            if (i_ip == i_lanIp) { 

+                return true;

+            }

+		

+            var res1 = [];

+            var res2 = [];

+		

+            var mask_array = [];

+		

+            ip_array = i_ip.split(".");

+            lanIp_array = i_lanIp.split(".");

+            mask_array  = i_lanMask.split(".");

+            for(var index = 0; index < ip_array.length; index += 1){

+                res1.push(parseInt(mask_array[index]) & parseInt(ip_array[index]));

+                res2.push(parseInt(mask_array[index]) & parseInt(lanIp_array[index]));

+            }

+            if(res2.join(".") != res1.join(".")){//ÔÚ²»Í¬Íø¶Î

+                return false;

+            }else{//ÔÚÍ¬Ò»Íø¶Î

+                return true;

+            }

+        }

+	

+

+    function sf_isValidate_NetmaskIP(i_ip) {

+        return (i_ip == 255

+      		 || i_ip == 254 

+			 || i_ip == 252 

+			 || i_ip == 248

+             || i_ip == 240 

+			 || i_ip == 224 

+			 || i_ip == 192 

+			 || i_ip == 128

+			 || i_ip == 0);

+    }

+	

+	function sf_convertIpToString(i_ip)

+	{

+        var s_i1 = i_ip.indexOf('.');

+        var s_i2 = i_ip.indexOf('.', (s_i1 + 1));

+        var s_i3 = i_ip.indexOf('.', (s_i2 + 1));

+        o_ip = hex(i_ip.substring(0, s_i1)) + hex(i_ip.substring((s_i1 + 1), s_i2)) + hex(i_ip.substring((s_i2 + 1), s_i3)) + hex(i_ip.substring((s_i3 + 1), i_ip.length));

+        o_ip = '0x' + o_ip;

+

+        return 	o_ip;	

+	}

+	

+	function sf_getIpString_3(i_ip)

+	{

+        var i1 = i_ip.indexOf('.');

+        var i2 = i_ip.indexOf('.', (i1 + 1));

+        var i3 = i_ip.indexOf('.', (i2 + 1));

+        var i4 = i_ip.substring((i3+1),i_ip.length)-0;

+

+        return 	i4;	

+	}	

+

+	

+    // Íø¹ØÐ£Ñ麯Êý

+    function sf_isValidate_Gateway(i_wanIp, i_netmaskIp, i_gatewayIp) {

+	    var s_wanIp = sf_convertIpToString(i_wanIp);

+		var lan4 = sf_getIpString_3(i_wanIp);

+		

+	    var s_netmaskIp = sf_convertIpToString(i_netmaskIp);

+		var mask4 = sf_getIpString_3(i_netmaskIp);		

+		

+	    var s_gatewayIp = sf_convertIpToString(i_gatewayIp);

+		var pool4 = sf_getIpString_3(i_gatewayIp);	

+		

+        var net_no;

+        var lo_broadcast;		

+

+        if (sf_opAnd4Byte(s_wanIp, s_netmaskIp) != sf_opAnd4Byte(s_gatewayIp, s_netmaskIp)) {

+            return false;

+        }

+

+        net_no       = (lan4 & mask4);

+        lo_broadcast =  (lan4 & mask4) + (255-mask4);

+

+        return !(pool4==net_no || pool4==lo_broadcast);		

+	

+    }	

+

+	// ×ÓÍøÑÚÂëУÑ麯Êý		

+    function sf_isValidate_Netmask(i_netmask) {

+        var addr = i_netmask.split(".");

+		

+		if ("0.0.0.0" == i_netmask || "255.255.255.255" == i_netmask) {

+            return false;

+        }

+

+        if (addr.length != 4) {

+            return false;

+        }

+

+        addr[0] = parseInt(addr[0]);

+        addr[1] = parseInt(addr[1]);

+        addr[2] = parseInt(addr[2]);

+        addr[3] = parseInt(addr[3]);

+

+        if (addr[3] != 0) {

+            if (addr[0] != 255 || addr[1] != 255 || addr[2] != 255) {

+                return false;

+            } else {

+                if (!sf_isValidate_NetmaskIP(addr[3])) {

+                    return false;

+                }

+            }

+        }

+

+        if (addr[2] != 0) {

+            if (addr[0] != 255 || addr[1] != 255) {

+                return false;

+            } else {

+                if (!sf_isValidate_NetmaskIP(addr[2])) {

+                    return false;

+                }

+            }

+        }

+

+        if (addr[1] != 0) {

+            if (addr[0] != 255) {

+                return false;

+            } else {

+                if (!sf_isValidate_NetmaskIP(addr[1])) {

+                    return false;

+                }

+            }

+        }

+			

+        if (addr[0] != 255) {

+            return false;

+        }

+			

+        return true;

+    }

+	

+    // DHCP IP³ØÐ£Ñ麯Êý

+    function sf_isValidate_StartEndIp(i_lanIpaddr, i_netIp, i_startIp, i_endIp, i_DHCPFlag) {

+	    s_startIp = sf_convertIpToString(i_startIp);

+		s_endIp   = sf_convertIpToString(i_endIp);

+		s_lanIp   = sf_convertIpToString(i_lanIpaddr);

+

+		if(s_startIp>s_endIp) {

+            return 1;

+        }

+		

+        if(s_lanIp >= s_startIp && s_lanIp <= s_endIp) {

+            return 2;

+        }

+

+        return 0;		

+	}

+

+

+    function init() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var fwVm = new LanViewModel();

+        ko.applyBindings(fwVm, container[0]);

+

+        addInterval(fwVm.refreshStatus, 1000);

+

+        $('#frmLan').validate({

+            submitHandler:function () {

+                fwVm.save();

+            },

+			

+            rules:{

+                txtIpAddress: {

+                    lanip_check: true,

+                    ipRange: true

+                },

+                txtSubnetMask: {

+                    ipv4: true,

+                    subnetmask_check: true

+                },

+                txtDhcpIpPoolStart: {

+                    lanip_check: true,

+                    dhcp_check: "start",

+                    dhcpCompare: "#txtDhcpIpPoolEnd"

+                },

+                txtDhcpIpPoolEnd: {

+                    lanip_check: true,

+                    dhcp_check: "end",

+                    dhcpCompare: "#txtDhcpIpPoolStart"

+                },

+                txtDhcpLease: {

+                    range: [1, 65535],

+                    digits: true

+                }

+            },

+				

+            groups: {

+                lanip_check: "txtDhcpIpPoolStart txtDhcpIpPoolEnd"

+            },

+				

+            errorPlacement: function (error, element) {

+                if (element.attr("name") == "txtDhcpLease") {

+                    error.insertAfter("#errorHolder");

+                } else if (element.attr("name") == "txtDhcpIpPoolStart") {

+                    error.insertAfter("#txtDhcpIpPoolEnd");

+                } else {

+                    error.insertAfter(element);

+                }

+			}

+        });

+

+    }

+		

+		

+    return {

+        init:init

+    }

+});

+

+// others Ä£¿é°üº¬:Fast Boot Settings¡¢Restart and Reset¡¢SNTP¡¢Turn Off Device¡¢PIN Management

+define("adm_others","jquery knockout set service underscore".split(" "),

+

+    function ($, ko, config, service, _) {

+		

+		var timeSetModes = _.map(config.sntpTimeSetMode, function(item) {

+			return new Option(item.name, item.value);

+		});

+		

+		var timeZones    = _.map(config.timeZone, function(item){

+			return new Option(item.name, item.value);

+		});

+		

+		var daylightSave = _.map(config.daylightSave, function(item){

+			return new Option(item.name, item.value);

+		});

+		

+		var sv_sntpYears    = [];

+		var sv_sntpMonths   = [];

+		var sv_sntpDates    = [];  //¸ù¾Ý´óСÔÂÉú³ÉÊý×é

+		var sv_sntpHours    = [];

+		var sv_sntpMinutes  = [];

+			

+		var sf_bigMonth     = [1, 3, 5, 7, 8, 10, 12];

+		var sf_smallMonth   = [4, 6, 9, 11];

+		

+		function sf_produceArray(start, end, arryName) {

+			var item = {};

+			for(var i = start; i <= end; i++) {

+				item.name  = i;

+				item.value = i;

+				arryName.push(new Option(item.name, item.value));

+			}

+		}

+		

+		//Éú³ÉÄê¡¢Ô¡¢Ê±¡¢·ÖµÄÊý×é

+		sf_produceArray(2000, 2030, sv_sntpYears);

+		sf_produceArray(1, 12, sv_sntpMonths);

+		sf_produceArray(0, 23, sv_sntpHours);

+		sf_produceArray(0, 59, sv_sntpMinutes);			

+		

+        function othersViewModel() {

+            var target = this;

+			

+			var inChildGroup = false;

+			

+            target.fastbootSupport    = config.FAST_BOOT_SUPPORT;

+            target.turnOffSupport     = config.TURN_OFF_SUPPORT;     

+            target.SNTPSupport        = config.HAS_SNTP;

+			target.hasUssd            = config.HAS_USSD;

+			target.hasDdns            = config.DDNS_SUPPORT;

+			target.hasUpdateCheck     = config.HAS_UPDATE_CHECK;

+

+			

+            if (config.HAS_PARENTAL_CONTROL) {

+                inChildGroup = service.checkCurrentUserInChildGroup().result;

+            }

+            target.currentUserInChildGroup = ko.observable(inChildGroup);

+

+            var sv_fastbootInfo = service.getFastbootSetting();

+            target.fastbootEnableFlag =  ko.observable(config.RJ45_SUPPORT ? (sv_fastbootInfo.need_sim_pin != "yes" && service.getRj45PlugState().rj45_plug == "wan_lan_off") : sv_fastbootInfo.need_sim_pin != "yes");

+            target.fastbootSetting = ko.observable(sv_fastbootInfo.fastbootEnabled);

+

+

+            // @method addInterval		

+			addInterval(function(){

+				target.fastbootEnableFlag(config.RJ45_SUPPORT ? (sv_fastbootInfo.need_sim_pin != "yes" && service.getRj45PlugState().rj45_plug == "wan_lan_off") : sv_fastbootInfo.need_sim_pin != "yes");

+			}, 1000);				

+

+            // »Ö¸´³ö³§ÉèÖÃ

+            // @event restore

+            target.restore = function () {

+                showConfirm("restore_confirm", function () {

+                    showLoading("restoring");

+                    service.restoreFactorySettings({}, function (info) {

+                        if (info && info.result == "success") {

+                            successOverlay();

+                        } else {

+                            errorOverlay();

+                        }

+                    }, function (result) {

+                        if (isErrorObject(result) && result.errorType == 'no_auth') {

+                            errorOverlay();

+                        }

+                    });

+                });

+            };

+

+            target.restart = function () {

+                showConfirm("restart_confirm", function () {

+                    restartDevice(service);

+                });

+            };

+			

+            // ¿ìËÙ¿ª¹Ø»úÉèÖÃ

+            target.saveFastBoot = function() {

+                showLoading();

+                var params = {

+                    fastbootEnabled: target.fastbootSetting(),

+                    need_hard_reboot: sv_fastbootInfo.need_hard_reboot

+                };

+                service.setFastbootSetting(params, function(result) {

+                    if (result.result == "success") {

+                        successOverlay();

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            };

+			

+            // ¹Ø»ú

+            target.turnoff = function () {

+                showConfirm("turnoff_confirm", function () {

+                    showLoading("turnoff");

+                    service.turnOffDevice({}, function (info) {

+                        if (info && info.result == "success") {

+                            successOverlay();

+                        } else {

+                            errorOverlay();

+                        }

+                    }, $.noop);

+                });

+            };

+					

+			//SNTP´¥·¢serverУ׼ʱ¼ä

+			service.setSNTPDate({

+				goformId: "SNTP_Getdatastatic"

+			});

+			

+			var target       = this;

+			var sntpInfo   = service.getSntpParams();

+			

+			globalTime     = new Date(parseInt(sntpInfo.sntp_year, 10),parseInt(sntpInfo.sntp_month, 10)-1, parseInt(sntpInfo.sntp_day, 10), parseInt(sntpInfo.sntp_hour, 10), parseInt(sntpInfo.sntp_minute, 10), parseInt(sntpInfo.sntp_second, 10));

+

+			target.day       = ko.observable();

+			target.localTime = ko.observable();

+			

+			//³õʼ»¯µ±Ç°±¾µØÊ±¼ä

+			//target.updateCurrentTime; cov_2

+			target.timeSetModes    = ko.observableArray(timeSetModes);

+			target.isManualSetTime = ko.observable(false);

+			target.isAutoSntpTime  = ko.observable(false);

+			

+			target.currentMode = ko.observable(sntpInfo.sntp_time_set_mode);

+			

+			changeSetTimeMode();

+			target.changeSetTimeMode = function(){

+				changeSetTimeMode();

+			};

+			

+			target.currentYear   = ko.observable(parseInt(sntpInfo.sntp_year, 10));

+			target.currentMonth  = ko.observable(parseInt(sntpInfo.sntp_month, 10));

+			target.currentDate   = ko.observable(parseInt(sntpInfo.sntp_day, 10));

+			target.currentHour   = ko.observable(parseInt(sntpInfo.sntp_hour, 10));

+			target.currentMinute = ko.observable(parseInt(sntpInfo.sntp_minute, 10));

+			

+

+			// ÐèÒª¸ù¾ÝÄêÔÂË¢ÐÂÈÕÆÚÁбíÊý¾Ý£¬×¢Òâ˳Ðò 

+

+			target.years  = ko.observableArray(sv_sntpYears);

+			target.months = ko.observableArray(sv_sntpMonths);				

+			//µ±Óû§Ñ¡ÔñÔ·ݵÄʱºò¸Ä±äÈÕÆÚÑ¡Ôñ¿òµÄÑ¡Ïî

+			target.initDateList = function(){

+				initDateList();

+				target.dates(sv_sntpDates);

+			}

+		

+			//³õʼ»¯ÈÕÆÚÁбí

+			initDateList();

+			target.dates   = ko.observableArray(sv_sntpDates);

+			target.hours   = ko.observableArray(sv_sntpHours);

+			target.minutes = ko.observableArray(sv_sntpMinutes);

+			

+			//×Ô¶¯SNTP»ñȡʱ¼äÊý¾Ý°ó¶¨´¦Àí

+			var serverArray = _.map(sntpInfo.sntp_servers, function(item) {

+				return new Option(item.name, item.value)

+			});

+			

+			target.serverList          = ko.observableArray(serverArray);

+

+			// ÒÔÏÂÃû×Ö²»ÄÜÐ޸ģ¬ÐÞ¸ÄÎÞ·¨Ë¢ÐÂÍøÒ³

+

+			target.currentServer0 = ko.observable(sntpInfo.sntp_server0);

+			target.currentServer1 = ko.observable(sntpInfo.sntp_server1);

+			target.currentServer2 = ko.observable(sntpInfo.sntp_server2);

+			target.customServer0 = ko.observable(sntpInfo.sntp_other_server0);

+			target.customServer1 = ko.observable(sntpInfo.sntp_other_server1);

+			target.customServer2 = ko.observable(sntpInfo.sntp_other_server2);

+			target.isOther0 = ko.observable(false);

+			target.isOther1 = ko.observable(false);

+			target.isOther2 = ko.observable(false);

+			

+			initOtherServer();

+

+			target.changeServerSelect = function(){

+				initOtherServer();

+			}

+			

+			target.timeZones           = ko.observableArray(timeZones);

+			target.currentTimeZone     = ko.observable(sntpInfo.sntp_timezone + "_" + sntpInfo.sntp_timezone_index);

+			target.daylightSaves       = ko.observableArray(daylightSave);

+			target.currentDaylightSave = ko.observable(sntpInfo.sntp_dst_enable);

+			

+			//¸üе±Ç°ÏÔʾʱ¼ä

+			target.updateCurrentTime = function() {

+			    var globalDay = globalTime.getDay();

+				

+				switch(globalDay){

+				    case 6:

+				    	target.day($.i18n.prop("saturday"));

+				    	break;		

+				    case 5:

+				    	target.day($.i18n.prop("friday"));

+				    	break;	

+				    case 4:

+				    	target.day($.i18n.prop("thursday"));

+				    	break;	

+				    case 3:

+				    	target.day($.i18n.prop("wednesday"));

+				    	break;

+				    case 2:

+				    	target.day($.i18n.prop("tuesday"));

+				    	break;	

+				    case 1:

+				    	target.day($.i18n.prop("monday"));

+				    	break;						

+				    case 0:

+				    	target.day($.i18n.prop("sunday"));

+				    	break;

+				    default:

+			        	break;

+				}

+					

+				var localCurrentTime = globalTime.getFullYear() + "-" + getTwoDigit(globalTime.getMonth()+1) + "-" + getTwoDigit(globalTime.getDate()) + " " + getTwoDigit(globalTime.getHours()) + ":" + getTwoDigit(globalTime.getMinutes()) + ":" + getTwoDigit(globalTime.getSeconds());

+				target.localTime(localCurrentTime);

+				globalTime.setTime(globalTime.getTime()+1000);			

+			};

+				

+            // SNTPÉèÖÃ		

+			target.apply = function(){

+				var tmpArray = [];

+				for(var i=0; i< sntpInfo.sntp_servers.length; i++){

+					tmpArray.push(sntpInfo.sntp_servers[i].value);

+				}

+				var staInfo = service.getStatusInfo();

+				if(!checkConnectedStatus(staInfo.connectStatus, staInfo.rj45ConnectStatus, staInfo.connectWifiStatus) && target.currentMode() == "auto"){

+					showAlert("sntp_syn_time_wan_connected");

+					return;

+				}

+				

+				showLoading("");

+				var requestParams = {

+					goformId: "SNTP",

+					manualsettime : target.currentMode(),

+					sntp_server1_ip : target.currentServer0(),

+					sntp_server2_ip : target.currentServer1(),

+					sntp_server3_ip : target.currentServer2(),

+					sntp_other_server0 : target.customServer0(),

+					sntp_other_server1 : target.customServer1(),

+					sntp_other_server2 : target.customServer2(),

+					timezone : target.currentTimeZone().split("_")[0],

+					sntp_timezone_index : target.currentTimeZone().split("_")[1],

+					DaylightEnabled : target.currentDaylightSave(),

+					time_year : target.currentYear(),

+					time_month : target.currentMonth(),

+					time_day : target.currentDate(),

+					time_hour : target.currentHour(),

+					time_minute : target.currentMinute()

+				};

+        

+				service.setSntpSetting(requestParams, function(data2){

+					if(data2) {

+					    if(data2.result == "success" && target.currentMode() == "auto"){

+                            successOverlay("sntp_req_success");

+							//hideLoading();

+						}else if(data2.result == "processing" && target.currentMode() == "auto"){

+							successOverlay("sntp_processing");

+						}else{

+							//´¥·¢serverУ׼ʱ¼ä

+							service.setSNTPDate({

+								goformId: "SNTP_Getdatastatic"

+							}, function(result){

+									var sntpInfo = 	service.getSntpParams();

+									globalTime = new Date(parseInt(sntpInfo.sntp_year, 10),parseInt(sntpInfo.sntp_month, 10)-1, parseInt(sntpInfo.sntp_day, 10), parseInt(sntpInfo.sntp_hour, 10), parseInt(sntpInfo.sntp_minute, 10), parseInt(sntpInfo.sntp_second, 10));

+									successOverlay();

+							});

+						}

+					} else {

+						errorOverlay();

+					}

+				});

+			}

+			

+            // ÊÖ¶¯/×Ô¶¯Çл»ÏìÓ¦º¯Êý		

+			function changeSetTimeMode() {

+				if(target.currentMode() == "manual") {

+					target.isManualSetTime(true);

+					target.isAutoSntpTime(false);

+				} else {

+					target.isManualSetTime(false);

+					target.isAutoSntpTime(true);

+				}

+				return true;

+			}

+			

+            // ³õʼ»¯Ê±¼ä

+			function initDateList(){

+				sv_sntpDates = [];

+				if($.inArray(parseInt(target.currentMonth(), 10), sf_smallMonth) != -1) {

+					sf_produceArray(1, 30, sv_sntpDates);

+				} else if($.inArray(parseInt(target.currentMonth(), 10), sf_bigMonth) != -1) {

+					sf_produceArray(1, 31, sv_sntpDates);

+				} else if(parseInt(target.currentYear(), 10)%4 == 0) {

+					sf_produceArray(1, 29, sv_sntpDates);

+				} else {

+					sf_produceArray(1, 28, sv_sntpDates);

+				}

+			}

+			

+            // ³õʼ»¯ÆäËû·þÎñÆ÷			

+			function initOtherServer(){

+				target.isOther0(target.currentServer0() == "Other");

+				target.isOther1(target.currentServer1() == "Other");

+				target.isOther2(target.currentServer2() == "Other");

+				!target.isOther0() && $("#sntp_server0").find(".error").hide();

+				!target.isOther1() && $("#sntp_server1").find(".error").hide();

+				!target.isOther2() && $("#sntp_server2").find(".error").hide();

+			}

+

+			

+        }

+

+	    // ³õʼ»¯ ViewModel£¬²¢½øÐÐÊÓͼ°ó¶¨

+        function init() {

+            var fwVm = new othersViewModel();

+            var container = $('#container')[0];

+		    ko.cleanNode(container);

+            ko.applyBindings(fwVm, container);

+			fwVm.updateCurrentTime();

+		

+		    addInterval(function(){

+			    fwVm.updateCurrentTime();

+		    }, 1000);

+		

+		    $("#sntpForm").validate({

+			    submitHandler: function(){

+				    fwVm.apply();

+			    },

+			    rules: {

+				    sntp_other_server0 : "sntp_invalid_server_name",

+				    sntp_other_server1 : "sntp_invalid_server_name",

+				    sntp_other_server2 : "sntp_invalid_server_name"

+			    }

+		    });

+        }

+

+        return {

+            init:init

+        }

+    });

+// ÃÜÂë¹ÜÀí Ä£¿é

+

+define("adm_management","jquery knockout set service underscore CryptoJS".split(" "),

+

+    function ($, ko, config, service, _, CryptoJS) {

+

+        function manageViewModel() {

+            var target = this;

+            

+            target.currentValue = ko.observable();

+            target.newValue     = ko.observable();

+            target.confirmValue = ko.observable();

+            

+            function sf_changeValue() {

+            var sv_manageInfo = {};

+            if (config.PASSWORD_ENCODE) {

+                sv_manageInfo.oldValue = target.currentValue();

+                sv_manageInfo.newValue = target.newValue(); 

+            } else {            

+                var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,32}');

+  

+                if (!pwdRegex.test(target.newValue())) {

+                    showConfirm("password_note_too_low", function () {

+

+                    var kparam = service.getDeviceInfoLow();

+                    var tkey = CryptoJS.enc.Latin1.parse(kparam.skey);

+					var tiv = CryptoJS.enc.Latin1.parse(kparam.siv);

+                    var cipherold = CryptoJS.AES.encrypt(target.currentValue(), tkey, {

+                            iv: tiv,

+                            mode: CryptoJS.mode.CBC,

+                            padding: CryptoJS.pad.ZeroPadding

+                            }).toString();

+                    var ciphernew = CryptoJS.AES.encrypt(target.newValue(), tkey, {

+                            iv: tiv,

+                            mode: CryptoJS.mode.CBC,

+                            padding: CryptoJS.pad.ZeroPadding

+                            }).toString();

+

+                    sv_manageInfo.oldValue = cipherold;

+                    sv_manageInfo.newValue = ciphernew;

+                

+                    showLoading();

+                

+                    service.changeManageInfo(sv_manageInfo, function (resultInfo) {

+                        target.cancel();

+                        if (resultInfo && resultInfo.result == true) {

+                            successOverlay();

+                        } else {

+                            if (resultInfo && resultInfo.errorType == "badPassword") {

+                                hideLoading();

+                                showAlert("current_password_error",function(){

+                                    $("#txtCurrent").focus();

+                                });

+                            } else {

+                                errorOverlay();

+                            }

+                        }

+                    });

+                    });

+                    return;

+               }

+                var kparam = service.getDeviceInfoLow();

+                var tkey = CryptoJS.enc.Latin1.parse(kparam.skey);

+		var tiv = CryptoJS.enc.Latin1.parse(kparam.siv);

+                var cipherold = CryptoJS.AES.encrypt(target.currentValue(), tkey, {

+                        iv: tiv,

+                        mode: CryptoJS.mode.CBC,

+                        padding: CryptoJS.pad.ZeroPadding

+                        }).toString();

+                var ciphernew = CryptoJS.AES.encrypt(target.newValue(), tkey, {

+                        iv: tiv,

+                        mode: CryptoJS.mode.CBC,

+                        padding: CryptoJS.pad.ZeroPadding

+                        }).toString();

+

+                sv_manageInfo.oldValue = cipherold;

+                sv_manageInfo.newValue = ciphernew;

+                }

+

+                showLoading();

+                

+                service.changeManageInfo(sv_manageInfo, function (resultInfo) {

+                    target.cancel();

+                    if (resultInfo && resultInfo.result == true) {

+                        successOverlay();

+                    } else {

+                        if (resultInfo && resultInfo.errorType == "badPassword") {

+                            hideLoading();

+                            showAlert("current_password_error",function(){

+                                $("#txtCurrent").focus();

+                            });

+                        } else {

+                            errorOverlay();

+                        }

+                    }

+                });     

+            }

+            

+            // Çå³ýÊäÈëµÄÃÜÂë

+            function sf_cancel() {

+                target.currentValue("");

+                target.newValue("");

+                target.confirmValue("");

+            }           

+            

+            target.cancel = sf_cancel;

+            

+            // ÐÞ¸ÄÃÜÂë

+            target.changeValue = sf_changeValue;

+        }

+

+        function init() {

+            var container = $('#container');

+            ko.cleanNode(container[0]);

+            var fwVm = new manageViewModel();

+            ko.applyBindings(fwVm, container[0]);

+                  

+            $('#frmPassword').validate({

+                submitHandler:function () {

+                    fwVm.changeValue();

+                },

+                rules:{

+                    txtCurrent:"manage_info_check",

+                    txtNew:"manage_info_check",

+                    txtConfirm:{ equalTo:"#txtNew"}

+                }

+            });

+        }

+

+        return {

+            init:init

+        }

+    }

+);

+// PIN¹ÜÀíÄ£¿é

+

+define("adm_pin","jquery knockout set service".split(" "),

+

+    function ($, ko, config, service) {

+        var pageState = {common:0, requirePin:1, modifyPin:2, requirePuk:3, destroyed:4};

+        var pinStatus = {enable:"1", disable:"0"};

+

+

+        function pinViewModel() {

+            var target = this;

+            var sv_currentPinData     = service.getPinData();

+			

+            target.isDataCard         = config.PRODUCT_TYPE == 'DATACARD';

+            target.originPinStatus    = ko.observable(sv_currentPinData.pin_status);

+			

+            target.pinStatus          = ko.observable(sv_currentPinData.pin_status);

+            target.pinNumber          = ko.observable(sv_currentPinData.pinnumber);

+            target.pukNumber          = ko.observable(sv_currentPinData.puknumber);

+			

+            target.currentPin         = ko.observable();

+            target.newPin             = ko.observable();

+            target.confirmPin         = ko.observable();

+			

+            target.puk                = ko.observable();

+			

+            target.pageState          = ko.observable();

+            // ÇëÇó²Ù×÷ºó³É¹¦±ê־λ

+            target.operateSuccessFlag = true;

+			

+			target.callback           = sf_callback;		

+			

+			function sf_callback(info) {

+                if (info && info.result == true) {

+                    target.operateSuccessFlag = true;

+                    successOverlay();

+                } else {

+                    target.operateSuccessFlag = false;

+					

+                    // ×îºóÒ»´ÎǰҪµ¯¿òÌáʾ					 

+                    if(target.pinNumber() == 2){

+                      showAlert("last_enter_pin");    

+                    } else if(target.pukNumber() == 2){

+                      showAlert("last_enter_puk");    

+                    }

+                    else{

+                      errorOverlay();      

+                    }   

+                }

+                init(target);

+            }

+            	

+

+            // È·¶¨°´Å¥Ê¼þ´¦Àí£¬°üÀ¨ÐÞ¸ÄPIN£¬¸ù¾ÝPUKÉèÖÃPIN£¬ÉèÖÃPINµÄʹÄÜ״̬

+			

+            function sf_changePin() {

+                if (target.isConnectedNetWork()) {

+                    showAlert("cannot_operate_when_connected");

+                    return;

+                }

+

+                if (target.pageState() == pageState.common) {

+                    return;

+                }

+

+                var sv_pinPara = {

+                    oldPin:target.currentPin(),

+                    newPin:target.newPin()

+                };

+                showLoading();

+

+                if (target.pageState() == pageState.modifyPin) {

+                    service.changePin(sv_pinPara, target.callback);

+                } else if (target.pageState() == pageState.requirePuk) {

+                    sv_pinPara = {

+                        PinNumber:target.newPin(),

+                        PUKNumber:target.puk()

+                    };

+                    service.enterPUK(sv_pinPara, target.callback);

+                } else {

+                    if (target.pinStatus() == pinStatus.enable) {

+                        service.enablePin(sv_pinPara, target.callback);

+                    } else {

+                        service.disablePin(sv_pinPara, target.callback);

+                    }

+                }

+            }	

+			

+

+			// È¡Ïûʼþ´¦Àí

+            function sf_cancel() {

+                target.pageState(pageState.common);

+                target.pinStatus(target.originPinStatus());

+                target.clear();

+            }		

+

+            // Çå³ýÒ³ÃæÊäÈëºÍ¼ì²âÏûÏ¢

+			function sf_clear() {

+                target.confirmPin("");			

+                target.currentPin("");

+                target.newPin("");

+                target.puk("");

+                clearValidateMsg();

+            }	

+

+            // ¸ù¾ÝÊý¾Ý£¬ÉèÖõ±Ç°µÄÒ³Ãæ×´Ì¬

+            function sf_computePageState(i_pinData) {

+                if (i_pinData.pinnumber > 0) {

+                    //²Ù×÷³É¹¦Ò³Ãæ»Øµ½³õʼ״̬£¬²Ù×÷ʧ°Ü²¢ÇÒpinnumber>0,Ò³Ãæ²»Ìø×ª

+                    if (target.operateSuccessFlag) {

+                        target.cancel();

+                    } else {

+                        target.clear();

+                    }

+                } else {

+                    target.clear();

+                    if (i_pinData.puknumber > 0) {

+                        target.pageState(pageState.requirePuk);

+                    } else {

+                        target.pageState(pageState.destroyed);

+                    }

+                }

+            }

+			

+            // ½øÈëPINÐÞ¸Ä״̬ʼþ´¦Àí

+			function sf_displayModifyPinPage() {

+                if (target.isConnectedNetWork()) {

+                    showAlert("cannot_operate_when_connected");

+                    return;

+                }

+                target.pinStatus(target.originPinStatus());

+                target.pageState(pageState.modifyPin);

+                target.clear();

+            }

+			

+			// ´¦ÀíÒ³ÃæÔªËØµÄʹÄÜ״̬

+			function sf_fixPageEnable() {

+                if (target.isConnectedNetWork()) {

+                    $('#frmPin :input').each(function () {

+                        disableBtn($(this));

+                    });

+                    clearValidateMsg();

+                } else {

+                    $('#frmPin :input').each(function () {

+                        if (this.id == "txtPin" || this.id == "btnPinApply") {

+                            if (target.pageState() == pageState.common) {

+                                disableBtn($(this));

+                                return;

+                            }

+                        }

+                        if (this.id == "btnModifyPin") {

+                            if (target.originPinStatus() != pinStatus.enable) {

+                                disableBtn($(this));

+                                return;

+                            }

+                        }

+                        if (this.id == "pinEnable" || this.id == "pinDisable") {

+                            if (target.pageState() == pageState.modifyPin) {

+                                disableBtn($(this));

+                                return;

+                            }

+                        }

+                        enableBtn($(this));

+                    });

+

+                }

+            }

+			

+			// ÊÇ·ñÒÑÁªÍø

+			function sf_isConnectedNetWork() {

+                var info = service.getConnectionInfo();

+                return info.connectStatus == "ppp_connected";

+            }

+			

+            // PINʹÄܸıäʱʼþ´¦Àí

+			function sf_pinStatusChangeEvent() {

+                if (target.pinStatus() == target.originPinStatus()) {

+                    target.pageState(pageState.common);

+                } else {

+                    target.pageState(pageState.requirePin);

+                }

+                target.clear();

+            }

+			

+            target.changePin            = sf_changePin;

+            target.cancel               = sf_cancel;

+            target.clear                = sf_clear;	

+            target.computePageState     = sf_computePageState;

+			

+            target.computePageState(sv_currentPinData);			

+			

+            target.displayModifyPinPage = sf_displayModifyPinPage;   

+            target.fixPageEnable        = sf_fixPageEnable;		

+            target.isConnectedNetWork   = sf_isConnectedNetWork;

+			

+            target.pinStatusChangeEvent = ko.dependentObservable(sf_pinStatusChangeEvent, this);			

+        }

+

+        function init(oldViewModel) {

+		

+            var fwVm = oldViewModel;		

+		

+            if (fwVm) {

+                var sv_currentPinData = service.getPinData();

+                fwVm.originPinStatus(sv_currentPinData.pin_status);

+                fwVm.pinNumber(sv_currentPinData.pinnumber);

+                fwVm.pukNumber(sv_currentPinData.puknumber);

+                fwVm.computePageState(sv_currentPinData);

+            } else {

+                fwVm = new pinViewModel();

+                addInterval(function () {

+                    fwVm.fixPageEnable();

+                }, 1000);

+            }

+			

+            var container = $('#container')[0];

+		    ko.cleanNode(container);

+            ko.applyBindings(fwVm, container);

+            fwVm.fixPageEnable();

+

+            $('#frmPin').validate({

+                submitHandler:function () {

+                    fwVm.changePin();

+                },

+                rules:{

+                    txtPuk:"puk_check",

+                    txtPin:"pin_check",

+                    txtNewPin:"pin_check",

+                    txtConfirmPin:{equalToPin:"#txtNewPin"}

+                }

+            });

+        }

+

+        return {

+            init:init

+        }

+    }

+);

+

+// ¿ìËÙÉèÖÃ

+define("adm_quick_set","jquery knockout set service underscore CryptoJS".split(" "),

+

+    function ($, ko, config, service, _, CryptoJS) {

+

+        var sv_wifiState = {ok:0, wps_on:1, wifi_off:2};

+        var sv_apnMode   = {auto:"auto", manual:"manual"};

+        var sv_minStep   = 1;

+        var sv_maxStep   = 5;

+

+        // »ñÈ¡¼øÈ¨·½Ê½

+        function sf_fetchAuthenticationModes() {

+            return _.map(config.APN_AUTH_MODES, function (item) {

+                return new Option(item.name, item.value);

+            });

+        }

+		

+        // WIFI°²È«Ä£Ê½Ñ¡Ïî

+        var sv_securityModes = _.map(config.WIFI_WEP_SUPPORT ? config.AUTH_MODES_WEP : config.AUTH_MODES, function (item) {

+            return new Option(item.name, item.value);

+        });

+

+

+        function quickSettingViewModel() {

+            var target = this;

+			

+            var sv_quickSettingInfo        = service.getQuickSettingInfo();

+

+            target.currentStep            = ko.observable(sv_minStep);

+            target.ipType                 = ko.observable(sv_quickSettingInfo.pdp_type == "IP" ? "IP" : sv_quickSettingInfo.ipv6_pdp_type);			

+            target.supportIPv6            = config.IPV6_SUPPORT;

+            target.supportIpv4AndIpv6     = config.IPV4_AND_V6_SUPPORT;

+

+            target.wpsFlag                = ko.observable(sv_quickSettingInfo.WscModeOption);		

+

+            function sf_apnDisabled() {

+                return (sv_quickSettingInfo.apn_index < config.defaultApnSize || sv_quickSettingInfo.ppp_status == "ppp_connected" || sv_quickSettingInfo.ppp_status == "ppp_connecting");

+            }

+

+			function sf_apnModeDisabled() {

+                return (sv_quickSettingInfo.ppp_status == "ppp_connected" || sv_quickSettingInfo.ppp_status == "ppp_connecting" || (!target.profileName() && target.apnMode() == sv_apnMode.auto));//Ñ¡ÏîΪ¿Õ»òÕýÔÚÁ¬½Ó»òÒÑÁ¬½Ó

+            }	

+

+            function sf_currAPN() {

+                var sv_APNText = sv_quickSettingInfo["APN_configtmp" + sv_quickSettingInfo.apn_index];

+                var strIPv6APN = sv_quickSettingInfo["ipv6_APN_configtmp" + sv_quickSettingInfo.apn_index];

+				

+                var sv_apn     = [];

+                var sv_ipv6APNItems = [];

+				

+                if (sv_APNText) {

+                    sv_apn = sv_APNText.split("($)");

+                }

+

+                if (strIPv6APN) {

+                    sv_ipv6APNItems = strIPv6APN.split("($)");

+                }

+

+                return {

+                    m_profile_name:sv_apn[0],

+                    wan_apn:sv_apn[1],

+                    ppp_auth_mode: sv_apn[4] == "" || typeof(sv_apn[4]) == "undefined" ? "" : sv_apn[4].toLowerCase(),					

+                    ppp_username:sv_apn[5],

+                    ppp_passtmp:sv_apn[6],						

+                    pdp_type: sv_apn[7],			

+                    ipv6_wan_apn:sv_ipv6APNItems[1],	

+                    ipv6_ppp_auth_mode:typeof(sv_ipv6APNItems[4]) == "undefined" || sv_ipv6APNItems[4] == ""? "" : sv_ipv6APNItems[4].toLowerCase(),

+                    ipv6_ppp_username:sv_ipv6APNItems[5],					

+                    ipv6_ppp_passtmp:sv_ipv6APNItems[6],					

+                    ipv6_pdp_type:sv_ipv6APNItems[7]			

+                }

+            }			

+			

+            // µ±Ç°APNÅäÖÃ			

+            target.currAPN                = ko.computed(sf_currAPN);

+			

+			target.apn                    = ko.observable(target.currAPN().wan_apn);

+			target.ipv6_apn               = ko.observable(target.currAPN().ipv6_wan_apn);

+            target.ipv6_selectedAuthMode  = ko.observable(target.currAPN().ipv6_ppp_auth_mode);				

+            target.ipv6_username          = ko.observable(target.currAPN().ipv6_ppp_username);

+            target.ipv6_password          = ko.observable(target.currAPN().ipv6_ppp_passtmp);			

+			target.profileName            = ko.observable(target.currAPN().m_profile_name);	

+			target.selectedAuthMode       = ko.observable(target.currAPN().ppp_auth_mode);

+            target.username               = ko.observable(target.currAPN().ppp_username);

+            target.password               = ko.observable(target.currAPN().ppp_passtmp);

+

+            target.transAPN               = ko.observable("apn_ipv4_apn");

+			target.transAPNIPv6           = ko.observable("apn_ipv6_apn");			

+            target.transAuthMode          = ko.observable("apn_authentication_ipv4");

+			target.transAuthModeIPv6      = ko.observable("apn_authentication_ipv6");

+            target.transUserName          = ko.observable("apn_user_name_ipv4");

+            target.transPassword          = ko.observable("apn_password_ipv4");     

+            target.transUserNameIPv6      = ko.observable("apn_user_name_ipv6");

+            target.transPasswordIPv6      = ko.observable("apn_password_ipv6");	

+

+		

+			

+            target.apnDisabled            = ko.computed(sf_apnDisabled);

+			target.apnMode                = ko.observable(sv_quickSettingInfo.apn_mode);	

+            target.apnModeDisabled        = ko.computed(sf_apnModeDisabled);

+            target.authModes              = ko.observableArray(sf_fetchAuthenticationModes());

+ 

+            if (target.ipType() == "IPv6") {

+                target.showIPv4 = false;

+                target.showIPv6 = true;

+                target.transAPNIPv6("apn");

+                target.transAuthModeIPv6("apn_authentication");

+                target.transUserNameIPv6("apn_user_name");

+                target.transPasswordIPv6("apn_password");

+            } else if (config.IPV4_AND_V6_SUPPORT && target.ipType() == "IPv4v6") {

+                target.showIPv4 = true;

+                target.showIPv6 = true;

+                //ʹÓÃĬÈÏ

+            } else if (target.ipType() == "IP" || target.ipType() == "IPv4") {

+                target.showIPv4 = true;

+                target.showIPv6 = false;

+                target.transAPN("apn");

+                target.transAuthMode("apn_authentication");

+                target.transUserName("apn_user_name");

+                target.transPassword("apn_password");

+            } else { //pdp_type == "IPv4v6" && config.IPV4V6_SUPPORT

+                target.showIPv4 = true;

+                target.showIPv6 = false;

+                target.transAPN("apn");

+                target.transAuthMode("apn_authentication");

+                target.transUserName("apn_user_name");

+                target.transPassword("apn_password");

+            }

+

+            target.wifiDisabled                  = (sv_quickSettingInfo.wifi_cur_state != "1");

+            target.ssid                          = ko.observable(sv_quickSettingInfo.SSID1);

+            target.broadcast                     = ko.observable(sv_quickSettingInfo.HideSSID);

+	    target.hasWifiWep                    = config.WIFI_WEP_SUPPORT;

+	    target.hasWifiWpa3                   = config.WIFI_WAP3_SUPPORT;

+	    target.hasWifiWpa23                  = config.WIFI_WPA2_WAP3_SUPPORT;

+

+            target.securityModes                 = ko.observableArray(sv_securityModes);

+            target.selectedSecurityMode          = ko.observable(sv_quickSettingInfo.AuthMode);

+            target.WPAKey                        = ko.observable(sv_quickSettingInfo.WPAPSK1);

+

+            target.apnMode_display               = ko.observable("");

+			

+            target.apnMode_trans                 = ko.computed(sf_apnMode_trans);

+            target.selectedAuthMode_display      = ko.computed(sf_selectedAuthMode_display);

+            target.ipv6_selectedAuthMode_display = ko.computed(sf_ipv6_selectedAuthMode_display);

+

+            target.showWifiPassword              = ko.observable(false);

+            target.showWifiPasswordHandler       = sf_showWifiPasswordHandler;

+            

+			//ÅжÏÊÇ·ñÔÚ802 n onlyÏÂ

+			var sv_adInfo                        = service.getWifiAdvance();

+			target.adBand                        = ko.observable(sv_adInfo.wifiBand);

+			target.adMode                        = ko.observable(sv_adInfo.mode);

+			

+			target.encryptType                   = ko.observable(sv_quickSettingInfo.EncrypType);

+			target.keyID                         = ko.observable(sv_quickSettingInfo.DefaultKeyID);

+			target.wepPassword                   = ko.observable("");

+			

+			target.getWepPassword                = sf_getWepPassword;

+			target.wepPassword(target.getWepPassword());

+			target.profileChangeHandler          = sf_profileChangeHandler;

+			

+            target.broadcast_display             = ko.observable("");

+            target.broadcast_trans               = ko.computed(sf_broadcast_trans);

+

+            target.selectedSecurityMode_display  = ko.observable();   

+            target.selectedSecurityMode_trans    = ko.computed(sf_selectedSecurityMode_trans);

+			

+

+            target.callback                      = sf_callback;

+            target.next                          = sf_button_next;			

+            target.previous                      = sf_button_previous;					

+            target.save                          = sf_button_save;

+

+			function sf_apnMode_trans() {

+                if (sv_apnMode.auto == target.apnMode()) {

+                    target.apnMode_display($.i18n.prop("apn_auto_apn"));

+                    return "apn_auto_apn";

+                } else {

+                    target.apnMode_display($.i18n.prop("apn_manual_apn"));

+                    return "apn_manual_apn";

+                }

+            }

+			

+			function sf_broadcast_trans() {

+                if ("0" == target.broadcast()) {

+                    target.broadcast_display($.i18n.prop("enable"));

+                    return "enable";

+                } else {

+                    target.broadcast_display($.i18n.prop("disable"));

+                    return "disable";

+                }

+            }

+			

+			function sf_button_next() {

+                var currentStep = target.currentStep();

+                var toStep = target.currentStep() + 1;

+                sf_changeStep(toStep);

+				

+                if (currentStep == 1 && target.apnMode() == sv_apnMode.auto) {

+                    toStep = target.currentStep() + 1;

+                    sf_changeStep(toStep);

+                }

+            }

+			

+			function sf_button_previous() {

+			

+                var currentStep = target.currentStep();

+                var toStep = target.currentStep() - 1;

+				

+                sf_changeStep(toStep);

+				

+                if (currentStep == 3 && target.apnMode() == sv_apnMode.auto) {

+                    toStep = target.currentStep() - 1;

+                    sf_changeStep(toStep);

+                }

+            }

+			function sf_button_save() {

+                var submit = function () {

+                    sf_quickSetting4IPv6();

+                };

+                var result = sf_isDisabled_Wifi();

+                if(result == sv_wifiState.wifi_off){

+                    showConfirm("quick_setting_wifi_disable_confirm", submit);

+                } else if (result == sv_wifiState.wps_on) {

+                    showAlert("wps_on_info");

+                } else{

+                    showConfirm("quick_setting_param_changed_confirm", submit);//submit();

+                }

+            }

+            // ¿ìËÙÉèÖÃÌá½»ºóµÄ»Øµ÷´¦Àí

+			function sf_callback(data) {

+                if (data.result == "success") {

+                    successOverlay();

+                    location.hash = "#network_choose";

+                }

+                else {

+                    errorOverlay();

+                }

+            }

+

+            // ±ä»»²½Öèʱ´¦Àí

+            function sf_changeStep(i_step) {

+                if (i_step > sv_maxStep) {

+                    i_step = sv_maxStep;

+                } else if (i_step < sv_minStep) {

+                    i_step = sv_minStep;

+                }

+				

+                target.currentStep(i_step);

+                return true;

+            }			

+		

+			function sf_ipv6_selectedAuthMode_display() {

+                var mode = target.ipv6_selectedAuthMode();

+                return sf_getAuthModeNameByValue(mode);

+            }

+			// ¸ù¾Ý¼øÈ¨Ä£Ê½µÄÖµ»ñÆäÃû³Æ

+            function sf_getAuthModeNameByValue(authMode) {

+                for (var i = 0; i < config.APN_AUTH_MODES.length; i++) {

+                    if (authMode == config.APN_AUTH_MODES[i].value) {

+                        return config.APN_AUTH_MODES[i].name;

+                    }

+                }

+            }

+			

+			function sf_getWepPassword(){

+				return target.keyID() == '3' ? sv_quickSettingInfo.Key4Str1 : (target.keyID() == '2' ? sv_quickSettingInfo.Key3Str1 : target.keyID() == '1' ? sv_quickSettingInfo.Key2Str1 : sv_quickSettingInfo.Key1Str1);

+			}

+			

+            function sf_isDisabled_Wifi() {

+                var s_wpsInfo = service.getWpsInfo();

+                if(s_wpsInfo.radioFlag == "0"){

+                    return sv_wifiState.wifi_off;

+                }else if (s_wpsInfo.wpsFlag == '1') {

+                    return sv_wifiState.wps_on;

+                }

+                return sv_wifiState.ok;

+            }			

+			function sf_profileChangeHandler(i_data, i_event) {

+			    $("#pwdWepKey").parent().find("label[class='error']").hide();		

+			    target.wepPassword(target.getWepPassword());

+			    return true;

+		    }

+			

+           // ¿ìËÙÉèÖÃÌá½»(Ö§³ÖIPv6£©

+            function sf_quickSetting4IPv6() {

+                showLoading();

+                var useIPv4ForV6 = config.IPV4V6_SUPPORT && target.currAPN().pdp_type == "IPv4v6";

+

+                var ciphertext = "";

+                if (config.PASSWORD_ENCODE) {

+		    ciphertext = target.WPAKey();

+		} else {

+                    var kparam = service.getDeviceInfoLow();

+                    var tkey = CryptoJS.enc.Latin1.parse(kparam.skey);

+		    var tiv = CryptoJS.enc.Latin1.parse(kparam.siv);

+                    ciphertext = CryptoJS.AES.encrypt(target.WPAKey(), tkey, {

+                        iv: tiv,

+                        mode: CryptoJS.mode.CBC,

+                        padding: CryptoJS.pad.ZeroPadding

+                        }).toString();

+		}

+				

+                var s_quickSettingParameters = {

+                    apn_index: sv_quickSettingInfo.apn_index,

+                    apnMode: target.apnMode(),		

+                    Encryption_Mode_hid: target.selectedSecurityMode(),	

+                    ipv6_ppp_auth_mode: useIPv4ForV6 ? target.selectedAuthMode() : target.ipv6_selectedAuthMode(),

+                    ipv6_ppp_username: useIPv4ForV6 ? target.username() : target.ipv6_username(),

+                    ipv6_ppp_passtmp: useIPv4ForV6 ? target.password() : target.ipv6_password(),	

+                    ipv6_wan_apn: useIPv4ForV6 ? target.apn() : target.ipv6_apn(),					

+                    pdp_type: target.ipType(),

+                    ppp_auth_mode: target.selectedAuthMode(),

+                    ppp_username: target.username(),

+                    ppp_passtmp: target.password(),

+                    profile_name: target.profileName(),

+                    //Ŀǰ¼ÓÃÜģʽֻÓÐ2ÖÖ£¬ÏÂÃæ3¸ö²ÎÊýΪ¹Ì¶¨Öµ

+                    //Èç¹ûÐèÒª¶¨ÖÆÎª5ÖÖ£¬²ÎÊýÖµÐèÒªÉèÖÃ

+                    security_shared_mode: "NONE",					

+                    SSID_Broadcast: target.broadcast(),

+                    SSID_name: target.ssid(),

+                    wan_apn: target.apn(),		

+                    wep_default_key: 0,				

+                    WPA_ENCRYPTION_hid: target.selectedSecurityMode() == "OPEN" ? "NONE" : target.selectedSecurityMode() == "WPA2PSK" ? 1 : 2,					

+                    WPA_PreShared_Key: ciphertext

+                }

+				

+				s_quickSettingParameters.wep_default_key = target.keyID();	

+				

+				if(target.encryptType() == "SHARED" || target.selectedSecurityMode() == "WEP") {

+				

+					s_quickSettingParameters.security_shared_mode = "WEP";

+					

+                    s_quickSettingParameters.wep_key_1 = sv_quickSettingInfo.Key1Str1;

+					s_quickSettingParameters.wep_key_2 = sv_quickSettingInfo.Key2Str1;

+					s_quickSettingParameters.wep_key_3 = sv_quickSettingInfo.Key3Str1;

+					s_quickSettingParameters.wep_key_4 = sv_quickSettingInfo.Key4Str1;

+					

+					var WEPSelectTmp = '0';

+					

+                    if(target.wepPassword().length =='5' ||target.wepPassword().length =='13'){

+						WEPSelectTmp = '1';	

+					}else{

+						WEPSelectTmp = '0';	

+					}	

+					

+					if(target.keyID() =='3'){

+						s_quickSettingParameters.wep_key_4  = target.wepPassword();

+						s_quickSettingParameters.WEP4Select = WEPSelectTmp;						

+					}else if(target.keyID() =='2'){	

+						s_quickSettingParameters.wep_key_3  = target.wepPassword();

+						s_quickSettingParameters.WEP3Select = WEPSelectTmp;						

+					}else if(target.keyID() =='1'){						

+						s_quickSettingParameters.wep_key_2  = target.wepPassword();

+						s_quickSettingParameters.WEP2Select = WEPSelectTmp;					

+					}else{

+						s_quickSettingParameters.wep_key_1  = target.wepPassword();

+						s_quickSettingParameters.WEP1Select = WEPSelectTmp;					

+					}					

+				}else if(target.encryptType() == "WPAPSKWPA2PSK") {

+					s_quickSettingParameters.security_shared_mode = "NONE";

+				}else {

+					s_quickSettingParameters.security_shared_mode = "NONE";

+				}

+				

+                service.setQuickSetting4IPv6(s_quickSettingParameters, target.callback);

+            }			

+			

+			function sf_selectedAuthMode_display() {

+                var mode = target.selectedAuthMode();

+                return sf_getAuthModeNameByValue(mode);

+            }

+			

+            function sf_selectedSecurityMode_trans() {

+                var mode = target.selectedSecurityMode();

+				var modesOption = config.WIFI_WEP_SUPPORT ? config.AUTH_MODES_WEP : config.AUTH_MODES;

+                for (var i = 0; i < modesOption.length; i++) {

+                    if (mode == modesOption[i].value) {

+                        target.selectedSecurityMode_display($.i18n.prop("security_mode_" +  modesOption[i].value));

+                        return "security_mode_" +  modesOption[i].value;

+                    }

+                }

+            }

+			

+			function sf_showWifiPasswordHandler(){

+				$("#pwdWepKey").parent().find(".error").hide();

+                $("#codeWPAKey").parent().find(".error").hide();

+                var checkbox = $("#showWifiPassword:checked");

+                if(checkbox && checkbox.length == 0){

+                    target.showWifiPassword(true);

+                }else{

+                    target.showWifiPassword(false);

+                }

+            }			

+			

+        }

+

+        function init() {

+            var container = $('#container');

+            ko.cleanNode(container[0]);

+            var fwVm = new quickSettingViewModel();

+            ko.applyBindings(fwVm, container[0]);

+            

+            $('#quickSettingForm').validate({

+                submitHandler:function () {

+                    if (fwVm.currentStep() < 5) {

+                        fwVm.next();

+                    } else {

+                        fwVm.save();

+                    }

+                },

+                rules:{

+                    txtAPN:"apn_check",

+                    txtIPv6APN:"apn_check",

+                    txtSSID:'ssid',

+                    pwdWepKey:{wifi_wep_password_check:true,wifi_password_check: true},

+                    txtWepKey:{wifi_wep_password_check:true,wifi_password_check: true},

+                    txtWPAKey:'wifi_password_check',

+                    codeWPAKey:'wifi_password_check',

+                    txtUserName:'ppp_username_check',

+                    txtIPv6UserName:'ppp_username_check',

+                    txtSecretCode:"ppp_secretcode_check",

+                    txtIPv6SecretCode:"ppp_secretcode_check"

+                },

+                errorPlacement:function (error, element) {

+                    var id = element.attr("id");

+                    if (id == "pwdWepKey" || id == "txtWepKey"){

+						error.insertAfter("#lblShowWepPassword");

+					} else if (id == "txtWPAKey" || id == "codeWPAKey") {

+                        error.insertAfter("#lblShowWifiPassword");

+                    } else {

+                        error.insertAfter(element);

+                    }

+                }

+            });

+        }

+

+        return {

+            init:init

+        };

+    }

+);

+

+define("main","set service knockout underscore jquery statusBar echarts".split(" "), function (set, fnc, libko, libus, libjq, barStat, echarts) {

+

+    var chartOptions = {

+        color: ['red', 'red', 'red', 'red', 'red'],	

+        series: [{

+                name: 'Á÷Á¿¿ØÖÆ',

+                type: 'pie',

+                radius: ['0', '72'],

+                itemStyle: {

+                    normal: {

+                        label: {

+                            show: false

+                        },

+                        labelLine: {

+                            show: false

+                        }

+                    }

+                },

+                data: [],

+                selectedOffset: 3

+            }

+        ],

+		animation: false,

+        title: {

+            text: '',

+            x: 'center',

+            y: 'center',

+            itemGap: 0,

+            textStyle: {

+                color: '#FFF',

+                fontFamily: '΢ÈíÑźÚ',

+                fontSize: 20,

+                fontWeight: 'bolder'

+            },

+            subtextStyle: {

+                color: '#FFF',

+                fontFamily: '΢ÈíÑźÚ',

+                fontSize: 16,

+                fontWeight: 'bolder'

+            }

+        },

+        tooltip: {

+            formatter: "{b}"

+        },

+    };

+	var languageOld = window.language;

+	var num_refresh = 0;

+	var traffic_graphic_chart = null;

+    var connStat = {

+        CONNECTED: 1,

+        DISCONNECTED: 2,

+        CONNECTING: 3,

+        DISCONNECTING: 4

+    };

+	function init() {

+        num_refresh = 0;

+        homeUtil.oldUsedData = null;

+        homeUtil.oldAlarmData = null;

+        traffic_graphic_chart = echarts.init(libjq("#traffic_graphic")[0]);

+        var container = libjq('#container')[0];

+        libko.cleanNode(container);

+        var tmp = new VmHome();

+        libko.applyBindings(tmp, container);

+		var data = fnc.getLoginData();

+		var psw_flg = data.psw_changed;

+		if (psw_flg != "1") {

+			showConfirm("password_note_first_change", function () {

+                    window.location.hash = '#pwd_mode';

+                });

+			return;

+		}										

+    }

+    

+    var homeUtil = {

+        initStatus: null,

+        initShownStatus: function (data) {

+            this.initStatus = {};

+            var ipv6Mode = data.ipv6PdpType.toLowerCase().indexOf("v6") > 0;

+            if (set.RJ45_SUPPORT) {

+                var mode = checkCableMode(data.blc_wan_mode);

+                if (mode) {

+                    this.initStatus.showIpv6WanIpAddr = false;

+                    this.initStatus.showIpv4WanIpAddr = true;

+                } else if (set.IPV6_SUPPORT) {

+                    if (data.pdpType == "IP") {

+                        this.initStatus.showIpv6WanIpAddr = false;

+                        this.initStatus.showIpv4WanIpAddr = true;

+                    } else if (ipv6Mode) {

+                        if (data.ipv6PdpType == "IPv6") {

+                            this.initStatus.showIpv6WanIpAddr = true;

+                            this.initStatus.showIpv4WanIpAddr = false;

+                        } else {

+                            this.initStatus.showIpv6WanIpAddr = true;

+                            this.initStatus.showIpv4WanIpAddr = true;

+                        }

+                    }

+                } else {

+                    this.initStatus.showIpv6WanIpAddr = false;

+                    this.initStatus.showIpv4WanIpAddr = true;

+                }

+            } else {

+                if (set.IPV6_SUPPORT) {

+                    if (data.pdpType == "IP") {

+                        this.initStatus.showIpv6WanIpAddr = false;

+                        this.initStatus.showIpv4WanIpAddr = true;

+                    } else if (ipv6Mode) {

+                        if (data.ipv6PdpType == "IPv6") {

+                            this.initStatus.showIpv6WanIpAddr = true;

+                            this.initStatus.showIpv4WanIpAddr = false;

+                        } else {

+                            this.initStatus.showIpv6WanIpAddr = true;

+                            this.initStatus.showIpv4WanIpAddr = true;

+                        }

+                    }

+                } else {

+                    this.initStatus.showIpv6WanIpAddr = false;

+                    this.initStatus.showIpv4WanIpAddr = true;

+                }

+            }

+        },

+        wanIpGet: function (data) {

+            var addrInfo = {

+                wanIpAddress: '',

+                ipv6WanIpAddress: ''

+            };

+            addrInfo.wanIpAddress = verifyDeviceInfo(data.wanIpAddress);

+            addrInfo.ipv6WanIpAddress = verifyDeviceInfo(data.ipv6WanIpAddress);

+            return addrInfo;

+        },

+        cachedAPStationBasic: null,

+        cachedConnectionMode: null,

+        getCanConnectNetWork: function (param) {

+            var status = fnc.getStatusInfo();

+            if (status.simStatus != "modem_init_complete") {

+                return false;

+            }

+            var typeNetworkTmp = status.networkType.toLowerCase();

+            if (typeNetworkTmp == 'searching') {

+                return false;

+            }

+            if (typeNetworkTmp == '' || typeNetworkTmp == 'limited service') {

+                typeNetworkTmp = 'limited_service';

+            }

+            if (typeNetworkTmp == 'no service') {

+                typeNetworkTmp = 'no_service';

+            }

+            if (typeNetworkTmp == 'limited_service' || typeNetworkTmp == 'no_service') {

+                if (param.cStatus() != connStat.CONNECTED) {

+                    return false;

+                }

+            }

+            if (set.AP_STATION_SUPPORT) {

+                if (status.connectWifiStatus == "connect") {

+                    if (status.ap_station_mode == "wifi_pref") {

+                        return false;

+                    }

+                }

+            }

+            return true;

+        },

+        doConnect: function () {

+            showLoading('connecting');

+            fnc.connect({}, function (data) {

+                if (data.result) {

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+        },

+        refreshHomeData: function (param) {

+            var info = fnc.getConnectionInfo();

+            param.connectStatus(info.connectStatus);

+            param.canConnect(this.getCanConnectNetWork(param));

+            param.networkType(homeUtil.getNetworkType(info.networkType));

+            if (info.connectStatus == "ppp_connected") {

+                param.current_Flux(transUnit(parseInt(info.data_counter.currentReceived, 10) + parseInt(info.data_counter.currentSent, 10), false));

+                param.connected_Time(transSecond2Time(info.data_counter.currentConnectedTime));

+                param.up_Speed(transUnit(info.data_counter.uploadRate, true));

+                param.down_Speed(transUnit(info.data_counter.downloadRate, true));

+            } else {

+                param.current_Flux(transUnit(0, false));

+                param.connected_Time(transSecond2Time(0));

+                param.up_Speed(transUnit(0, true));

+                param.down_Speed(transUnit(0, true));

+            }

+            param.trafficAlertEnable(info.limitVolumeEnable);

+            if (info.limitVolumeEnable) {

+                if (info.limitVolumeType == '1') {

+                    param.trafficUsed(transUnit(parseInt(info.data_counter.monthlySent, 10) + parseInt(info.data_counter.monthlyReceived, 10), false));

+                    param.trafficLimited(transUnit(info.limitDataMonth, false));

+                } else {

+                    param.trafficUsed(transSecond2Time(info.data_counter.monthlyConnectedTime));

+                    param.trafficLimited(transSecond2Time(info.limitTimeMonth));

+                }

+            }

+            if (languageOld != window.language) {

+                languageOld = window.language;

+                num_refresh = 1;

+            }

+            if (param.showTraffic()) {

+                homeUtil.updateEcharts(info);

+            } else {

+                homeUtil.allFreeEcharts();

+            }

+            homeUtil.refreshStationInfo(param);

+        },

+        allFreeEcharts: function () {

+            var usedData = homeUtil.data.free;

+            usedData.value = 1;

+            usedData.selected = false;

+            usedData.name = libjq.i18n.prop("echarts_no");

+            chartOptions.series[0].data = [usedData];

+            chartOptions.title.text = '';

+            homeUtil.setEcharts(chartOptions, libjq.i18n.prop("echarts_no"));

+        },

+        getNetworkType: function (networkType) {

+            var typeNetworkTmp = networkType.toLowerCase();

+            if (typeNetworkTmp == '' || typeNetworkTmp == 'limited service') {

+                typeNetworkTmp = 'limited_service';

+            }

+            if (typeNetworkTmp == 'no service') {

+                typeNetworkTmp = 'no_service';

+            }

+            if (typeNetworkTmp == 'limited_service' || typeNetworkTmp == 'no_service') {

+                return libjq.i18n.prop("network_type_" + typeNetworkTmp);

+            } else {

+                return networkType;

+            }

+        },

+        data: {

+            full: {

+                value: 30,

+                name: 'Á÷Á¿³¬³ö',

+                itemStyle: {

+                    normal: {

+                        color: '#DF4313'

+                    }

+                }

+            },		

+            used: {

+                value: 30,

+                name: 'ÒÑʹÓÃ',

+                itemStyle: {

+                    normal: {

+                        color: '#8CC916'

+                    }

+                }

+            },

+            left1: {

+                value: 50,

+                name: 'ÌáÐÑÖµÄÚδʹÓÃ',

+                itemStyle: {

+                    normal: {

+                        color: '#D8D8D8'

+                    }

+                }

+            },

+            free: {

+                value: 50,

+                name: 'δʹÓÃ',

+                itemStyle: {

+                    normal: {

+                        color: '#D8D8D8'

+                    }

+                }

+            },

+            alert: {

+                value: 1,

+                name: 'ÌáÐÑÖµ',

+                itemStyle: {

+                    normal: {

+                        color: '#FF5500'

+                    }

+                }

+            },

+            alarm: {

+                value: 19.7,

+                name: '¾¯½äÇø',

+                itemStyle: {

+                    normal: {

+                        color: '#8CC916'

+                    }

+                }

+            },

+            start: {

+                value: 50,

+                name: 'ÌáÐÑÖµÄÚδʹÓÃ',

+                itemStyle: {

+                    normal: {

+                        color: '#D8D8D8'

+                    }

+                }

+            },

+        },

+		getDataInfo: function (value) {

+            return {

+                data: /\d+(.\d+)?/.exec(value)[0],

+                unit: /[A-Z]{1,2}/.exec(value)[0]

+            }

+        },

+        oldAlarmData: null,

+        oldUsedData: null,

+        updateEcharts: function (info) {

+            var startName = libjq.i18n.prop("echarts_no");

+            num_refresh++;

+            if (num_refresh % 10 != 2) {

+                return false;

+            }

+            var total = 0,

+            used = 0,

+            reach = 0,

+            left = 0,

+            alarm = 0,

+            left1 = 0;

+            if (info.limitVolumeEnable) {

+                startName = libjq.i18n.prop("echarts_used");

+                chartOptions.series[0].data = [];

+                if (info.limitVolumeType == '1') {

+                    var limitedDataFormatted = transUnit(info.limitDataMonth, false);

+                    chartOptions.series[0].data = [];

+                    if (info.limitDataMonth == 0) {

+                        var usedData = homeUtil.data.used;

+                        usedData.value = 1;

+                        usedData.selected = false;

+                        usedData.name = libjq.i18n.prop("echarts_used");

+                        chartOptions.series[0].data.push(usedData);

+                    } else {

+                        var dataInfo = homeUtil.getDataInfo(limitedDataFormatted);

+                        total = dataInfo.data * homeUtil.getUnitValue(dataInfo.unit) * 1048576;

+                        used = parseInt(info.data_counter.monthlySent, 10) + parseInt(info.data_counter.monthlyReceived, 10);

+                        reach = total * info.limitVolumePercent / 100;

+                        if (used >= total) {

+                            var fullData = homeUtil.data.full;

+                            fullData.value = 100;

+                            fullData.name = libjq.i18n.prop("echarts_full");

+                            chartOptions.series[0].data.push(fullData);

+                            startName = libjq.i18n.prop("echarts_full");

+                        } else {

+                            if (reach - used > 0) {

+                                left1 = reach - used;

+                                left = total - reach;

+                            } else {

+                                alarm = used - reach;

+                                left = total - used;

+                            }

+                            var usedData = homeUtil.data.used;

+                            if (reach - used > 0) {

+                                usedData.value = used;

+                            } else {

+                                usedData.value = reach;

+                            }

+                            usedData.name = libjq.i18n.prop("echarts_used");

+                            chartOptions.series[0].data.push(usedData);

+                            if (left1 > 0) {

+                                var left1Data = homeUtil.data.left1;

+                                left1Data.value = left1;

+                                left1Data.name = libjq.i18n.prop("echarts_left1");

+                                chartOptions.series[0].data.push(left1Data);

+                            }

+                            var alertData = homeUtil.data.alert;

+                            alertData.value = total / 200;

+                            alertData.name = libjq.i18n.prop("echarts_alert");

+                            chartOptions.series[0].data.push(alertData);

+                            if (alarm > 0) {

+                                var alarmData = homeUtil.data.alarm;

+                                alarmData.value = alarm;

+                                alarmData.name = libjq.i18n.prop("echarts_alarm");

+                                chartOptions.series[0].data.push(alarmData);

+                            }

+                            var freeData = homeUtil.data.free;

+                            freeData.value = left;

+                            freeData.name = libjq.i18n.prop("echarts_free");

+                            chartOptions.series[0].data.push(freeData);

+                        }

+                    }

+                } else {

+                    chartOptions.series[0].data = [];

+                    if (info.limitTimeMonth == 0) {

+                        var usedData = homeUtil.data.used;

+                        usedData.value = 1;

+                        usedData.selected = false;

+                        usedData.name = libjq.i18n.prop("echarts_used");

+                        chartOptions.series[0].data.push(usedData);

+                    } else {

+                        total = info.limitTimeMonth;

+                        used = info.data_counter.monthlyConnectedTime;

+                        reach = total * info.limitVolumePercent / 100;

+                        if (used >= total) {

+                            var fullTime = homeUtil.data.full;

+                            fullTime.value = 100;

+                            fullTime.name = libjq.i18n.prop("echarts_full");

+                            chartOptions.series[0].data.push(fullTime);

+                            startName = libjq.i18n.prop("echarts_full");

+                        } else {

+                            if (reach - used > 0) {

+                                left1 = reach - used;

+                                left = total - reach;

+                            } else {

+                                alarm = used - reach;

+                                left = total - used;

+                            }

+                            var usedTime = homeUtil.data.used;

+                            if (reach - used > 0) {

+                                usedTime.value = used;

+                            } else {

+                                usedTime.value = reach;

+                            }

+                            usedTime.name = libjq.i18n.prop("echarts_used");

+                            chartOptions.series[0].data.push(usedTime);

+                            if (left1 > 0) {

+                                var left1Time = homeUtil.data.left1;

+                                left1Time.value = left1;

+                                left1Time.name = libjq.i18n.prop("echarts_left1");

+                                chartOptions.series[0].data.push(left1Time);

+                            }

+                            var alertTime = homeUtil.data.alert;

+                            alertTime.value = total / 200;

+                            alertTime.name = libjq.i18n.prop("echarts_alert");

+                            chartOptions.series[0].data.push(alertTime);

+                            if (alarm > 0) {

+                                var alarmTime = homeUtil.data.alarm;

+                                alarmTime.value = alarm;

+                                alarmTime.name = libjq.i18n.prop("echarts_alarm");

+                                chartOptions.series[0].data.push(alarmTime);

+                            }

+                            var freeTime = homeUtil.data.free;

+                            freeTime.value = left;

+                            freeTime.name = libjq.i18n.prop("echarts_free");

+                            chartOptions.series[0].data.push(freeTime);

+                        }

+                    }

+                }

+            } else {

+                var usedData = homeUtil.data.used;

+                usedData.value = 1;

+                usedData.selected = false;

+                usedData.name = libjq.i18n.prop("echarts_no");

+                chartOptions.series[0].data = [usedData];

+                chartOptions.title.text = '';

+            }

+            var firstEle = libus.find(chartOptions.series[0].data, function (n) {

+                return n.name == libjq.i18n.prop("echarts_used");

+            });

+            var alarmEle = libus.find(chartOptions.series[0].data, function (n) {

+                return n.name == libjq.i18n.prop("echarts_alarm");

+            });

+            if (!alarmEle) {

+                alarmEle = {

+                    value: 0

+                };

+            }

+            if (typeof firstEle == "undefined") {

+                homeUtil.setEcharts(chartOptions, startName);

+            } else if (homeUtil.oldUsedData != firstEle.value || homeUtil.oldAlarmData != alarmEle.value) {

+                homeUtil.oldUsedData = firstEle.value;

+                homeUtil.oldAlarmData = alarmEle.value;

+                homeUtil.setEcharts(chartOptions, startName);

+            }

+        },

+        getUnitValue: function (unit) {

+            unit = unit.toUpperCase();

+            if (unit == 'GB') {

+                return '1024';

+            } else if (unit == 'TB') {

+                return '1048576';

+            } else {

+                return '1';

+            }

+        },		

+        setEcharts: function (options, startName) {

+            var startPart = homeUtil.data.start;

+            startPart.value = 0;

+            startPart.name = startName;

+            startPart.selected = false;

+            var arr = [startPart].concat(options.series[0].data);

+            options.series[0].data = arr;

+            traffic_graphic_chart.setOption(options, true);

+            addTimeout(function () {

+                traffic_graphic_chart.resize();

+            }, 1000);

+        },

+        refreshStationInfo: function (param) {

+            param.wirelessDeviceNum(fnc.getStatusInfo().wirelessDeviceNum);

+            if (num_refresh % 10 == 2) {

+                fnc.getAttachedCableDevices({}, function (data) {

+                    param.wireDeviceNum(data.attachedDevices.length);

+                });

+            }

+        },		

+        getUnit: function (val) {

+            if (val == '1024') {

+                return 'GB';

+            } else if (val == '1048576') {

+                return 'TB';

+            } else {

+                return 'MB';

+            }

+        },

+        refreshOpmodeInfo: function (param) {

+            var obj = fnc.getOpMode();

+            param.isLoggedIn(obj.loginfo == "ok");

+            var currentMode = checkCableMode(obj.blc_wan_mode);

+            if (param.opCurMode() && !currentMode) {

+                var data = fnc.getLoginData();

+                var state = data.modem_main_state;

+                if (state == "modem_sim_undetected" || state == "modem_undetected" || state == "modem_sim_destroy" || state == "modem_waitpin" || state == "modem_waitpuk" || state == "modem_imsi_waitnck") {

+                    window.location.reload();

+                    return;

+                }

+            }

+            param.opCurMode(currentMode);

+            if (currentMode && obj.ethwan_mode == "DHCP") {

+                param.enableFlag(false);

+            } else if ((!currentMode && obj.ppp_status != "ppp_disconnected") || (currentMode && obj.rj45_state != "idle" && obj.rj45_state != "dead")) {

+                param.enableFlag(true);

+            } else {

+                param.enableFlag(false);

+            }

+            var mode = (obj.blc_wan_mode == "AUTO_PPP" || obj.blc_wan_mode == "AUTO_PPPOE") ? "AUTO" : obj.blc_wan_mode;

+            var currentOpMode = "";

+            switch (mode) {

+            case "AUTO":

+                currentOpMode = "opmode_auto";

+                break;

+            case "PPPOE":

+                currentOpMode = "opmode_cable";

+                break;

+            case "PPP":

+                currentOpMode = "opmode_gateway";

+                break;

+            default:

+                break;

+            }

+            libjq("#opmode").attr("data-trans", currentOpMode).text(libjq.i18n.prop(currentOpMode));

+            param.isShowHomeConnect(!currentMode);

+            param.showTraffic(set.TRAFFIC_SUPPORT && !currentMode);

+            param.isSupportQuicksetting(set.HAS_QUICK_SETTING && !currentMode);

+        }

+    };

+	function VmHome() {

+        var target = this;

+        target.hasSms = set.HAS_SMS;

+        target.hasPhonebook = set.HAS_PHONEBOOK;

+        target.isSupportSD = set.SD_CARD_SUPPORT;

+        target.isCPE = set.PRODUCT_TYPE == 'CPE';

+        target.hasRj45 = set.RJ45_SUPPORT;

+        target.notDataCard = set.PRODUCT_TYPE != 'DATACARD';

+        target.hasParentalControl = set.HAS_PARENTAL_CONTROL;

+        var wifiInfo = fnc.getWifiBasic();

+        if (set.WIFI_SUPPORT_QR_SWITCH) {

+            target.showQRCode = set.WIFI_SUPPORT_QR_CODE && wifiInfo.show_qrcode_flag;

+        } else {

+            target.showQRCode = set.WIFI_SUPPORT_QR_CODE;

+        }

+        target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + libjq.now();

+        if (target.hasRj45) {

+            var opModeObj = checkCableMode(fnc.getOpMode().blc_wan_mode);

+            target.opCurMode = libko.observable(opModeObj);

+            target.isShowHomeConnect = libko.observable(!opModeObj);

+            target.showTraffic = libko.observable(set.TRAFFIC_SUPPORT && !opModeObj);

+            target.isSupportQuicksetting = libko.observable(set.HAS_QUICK_SETTING && !opModeObj);

+        } else {

+            target.isShowHomeConnect = libko.observable(true);

+            target.showTraffic = libko.observable(set.TRAFFIC_SUPPORT);

+            target.isSupportQuicksetting = libko.observable(set.HAS_QUICK_SETTING);

+        }

+        if (set.PRODUCT_TYPE == 'DATACARD') {

+            libjq('#home_image').addClass('data-card');

+        }

+        var info = fnc.getConnectionInfo();

+        target.networkType = libko.observable(homeUtil.getNetworkType(info.networkType));

+        target.connectStatus = libko.observable(info.connectStatus);

+        target.canConnect = libko.observable(false);

+        target.cStatus = libko.computed(function () {

+            if (target.connectStatus().indexOf('_connected') != -1) {

+                return connStat.CONNECTED;

+            } else if (target.connectStatus().indexOf('_disconnecting') != -1) {

+                return connStat.DISCONNECTING;

+            } else if (target.connectStatus().indexOf('_connecting') != -1) {

+                return connStat.CONNECTING;

+            } else {

+                return connStat.DISCONNECTED;

+            }

+        });

+        target.current_Flux = libko.observable(transUnit(0, false));

+        target.connected_Time = libko.observable(transSecond2Time(0));

+        target.up_Speed = libko.observable(transUnit(0, true));

+        target.down_Speed = libko.observable(transUnit(0, true));

+        target.isLoggedIn = libko.observable(false);

+        target.enableFlag = libko.observable(true);

+        target.simSerialNumber = libko.observable('');

+        target.imei = libko.observable('');

+        target.imsi = libko.observable('');

+        target.ssid = libko.observable('');

+        target.hasWifi = set.HAS_WIFI;

+        target.showMultiSsid = libko.observable(set.HAS_MULTI_SSID && wifiInfo.multi_ssid_enable == "1");

+        target.trafficAlertEnable = libko.observable(false);

+        target.trafficUsed = libko.observable('');

+        target.trafficLimited = libko.observable('');

+        target.wireDeviceNum = libko.observable(fnc.getAttachedCableDevices().attachedDevices.length);

+        target.wirelessDeviceNum = libko.observable(fnc.getStatusInfo().wirelessDeviceNum);

+        target.showOpModeWindow = function () {

+            if (target.enableFlag()) {

+                return;

+            }

+            showSettingWindow("change_mode", "opmode_popup", "opmode_popup", 400, 300, function () {});

+        };

+        target.currentOpMode = libko.observable("0");

+        var popoverShown = false;

+        libjq('#showDetailInfo').popover({

+            html: true,

+            placement: 'top',

+            trigger: 'focus',

+            title: function () {

+                return libjq.i18n.prop('device_info')

+            },

+            content: function () {

+                return getDetailInfoContent();

+            }

+        }).on('shown.bs.popover', function () {

+            popoverShown = true;

+        }).on('hidden.bs.popover', function () {

+            popoverShown = false;

+        });

+        function fetchDeviceInfo() {

+            var data = fnc.getDeviceInfo();

+            target.simSerialNumber(verifyDeviceInfo(data.simSerialNumber));

+            target.imei(verifyDeviceInfo(data.imei));

+            target.imsi(verifyDeviceInfo(data.imsi));

+            target.ssid(verifyDeviceInfo(data.ssid));

+            target.showMultiSsid(set.HAS_MULTI_SSID && data.multi_ssid_enable == "1");

+            return data;

+        }

+        fetchDeviceInfo();

+        function getDetailInfoContent() {

+            var data = fetchDeviceInfo();

+            homeUtil.initShownStatus(data);

+            var addrInfo = homeUtil.wanIpGet(data);

+            var compiled = libus.template(libjq("#detailInfoTmpl").html());

+            var tmpl = compiled({

+                simSerialNumber: verifyDeviceInfo(data.simSerialNumber),

+                imei: verifyDeviceInfo(data.imei),

+                imsi: verifyDeviceInfo(data.imsi),

+                signal: signalFormat(data.signal),

+                hasWifi: set.HAS_WIFI,

+                isCPE: set.PRODUCT_TYPE == 'CPE',

+                hasRj45: set.RJ45_SUPPORT,

+                showMultiSsid: set.HAS_MULTI_SSID && data.multi_ssid_enable == "1",

+                ssid: verifyDeviceInfo(data.ssid),

+                max_access_num: verifyDeviceInfo(data.max_access_num),

+                m_ssid: verifyDeviceInfo(data.m_ssid),

+                m_max_access_num: verifyDeviceInfo(data.m_max_access_num),

+                wifi_long_mode: "wifi_des_" + data.wifiRange,

+                lanDomain: verifyDeviceInfo(data.lanDomain),

+                ipAddress: verifyDeviceInfo(data.ipAddress),

+                showMacAddress: set.SHOW_MAC_ADDRESS,

+                macAddress: verifyDeviceInfo(data.macAddress),

+                showIpv4WanIpAddr: homeUtil.initStatus.showIpv4WanIpAddr,

+                wanIpAddress: addrInfo.wanIpAddress,

+                showIpv6WanIpAddr: homeUtil.initStatus.showIpv6WanIpAddr,

+                ipv6WanIpAddress: addrInfo.ipv6WanIpAddress,

+                sw_version: verifyDeviceInfo(data.sw_version),

+                hw_version: verifyDeviceInfo(data.hw_version)

+            });

+            return libjq(tmpl).translate();

+        }

+        target.connectHandler = function () {

+            if (target.connectStatus() == "ppp_connected") {

+                showLoading('disconnecting');

+                fnc.disconnect({}, function (data) {

+                    if (data.result) {

+                        successOverlay();

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            } else {

+                if (fnc.getStatusInfo().roamingStatus) {

+                    showConfirm('dial_roaming_connect', function () {

+                        target.connect();

+                    });

+                } else {

+                    target.connect();

+                }

+            }

+        };

+        target.connect = function () {

+            var statusInfo = fnc.getStatusInfo();

+            var trafficResult = barStat.getTrafficResult(statusInfo);

+            if (statusInfo.limitVolumeEnable && trafficResult.showConfirm) {

+                var confirmMsg = null;

+                if (trafficResult.usedPercent > 100) {

+                    confirmMsg = {

+                        msg: 'traffic_beyond_connect_msg'

+                    };

+                    barStat.setTrafficAlertPopuped(true);

+                } else {

+                    confirmMsg = {

+                        msg: 'traffic_limit_connect_msg',

+                        params: [trafficResult.limitPercent]

+                    };

+                    barStat.setTrafficAlert100Popuped(false);

+                }

+                showConfirm(confirmMsg, function () {

+                    homeUtil.doConnect();

+                });

+            } else {

+                homeUtil.doConnect();

+            }

+        };

+        fnc.getSignalStrength({}, function (data) {

+            var signalTxt = signalFormat(convertSignal(data));

+            libjq("#fresh_signal_strength").text(signalTxt);

+            if (popoverShown) {

+                libjq("#popoverSignalTxt").text(signalTxt);

+            }

+        });

+        homeUtil.refreshHomeData(target);

+        addInterval(function () {

+            fnc.getSignalStrength({}, function (data) {

+                var signalTxt = signalFormat(convertSignal(data));

+                libjq("#fresh_signal_strength").text(signalTxt);

+                if (popoverShown) {

+                    libjq("#popoverSignalTxt").text(signalTxt);

+                }

+            });

+            homeUtil.refreshHomeData(target);

+        }, 1000);

+        if (target.hasRj45) {

+            homeUtil.refreshOpmodeInfo(target);

+            addInterval(function () {

+                homeUtil.refreshOpmodeInfo(target);

+            }, 1000);

+        }

+        target.showNetworkSettingsWindow = function () {

+            if (target.hasRj45) {

+                fnc.getOpMode({}, function (data) {

+                    var mode = checkCableMode(data.blc_wan_mode);

+                    if (mode) {

+                        window.location.hash = '#network_set';

+                    } else {

+                        window.location.hash = '#conn_set';

+                    }

+                });

+            } else {

+                window.location.hash = '#conn_set';

+            }

+        }

+    };

+    return {

+        init: init

+    };

+});

+

+

+define("language","knockout service jquery set underscore".split(" "), 

+    function(ko, service, $, config, _) {

+

+    //  »ñÈ¡µ±Ç°ÓïÑÔÏî

+    function getCurrentLanguage() {

+        return service.getLanguage();

+    }		

+

+    //  ¸ù¾ÝÓïÑÔÏî¼ÓÔØÓïÑÔ×ÊÔ´²¢·­ÒëÒ³ÃæÉϵÄbody²¿·Ö

+    //  @param {String} current ÓïÑÔÏî:zh-cn

+    function loadLanguageAndRefresh(current){

+        window.CURRENT_LANGUAGE = current;

+        $("body").attr('lang', current);

+        $.i18n.properties({

+            name:'Messages',

+            path:'i18n/',

+            mode:'map',

+            cache: true,

+            language:current,

+            callback: function() {

+                jQuery.validator.messages = $.i18n.map;

+                $('body').translate();

+            }

+        });

+    }

+    

+	window.language = null;

+	

+

+    function LanguageViewModel() {

+        var target = this;

+        var currentLan = getCurrentLanguage();

+        var languages = _.map(config.LANGUAGES, function(item) {

+            return new Option(item.name, item.value);

+        });

+

+        document.title = config.WEBUI_TITLE;

+        if($('#webui_title')[0]) {

+            $('#webui_title').html(config.WEBUI_TITLE);

+        }

+

+        target.languages   = ko.observableArray(languages);

+        target.currentLan = ko.observable(currentLan.Language);

+		window.language      = target.currentLan();

+

+        //  Çл»ÓïÑÔʼþ´¦Àí

+        //  @event langChangeHandler 

+        target.langChangeHandler = function(info, event) {

+            clearValidateMsg();

+

+            service.setLanguage({Language: target.currentLan()}, function() {

+                loadLanguageAndRefresh(target.currentLan());

+				window.language = target.currentLan();

+            });

+        };

+

+        // ¼ÓÔØÓïÑÔÁÐ±í²¢Ë¢Ð½çÃæ

+        loadLanguageAndRefresh(target.currentLan());

+    }

+

+    //  ³õʼ»¯ÓïÑÔVM²¢°ó¶¨

+    function init() {

+        ko.applyBindings(new LanguageViewModel(), $('#language')[0]);

+    }

+

+    return {

+        init: init

+    };

+});

+

+

+// µÇ½ Ä£¿é

+define("entry","jquery knockout set service underscore menu logout CryptoJS".split(" "), 

+	function($, ko,config, service, _, menu, logout, CryptoJS) {

+	

+

+        var pageState      = {LOGIN:0, WAIT_PIN:1, WAIT_PUK:2, PUK_LOCKED:3, LOGGEDIN:4, LOADING:5};

+        var timer          = loginStatusCheckingTimer();

+        var loginLockTimer = 0;

+        var lastLoginStatus = "0";

+        

+        function loginViewModel() {

+            var target        = this;

+            var data        = service.getLoginData();

+            var loginStatus = service.getLoginStatus();

+

+            target.confirmPIN           = ko.observable();	

+            target.leftSeconds          = ko.observable(0);				

+            target.loginCount           = ko.observable(0);

+            target.loginSecuritySupport = ko.observable(config.LOGIN_SECURITY_SUPPORT);

+            target.newPIN               = ko.observable();			

+            target.password             = ko.observable();

+            target.PIN                  = ko.observable();

+            target.pinNumber            = ko.observable(data.pinnumber);			

+            target.PUK                  = ko.observable();

+            target.pukNumber            = ko.observable(data.puknumber);	

+            target.showEntrance         = ko.observable(false);

+            target.sharePathInvalid     = ko.observable(false);			

+            target.uiLoginTimer         = ko.observable(300);

+

+            // ×¢Òâ˳Ðò£¬µ÷ÕûÇ°Ãæ»áÎÞ·¨Ë¢Ð³ö½çÃæ

+            target.accountLocked        = ko.computed(function () {

+                return target.loginCount() == config.MAX_LOGIN_COUNT && target.leftSeconds() != '-1';

+            });			

+			

+            target.leftUnlockTime       = ko.computed(function () {

+                target.leftSeconds();

+                var formatted = transSecond2Time(target.uiLoginTimer());

+                return formatted.substring(formatted.indexOf(':') + 1, formatted.length);

+            });

+

+

+            if(config.SD_CARD_SUPPORT){

+                service.getSDConfiguration({}, function (data) {

+                    target.showEntrance(data.sd_status == "1" && data.share_status == "1" && data.sd_mode == "0");

+                    if(target.showEntrance()){

+                        service.checkFileExists({

+                            path: data.share_file

+                        }, function (data1) {

+                            if (data1.status == 'exist' || data1.status == 'processing') {

+                                target.sharePathInvalid(false);

+                            } else {

+                                target.sharePathInvalid(true);

+                            }

+                        });

+                    }

+                });

+            }

+

+            var state = computePageState(loginStatus, data);

+            target.pageState = ko.observable(state);

+            if (state == pageState.LOADING) {

+                addTimeout(refreshPage, 500);

+            }

+            setFocus();

+

+            

+            // login ʼþ´¦Àí

+            

+            target.login = function () {

+                if(config.LOGIN_SECURITY_SUPPORT && target.accountLocked()){

+                    showAlert("password_error_account_lock_time", function () {

+                        setFocus();

+                    });

+                    return false;

+                }

+                target.pageState(pageState.LOADING);

+                window.clearInterval(timer);

+                var ciphertext = "";

+                if (config.PASSWORD_ENCODE) {

+		    ciphertext = target.password();

+		} else {

+                    var kparam = service.getDeviceInfoLow();

+                    var tkey = CryptoJS.enc.Latin1.parse(kparam.skey);

+		    var tiv = CryptoJS.enc.Latin1.parse(kparam.siv);

+                    ciphertext = CryptoJS.AES.encrypt(target.password(), tkey, {

+                        iv: tiv,

+                        mode: CryptoJS.mode.CBC,

+                        padding: CryptoJS.pad.ZeroPadding

+                        }).toString();

+		}

+                service.login({

+                    password:ciphertext

+                }, function (info) {

+                    setTimeout(function () {

+                        timer = loginStatusCheckingTimer();

+                    }, 1300);

+                    if (info.result) {

+                        target.pageState(pageState.LOGGEDIN);

+                        if(config.LOGIN_SECURITY_SUPPORT){

+                            target.loginCount(0);

+                            target.uiLoginTimer(300);

+                            clearInterval(loginLockTimer);

+                        }

+                        $("#container").empty();

+                        window.location.hash = "#main";

+                        logout.init();

+                    } else {

+                        target.password("");

+                        if(config.LOGIN_SECURITY_SUPPORT){

+                            target.checkLoginData(function(){

+                                if (target.loginCount() == config.MAX_LOGIN_COUNT) {

+                                    showAlert("password_error_five_times", function () {

+                                        setFocus();

+                                    });

+                                    target.startLoginLockInterval();

+                                } else {

+                                    showAlert({msg: 'password_error_left', params: [config.MAX_LOGIN_COUNT - target.loginCount()]}, function () {

+                                        setFocus();

+                                    });

+                                }

+                            });

+                        }else {

+                            showAlert("password_error", function () {

+                                setFocus();

+                            });

+                        }

+                        target.pageState(pageState.LOGIN);

+                    }

+                });

+            };

+

+            

+

+            

+            // »ñÈ¡µÇ¼Ïà¹ØÐÅÏ¢          

+            target.checkLoginData = function(cb){

+                service.getLoginData({}, function(r){

+                    var failTimes = parseInt(r.psw_fail_num_str, 10);

+                    target.loginCount(config.MAX_LOGIN_COUNT - failTimes);

+                    target.leftSeconds(r.login_lock_time);

+                    target.uiLoginTimer(r.login_lock_time);

+                    if($.isFunction(cb)){

+                        cb();

+                    } else if (target.loginCount() == config.MAX_LOGIN_COUNT) {

+                        target.startLoginLockInterval();

+                    }

+                });

+            };

+            

+            // Æô¶¯µ¹¼ÆÊ±¶¨Ê±Æ÷¡£

+            target.startLoginLockInterval = function () {

+                loginLockTimer = setInterval(function () {

+                    service.getLoginData({}, function (data) {

+                        if (data.login_lock_time <= 0 || data.psw_fail_num_str == 5) {

+                            target.loginCount(0);

+                            clearInterval(loginLockTimer);

+                        }

+                        if(target.leftSeconds() != data.login_lock_time){

+                            target.leftSeconds(data.login_lock_time);

+                            target.uiLoginTimer(data.login_lock_time);

+                        } else {

+                            target.uiLoginTimer(target.uiLoginTimer() > 0 ? target.uiLoginTimer() - 1 : 0);

+                        }

+                    });

+                }, 1000);

+            };            

+

+            target.checkLoginData();

+

+

+            

+            // ÑéÖ¤ÊäÈëPINʼþ´¦Àí

+            target.enterPIN = function () {

+                target.pageState(pageState.LOADING);

+                var pin = target.PIN();

+                service.enterPIN({

+                    PinNumber:pin

+                }, function (data) {

+                    if (!data.result) {

+                        showAlert("pin_error", function () {

+                            refreshPage();

+                        });

+                        target.PIN('');

+                    } else {

+                        refreshPage();

+                    }

+                });

+            };

+

+            function setFocus(){

+                setTimeout(function () {

+                    var txtAdmin = $('#txtAdmin:visible');

+                    var txtPIN = $('#txtPIN:visible');

+                    var txtPUK = $('#txtPUK:visible');

+                    if (txtAdmin.length > 0) {

+                        txtAdmin.focus();

+                    } else if (txtPIN.length > 0) {

+                        txtPIN.focus();

+                    } else if (txtPUK.length > 0) {

+                        txtPUK.focus();

+                    }

+                }, 100);

+            }            

+

+            

+            // Ë¢ÐÂÒ³Ãæ×´Ì¬           

+            function refreshPage() {

+                var data = service.getLoginData();

+                var loginStatus = service.getLoginStatus();

+                var state = computePageState(loginStatus, data);

+                if (state == pageState.LOADING) {

+                    addTimeout(refreshPage, 500);

+                } else {

+                    target.pageState(state);

+                    target.pinNumber(data.pinnumber);

+                    target.pukNumber(data.puknumber);

+                }

+                setFocus();

+            }

+

+            // ÊäÈëPUKÉèÖÃÐÂPINʼþ´¦Àí

+            target.enterPUK = function () {

+                target.pageState(pageState.LOADING);

+                var newPIN = target.newPIN();

+                var confirmPIN = target.confirmPIN();

+                var params = {};

+                params.PinNumber = newPIN;

+                params.PUKNumber = target.PUK();

+                service.enterPUK(params, function (data) {

+                    if (!data.result) {

+                        showAlert("puk_error", function () {

+                            refreshPage();

+                        });

+                        target.PUK('');

+                        target.newPIN('');

+                        target.confirmPIN('');

+                    } else {

+                        refreshPage();

+                    }

+                });

+            };            

+

+

+

+            // ¸ù¾ÝµÇ¼״̬ºÍSIM¿¨×´Ì¬·µ»ØÒ³Ãæ×´Ì¬

+            function checkPinAfterLogin(loginStatus, data) {

+                if (loginStatus.status == "loggedIn") {

+                    var currentState = data.modem_main_state; // cov_2

+                    if (currentState == "modem_waitpin") {

+                        return pageState.WAIT_PIN;

+                    } else if ((currentState == "modem_waitpuk" || data.pinnumber == 0) && (data.puknumber != 0)) {

+                        return pageState.WAIT_PUK;

+                    } else if ((data.puknumber == 0 || currentState == "modem_sim_destroy")

+                        && currentState != "modem_sim_undetected" && currentState != "modem_undetected") {

+                        return pageState.PUK_LOCKED;

+                    } else {

+                        return pageState.LOGGEDIN;

+                    }

+                } else {

+                    var currentState = data.modem_main_state;

+                    if ($.inArray(currentState, config.TEMPORARY_MODEM_MAIN_STATE) != -1) {

+                        return pageState.LOADING;

+                    } else {

+                        return pageState.LOGIN;

+                    }

+                }

+            }			

+            

+            // ¸ù¾ÝµÇ¼״̬ºÍSIM¿¨×´Ì¬ÉèÖÃÒ³Ãæ×´Ì¬

+            function computePageState(loginStatus, data) {

+                //PX-880 ÏȵǼÔÙ½øÐÐPINÑéÖ¤£¬ÓÉÓÚrouterÉè¼ÆÔ­Òò£¬µÇ¼ºó£¬PINÑéÖ¤²»ÔÚµÇÂ¼Ò³Ãæ½øÐУ¬ºÍÊý¾Ý¿¨µÄÑéÖ¤±£³ÖÒ»Ö¡£

+                if (config.LOGIN_THEN_CHECK_PIN) {

+                    return checkPinAfterLogin(loginStatus, data);

+                } else {

+                    return loginAfterCheckPin(loginStatus, data);

+                }

+            }

+			

+            // ¸ù¾ÝµÇ¼״̬ºÍSIM¿¨×´Ì¬·µ»ØÒ³Ãæ×´Ì¬

+            function loginAfterCheckPin(loginStatus, data) {

+                if (loginStatus.status == "loggedIn") {

+                    return pageState.LOGGEDIN;

+                } else {

+                    var currentState = data.modem_main_state;

+						if ($.inArray(currentState, config.TEMPORARY_MODEM_MAIN_STATE) != -1) {

+							return pageState.LOADING;

+						} else if (currentState == "modem_waitpin") {

+							return pageState.WAIT_PIN;

+						} else if ((currentState == "modem_waitpuk" || parseInt(data.pinnumber) === 0) && (parseInt(data.puknumber) != 0)) {

+							return pageState.WAIT_PUK;

+						} else if ((parseInt(data.puknumber) === 0 || currentState == "modem_sim_destroy") && currentState != "modem_sim_undetected" && currentState != "modem_undetected") {

+							return pageState.PUK_LOCKED;

+						} else {

+							return pageState.LOGIN;

+					}                    

+                }

+            }

+        }

+			

+        

+        // ¼ì²éµ±Ç°window.location.hash£¬Òì³£ÔòÌø×ªµ½index.html      

+        function gotoLogin() {

+            if (window.location.hash != config.defaultRoute && _.indexOf(config.GUEST_HASH, window.location.hash) == -1) {

+                if (!manualLogout && lastLoginStatus == "1") {

+                    manualLogout = false;

+                    lastLoginStatus = 'UNREAL';

+                    showAlert('need_login_again', function () {

+                        window.location = "index.html";

+                    });

+                } else if (lastLoginStatus == 'UNREAL') {

+                    //do nothing, only popup need_login_again alert one time

+                    return;

+                } else {

+                    window.location = "index.html";

+                }

+            }

+        }

+		

+        // ¶¨Ê±¼ì²éµÇ¼״̬      

+        function loginStatusCheckingTimer() {

+            return setInterval(function () {

+                var info = service.getStatusInfo();

+                if (!info.isLoggedIn) {

+                    gotoLogin();

+                    return;

+                }

+                lastLoginStatus = service.getStatusInfo().isLoggedIn ? "1" : "0";

+            }, 1000);

+        }	

+		

+        function init() {

+            var info = service.getStatusInfo();

+            if (info.isLoggedIn) {

+                window.location.hash = '#main';

+                return;

+            }

+

+            var container = $('#container')[0];

+            ko.cleanNode(container);

+            var fwVm = new loginViewModel();

+            ko.applyBindings(fwVm, container);

+

+            $('#frmLogin').validate({

+                submitHandler:function () {

+                    fwVm.login();

+                },

+                rules: {

+                    txtAdmin: 'login_password_length_check'

+                }

+            });

+            $('#frmPIN').validate({

+                submitHandler:function () {

+                    fwVm.enterPIN();

+                },

+                rules:{

+                    txtPIN:"pin_check"

+                }

+            });

+            $('#frmPUK').validate({

+                submitHandler:function () {

+                    fwVm.enterPUK();

+                },

+                rules:{

+                    txtNewPIN:"pin_check",

+                    txtConfirmPIN:{equalToPin:"#txtNewPIN"},

+                    txtPUK:"puk_check"

+                }

+            });

+        }

+		

+	

+        return {

+            init:init,

+            gotoLogin:gotoLogin

+        };

+    });

+	

+

+// Logout Ä£¿é

+define("logout","set service knockout underscore jquery".split(" "),

+    function (config, service, ko, _, $) {

+

+    function logoutViewModel() {

+        var target = this;

+        // »ñÈ¡ÊÇ·ñµÇ¼

+        var loginFlag = function () {

+            var loginInfo = service.getLoginStatus();

+            return (loginInfo.status == "loggedIn");

+        }

+        ();

+        target.loggedIn = ko.observable(loginFlag);

+

+        // Í˳öϵͳ

+        target.logout = function () {

+            showConfirm("confirm_logout", function () {

+                manualLogout = true;

+                service.logout({}, setLocation());

+            });

+        };

+

+        // ÊÇ·ñÏÔʾÍ˳ö°´Å¥

+        target.showLogout = function () {

+            if (config.HAS_LOGIN) {

+                return target.loggedIn();

+            } else {

+                return false;

+            }

+        };

+    }

+    function setLocation() {

+        window.location = 'index.html';

+    }

+    function initialize() {

+        var fwVm = new logoutViewModel();

+        bindContainer(fwVm);

+    }

+    function bindContainer(fwVm) {

+        var con = $('#logout')[0];

+        ko.cleanNode(con);

+        ko.applyBindings(fwVm, con);

+    }

+    return {

+        init: initialize

+    };

+});

+

+// operation mode Ä£¿é

+define("opmode","knockout service jquery set underscore".split(" "),

+

+    function (ko, service, $, config, _) {

+

+	function currentOperationModeViewMode(){

+		var target = this;

+		target.isLoggedIn = ko.observable(false);	

+		target.enableFlag = ko.observable(false);

+

+		target.showOpModeWindow = function () {

+			showSettingWindow("change_mode", "opmode_popup", "opmode_popup", 400, 300, function () {

+			});

+		};

+		target.currentOpMode = ko.observable("0");

+		

+		service.getOpMode({}, function(info){

+			target.isLoggedIn(info.loginfo == "ok");

+			if (info.opms_wan_mode != "PPP" && info.rj45_state != "idle" && info.rj45_state != "dead") {

+				target.enableFlag(false);

+			} else if (info.opms_wan_mode == "PPP" && info.ppp_status != "ppp_disconnected") {

+				target.enableFlag(false);

+			} else if(info.opms_wan_mode == "DHCP"){

+				target.enableFlag(true);

+			} else {

+				target.enableFlag(true);

+			}

+			

+			var opmsWanMode = (info.opms_wan_mode == "DHCP" || info.opms_wan_mode == "STATIC") ? "PPPOE" : info.opms_wan_mode;

+				

+			var currentOperationMode = "";

+			switch(opmsWanMode){

+				case "BRIDGE":

+					currentOperationMode = "opmode_bridge";

+					break;

+				case "PPP":

+					currentOperationMode = "opmode_gateway";

+					break;					

+				case "PPPOE":

+					currentOperationMode = "opmode_cable";

+					break;

+				default:

+					break;

+			}

+			$("#opmode").attr("data-trans", currentOperationMode).text($.i18n.prop(currentOperationMode));

+		});

+        // ¶¨Ê±²éѯ¹¤×÷ģʽÏà¹Ø×´Ì¬£¬ÉèÖýçÃæ×´Ì¬

+		setInterval(function(){

+			var object = service.getConnectionInfo();

+			if(object.opms_wan_mode == "DHCP") {

+				target.enableFlag(true);

+			} else if((object.opms_wan_mode == "PPP" && object.ppp_status != "ppp_disconnected") || (object.opms_wan_mode != "PPP" && object.rj45_state != "idle" && object.rj45_state != "dead")) {

+				target.enableFlag(false);

+			} else {

+				target.enableFlag(true);

+			}

+		}, 1000);

+	}

+

+	function init() {

+		var container = $('#currentOpMode')[0];

+        ko.cleanNode(container);

+        var fwVm = new currentOperationModeViewMode();

+        ko.applyBindings(fwVm, container);

+	}

+

+	return {

+		init:init

+	};

+});

+

+// operation mode popupÄ£¿é

+

+define("opmode_popup","knockout service jquery set underscore".split(" "),

+

+    function (ko, service, $, config, _) {

+   

+    function operationModeViewMode() {

+		var target = this;

+		var currentSelectedOperationMode = "";

+		target.selectedMode = ko.observable("0");	

+		

+	    // ³õʼ»¯½çÃæÄ£Ê½ÏÔʾ	

+		service.getOpMode({}, function(info){

+			if(info.blc_wan_mode == "AUTO_PPP"){

+                currentSelectedOperationMode = "AUTO";

+            }else if(info.blc_wan_mode == "AUTO_PPPOE"){

+                currentSelectedOperationMode = "AUTO";

+            }else if(info.blc_wan_mode == "PPPOE"){

+                currentSelectedOperationMode = "PPPOE";

+            }else{

+                currentSelectedOperationMode = info.blc_wan_mode;

+            }

+			target.selectedMode(currentSelectedOperationMode);

+		});

+		

+	    // ģʽÉèÖÃ/Çл»	

+		target.changeOpMode = function(){

+			var userSelectedOperationMode = $('input:radio[name="opMode"]:checked').val();

+            var messageText = "";

+			if(userSelectedOperationMode == currentSelectedOperationMode) {

+				hidePopupSettingWindow();

+				return;

+			}

+            if(userSelectedOperationMode == "LTE_BRIDGE"){

+                messageText = "opmode_msg3";

+            }else{

+                messageText = "opmode_msg2";

+            }

+			showConfirm(messageText, function(){

+                showLoading();

+				service.SetOperationMode({

+					opMode: userSelectedOperationMode

+				},function(info){

+					if (info && info.result == "success") {

+						var currentOperationMode = "";

+						switch(userSelectedOperationMode){

+							case "AUTO":

+								currentOperationMode = "opmode_auto"

+								break;

+							case "PPP":

+								currentOperationMode = "opmode_gateway";

+								break;

+							case "PPPOE":

+								currentOperationMode = "opmode_cable";

+								break;								

+							default:

+								break;

+						}

+						$("#opmode").attr("data-trans", currentOperationMode).text($.i18n.prop(currentOperationMode));

+						successOverlay();						

+					} else {

+						errorOverlay();

+					}

+				});

+			});

+			

+		}

+		

+	}

+

+	function init() {

+		var fwVm = new operationModeViewMode();

+		ko.applyBindings(fwVm, $('#popupSettingWindow')[0]);

+		

+		$("#opmode_form").validate({

+			submitHandler: function(){

+				fwVm.changeOpMode();

+			}

+		});

+	}

+

+	return {

+		init:init

+	};

+});

+

+define("router","underscore jquery menu set service".split(" "),

+    function (_, $, menu, config, service) {

+    var currentHash = '';

+    var container = $('#container');

+

+    //À뿪½çÃæÊ±¼ì²éÊÇ·ñÓÐÄÚÈÝÐ޸ģ¬Èç¹ûÓÐÔòÌáʾ

+    checkFormContentModify = function (href) {

+        if (config.CONTENT_MODIFIED.modified && window.location.hash != href) {

+            if (config.CONTENT_MODIFIED.message == 'sms_to_save_draft') {

+                config.CONTENT_MODIFIED.callback.ok(config.CONTENT_MODIFIED.data);

+                config.resetContentModifyValue();

+                window.location.hash = href;

+            } else {

+                showConfirm(config.CONTENT_MODIFIED.message, {

+                    ok: function () {

+                        config.CONTENT_MODIFIED.callback.ok(config.CONTENT_MODIFIED.data);

+                        config.resetContentModifyValue();

+                        window.location.hash = href;

+                    },

+                    no: function () {

+                        var result = config.CONTENT_MODIFIED.callback.no(config.CONTENT_MODIFIED.data);

+                        if (!result) {

+                            window.location.hash = href;

+                            config.resetContentModifyValue();

+                        }

+                    }

+                });

+            }

+            return false;

+        } else {

+            return true;

+        }

+    };

+

+    //¶¨Ê±²é¿´SIM¿¨µÄ״̬£¬Èôµ±Ç°SIM¿¨×´Ì¬²»Îª¾ÍÐ÷״̬ÇÒδÏÔʾnosimcardÒ³Ãæ£¬ÔòÏÔʾnosimcardÒ³Ãæ,ÒÔ±ÜÃâ²»¹Ø±Õwebui£¬ÖØÐ²å°ÎÉ豸ºó£¬²»ÔÙÅжÏSIM¿¨×´Ì¬µÄÎÊÌâ

+    function checkSimCardStatus() {

+        setInterval(function () {

+            var data = service.getStatusInfo();

+            var match = menu.findMenu();

+            if (match.length == 0) {

+                return false;

+            }

+            var requirePinHash = ["phonebook", "sms_list"];

+            var isRequirePin = ($.inArray(match[0].path, requirePinHash) != -1);

+            if (match[0].checkSIMStatus === true) {

+                var simstatus = data.simStatus == "modem_sim_undetected"

+                     || data.simStatus == "modem_sim_destroy" || data.simStatus == "modem_waitpin"

+                     || data.simStatus == "modem_waitpuk";

+                var netlockstatus = data.simStatus == "modem_imsi_waitnck";

+                if (data.isLoggedIn && (

+                        ($('#div-nosimcard')[0] == undefined && simstatus)

+                         || ($('#div-network-lock')[0] == undefined && netlockstatus)

+                         || (($('#div-nosimcard')[0] != undefined || $('#div-network-lock')[0] != undefined) && data.simStatus == "modem_init_complete"))) {

+                    fixedLoadResources(match[0], data.simStatus, isRequirePin);

+                }

+            }

+        }, 1000);

+    }

+

+    //¼ì²éµÇÂ¼Ò³Ãæ±³¾°

+    function checkLoginPageBg() {

+        var h = window.location.hash;

+        if (h == '#entry' || _.indexOf(config.GUEST_HASH, h) != -1) {

+            $("#manageContainer").attr("style", "margin-top:-36px;");

+        } else {

+            $("#manageContainer").attr("style", "margin-top:0px;");

+        }

+

+        if (window.location.hash == '#entry') {

+            $("#mainContainer").addClass('loginBackgroundBlue');

+        } else {

+            var mainContainer = $("#mainContainer");

+            if (mainContainer.hasClass('loginBackgroundBlue')) {

+                $("#container").css({

+                    margin: 0

+                });

+                mainContainer.removeClass('loginBackgroundBlue').height('auto');

+            }

+        }

+    }

+	

+    function fixedLoadResources(menuItem, simStatus, isRequirePin) {

+        var item = {};

+        $.extend(item, menuItem);

+        //ûÓÐSIM¿¨Ê±£¬Õë¶ÔhomeÒ³Ãæ²»×ö´¦Àí¡£

+        //ÍøÂç±»ËøÊ±£¬homeÒ³ÃæÏÔʾ½âËøÒ³Ãæ

+        if (simStatus == "modem_sim_undetected" || simStatus == "modem_sim_destroy") {

+            if (!isRequirePin) {

+                item.path = "sim_abnormal";

+            }

+        } else if (simStatus == "modem_waitpin" || simStatus == "modem_waitpuk") {

+            item.path = "sim_abnormal";

+        } else if (simStatus == "modem_imsi_waitnck") {

+            item.path = "locknet";

+        }

+        //load tmpl and controller js

+        loadResources(item);

+    }

+

+    //¸ù¾Ý²Ëµ¥ÅäÖÃitem¼ÓÔØ¶ÔÓ¦µÄ×ÊÔ´

+    function loadResources(item) {

+        var pId = item.path.replace(/\//g, '_');

+        var $body = $('body').removeClass();

+        if (pId != 'entry' && pId != 'main') {

+            $body.addClass('beautiful_bg page_' + pId);

+        } else {

+            $body.addClass('page_' + pId);

+        }

+        clearTimer();

+        hideLoading();

+        var tmplPath = 'text!tmpl/' + item.path + '.html';

+        //TODO: prevent first menu click cover the second menu content, need test with device

+        require([tmplPath, item.path], function (tmpl, viewModel) {

+            container.stop(true, true);

+            container.hide();

+            container.html(tmpl);

+            viewModel.init();

+            //support backward/forward

+            menu.refreshMenu();

+            $('#container').translate();

+            menu.activeSubMenu();

+

+            $("form").attr("autocomplete", "off");

+            container.fadeIn();

+        });

+    }

+    //±È¶Ôhash״̬, Èç¹û±ä»¯Ôò¸ù¾ÝеÄhashÆ¥Åä²Ëµ¥ÅäÖÃ,Æ¥Åä²»ÉÏÊ±Ìø×ªµ½homeÒ³Ãæ, Æ¥ÅäÉÏʱ¼Ç¼hashÖµ²¢¶¯Ì¬¼ÓÔØ¶ÔÓ¦µÄ×ÊÔ´Îļþ

+    function hashCheck() {

+        if (window.location.hash != currentHash) {

+            //½â¾öµÇ½ºóºóÍËÎÊÌâ, µÇ½Óû§·ÃÎʷǵǼÓû§Ê±Ò³Ãæ²»Ìø×ª

+            var info = service.getStatusInfo();

+            if (window.location.hash == config.defaultRoute || _.indexOf(config.GUEST_HASH, window.location.hash) != -1) {

+                if (info.isLoggedIn) {

+                    window.location.hash = currentHash == "" ? "#main" : currentHash;

+                    return;

+                }

+            }

+

+            var match = menu.findMenu();

+

+            if (match.length == 0) {

+                window.location.hash = config.defaultRoute;

+            } else {

+                //µÇ¼ʱ¼ì²é¹¤×÷ģʽ£¬ÓÐÏßģʽÏÂÇÒÖ÷½çÃæÐèÒª¼ì²éSIM¿¨×´Ì¬ÔòÖØÐ¼ÓÔØ,ÎÞÏßģʽÇÒÖ÷½çÃæ²»ÐèÒª¼ì²éSIM¿¨×´Ì¬ÔòÖØÐ¼ÓÔØ

+                if (config.RJ45_SUPPORT && window.location.hash == "#main") {

+                    if ((match[0].checkSIMStatus && checkCableMode(info.blc_wan_mode)) || (!match[0].checkSIMStatus && !checkCableMode(info.blc_wan_mode))) {

+                        window.location.reload();

+                        return;

+                    }

+                }

+                //TODO: ¶þ¼¶²Ëµ¥Óë¶ÔÓ¦Èý¼¶²Ëµ¥µÚÒ»ÏÏàÇл»Ê±²»ÖØÐ¼ÓÔØÊý¾Ý, ÓëTODO: click the same menu ʵÏÖ·½Ê½»¥³â

+                var oldMenu = menu.findMenu(currentHash);

+                currentHash = match[0].hash;

+                if (currentHash == "#entry") {

+                    $('#indexContainer').addClass('login-page-bg');

+                    menu.rebuild();

+                } else {

+                    $('#indexContainer').removeClass('login-page-bg');

+                }

+

+                if (oldMenu.length != 0 && match[0].path == oldMenu[0].path && match[0].level != oldMenu[0].level && match[0].level != '1' && oldMenu[0].level != '1') {

+                    return;

+                }

+

+                checkLoginPageBg();

+                var requirePinHash = ["phonebook", "sms_list"];

+                var isRequirePin = ($.inArray(match[0].path, requirePinHash) != -1);

+                if (match[0].checkSIMStatus === true || isRequirePin) {

+                    //simStatus is undefined when refreshing page

+                    if (info.simStatus == undefined) {

+                        showLoading('waiting');

+                        function checkSIM() {

+                            var data = service.getStatusInfo();

+                            if (data.simStatus == undefined || $.inArray(data.simStatus, config.TEMPORARY_MODEM_MAIN_STATE) != -1) {

+                                addTimeout(checkSIM, 500);

+                            } else {

+                                fixedLoadResources(match[0], data.simStatus, isRequirePin);

+                                hideLoading();

+                            }

+                        }

+                        checkSIM();

+                    } else {

+                        fixedLoadResources(match[0], info.simStatus, isRequirePin);

+                    }

+                } else {

+                    loadResources(match[0]);

+                }

+            }

+        }

+    }

+	

+    //ĬÈÏÈë¿ÚÒ³ÃæÎª#main, ¶¨Ê±¼ì²éhash״̬

+    function init() {

+        checkSimCardStatus();

+        window.location.hash = window.location.hash || "#main";

+        //if support onhashchange then use. If ie8 in ie7 mode, it doesn't trigger onhashchange.

+        if (('onhashchange' in window) && ((typeof document.documentMode === 'undefined') || document.documentMode == 8)) {

+            window.onhashchange = hashCheck;

+            hashCheck();

+        } else {

+            setInterval(hashCheck, 200);

+        }

+

+        //Èç¹ûÐÞ¸ÄÁËÒ³ÃæÄÚÈÝ, À뿪ʱ¸ø³öÌáʾ

+        $("a[href^='#']").die('click').live('click', function () {

+            var $this = $(this);

+            config.CONTENT_MODIFIED.checkChangMethod();

+            return checkFormContentModify($this.attr('href'));

+        });

+    }

+	

+    return {

+        init: init

+    };

+});

+

+// statusBar Ä£¿é

+

+define("statusBar", "knockout jquery underscore service set menu tooltip".split(" "), 

+

+    function (ko, $, _, service, config, menu, tooltip) {

+	

+	var sv__hasCheckedSMSCapacity   = false;	

+    var sv__initSMSCompleted        = false;		

+    var sv_newSMSMessageInDealing   = false;		

+    var sv_fotaUpdateCancel         = null;

+	var sv_batteryCheckTimer        = 0;	

+    var sv_dbMessageIds             = [];	

+    var sv_fotaResultAlertPopuped   = false;

+    var sv_isFirstLoadNewMessage    = true;	

+    var isLoggedIn                  = true;		

+    var sv_messagePopStack          = {};

+    var sv_newMessagePopTemplate    = null;	

+    var sv_resetTrafficAlertPopuped = false;

+    var sv_simMessageListTemplate   = null;

+    var sv_smsListTemplate          = null;		

+    var sv_trafficAlertPopuped_100  = false;		

+    var sv_trafficAlertPopuped      = false;

+    var sv_timer                    = 0;

+

+    // »ñȡ״̬ÐÅÏ¢£¬ÈçÍøÂç¡¢SIM¡¢WIFIµÈ

+    var getCurrentStatusInfo = function () {

+        return service.getStatusInfo();

+    };

+

+    function statusViewModel() {

+        var target         = this;

+        var info           = getCurrentStatusInfo();

+		var roamStatus   = info.roamingStatus ? true : false;

+		var $langLogoBar = $("#langLogoBar");

+		

+		

+        // ´ò¿ªÍøÂçÁ¬½Óʼþ´¦Àí

+		function sf_connect() {

+            showLoading("connecting");

+            service.connect({}, function (data) {

+                if (data.result) {

+                    refreshWifiConnectStatus(target, data.status);

+                }

+                successOverlay();

+            }, function (data) {

+                errorOverlay();

+            });

+        }

+        // ¶Ï¿ªÁ¬½Óʼþ´¦Àí

+		function sf_disconnect() {

+            showLoading("disconnecting");

+            service.disconnect({}, function (data) {

+                if (data.result) {

+                    refreshWifiConnectStatus(target, data.status);

+                }

+                successOverlay();

+            }, function (data) {

+                errorOverlay();

+            });

+        }			

+		

+        if(info.isLoggedIn){

+        	if(!$langLogoBar.hasClass("langborderBg")){

+                $langLogoBar.addClass("langborderBg");

+        	}

+        	$("#statusBar:hidden").show();

+        } else {

+        	if($langLogoBar.hasClass("langborderBg")){

+                $langLogoBar.removeClass("langborderBg");

+        	}

+        	$("#statusBar:visible").hide();

+        }	

+		

+		

+        //target.attachedDevices        = ko.observable(info.attachedDevices);

+        target.batteryLevel             = ko.observable(info.batteryLevel + '%');

+        target.batteryPers              = ko.observable(sf_getBatteryLevelImage(info.batteryPers, info.batteryStatus));		

+        target.batteryStatus            = ko.observable(info.batteryStatus);	

+        target.connectionCssClass       = ko.observable("");		

+        target.connectStatus            = ko.observable(info.connectStatus);

+        target.connectStatusText        = ko.observable();

+        target.connectStatusTrans       = ko.observable();

+        target.hasWifi                  = ko.observable(config.HAS_WIFI);

+        target.hasBattery               = ko.observable(config.HAS_BATTERY);		

+        target.isLoggedIn               = ko.observable(info.isLoggedIn);

+        target.isShowConnectionIcon     = ko.observable(false);

+		target.isShowFotaNewversionIcon = ko.observable(info.new_version_state && info.fota_package_already_download != "yes" && !config.isShowFotaIcon);		

+        target.isShowRj45ConnectionIcon = ko.observable(false);

+        target.networkOperator          = ko.observable(sf_getNetWorkProvider(info.spn_b1_flag,info.spn_name_data,info.spn_b2_flag,info.networkOperator,roamStatus));		

+        target.networkType              = ko.observable(getNetworkType(info.networkType));

+        target.pinStatus                = ko.observable(info.pinStatus);

+        target.pinStatusText            = ko.observable();	

+        target.rj45ConnectionCssClass   = ko.observable("");		

+        target.roamingStatus            = ko.observable(info.roamingStatus ? "R" : "");

+        target.showAttachedDevices      = ko.observable(info.wifiStatus);		

+        target.showSmsDeleteConfirm     = ko.observable(false);

+        target.smsUnreadCount           = ko.observable(0);

+        target.simStatus                = ko.observable(sf_convertSimStatusToImage(info.simStatus));

+        target.signalCssClass           = ko.observable(sf_getSignalCssClass(info.signalImg, info.networkType, info.simStatus));		

+        target.updateType               = ko.observable(service.getUpdateType().update_type);

+        target.wifiStatusCssClass       = ko.observable(sf_getWifiStatusCssClass(info.wifiStatus, info.wirelessDeviceNum));

+        target.wifiStatusImg            = ko.observable(sf_getWifiStatusImage(info.wifiStatus, info.wirelessDeviceNum));

+		

+        sf_getConnectionCssClass(target, info.connectStatus, info.data_counter, info.connectWifiSSID, info.connectWifiStatus, info.rj45ConnectStatus);	

+		

+        target.connect    = sf_connect;

+        target.disconnect = sf_disconnect;

+    }

+	

+	function sf_gotoSmsList(){

+        var s_href = '#msg_main';

+        if(window.location.hash == '#msg_main'){

+            s_href = '#msg_list';

+        }

+		config.CONTENT_MODIFIED.checkChangMethod();

+        if(checkFormContentModify(s_href)){

+            window.location.hash = s_href;

+        }

+    }

+	

+    gotoSmsList = sf_gotoSmsList;	

+

+    function sf_getNetWorkProvider(i_spnB1Flag, i_spnNameData, i_spnB2Flag, i_networkProvider, i_roamStatus) {

+        if (i_spnNameData == "") {

+            return i_networkProvider;

+        } else {

+            i_spnNameData = decodeMessage(i_spnNameData);

+            if (i_spnB1Flag == "0" && i_spnB2Flag == "0") {

+                if (i_roamStatus) {//ÂþÓÎ

+                    return i_spnNameData == i_networkProvider ? i_networkProvider : (i_spnNameData + '  ' + i_networkProvider);

+                } else {//²»ÂþÓÎ

+                    return i_spnNameData;

+                }

+            }else if (i_spnB1Flag == "1" && i_spnB2Flag == "1") {

+                if (i_roamStatus) {//ÂþÓÎ

+                    return i_networkProvider;

+                } else {//²»ÂþÓÎ

+                    return i_spnNameData == i_networkProvider ? i_networkProvider : (i_spnNameData + '  ' + i_networkProvider);

+                }

+            } else if (i_spnB1Flag == "1") {

+                return i_spnNameData == i_networkProvider ? i_networkProvider : (i_spnNameData + '  ' + i_networkProvider);

+            } else if (i_spnB2Flag == "1") {

+                if (i_roamStatus) {//ÂþÓÎ

+                    return i_networkProvider;

+                } else {//²»ÂþÓÎ

+                    return i_spnNameData;

+                }

+            } 

+            return "";

+        }

+    }

+  

+    // Ìí¼ÓжÌÏûÏ¢Ìáʾ£¬²¢¸üÐÂÏà¹ØÄÚÈÝ

+    function sf_addNewMessage(i_message, i_isUpdate, i_type){

+    	config.smsMaxId = i_message.id;

+    	var now = $.now();

+    	sv_messagePopStack["m" + now] = now;

+    	var name = i_message.number;

+    	if(sv_isFirstLoadNewMessage && config.phonebook && config.phonebook.length == 0){

+    		sv_isFirstLoadNewMessage = false;

+    		if(config.HAS_PHONEBOOK){

+				sf_getPhoneBooks();

+			}else{

+				config.phonebook = [];

+			}

+    	}

+    	for(i in config.phonebook){

+    		if(getLastNumber(config.phonebook[i].pbm_number, config.SMS_MATCH_LENGTH) == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)){

+    			name = config.phonebook[i].pbm_name;

+    			break;

+    		}

+    	}

+		var s_newMsg = {

+			mark : "m" + now,

+			name: name,

+			title: $.i18n.prop("sms"),

+			titleTrans: "sms",

+			tag: i_message.tag,

+			content : i_message.content,

+			datetime : i_message.time

+		};

+		if(sv_newMessagePopTemplate == null){

+			sv_newMessagePopTemplate = $.template("newMessagePopTmpl", $("#newMessagePopTmpl"));

+		}

+        $(".bubbleItem:not(.report)", "#buttom-bubble").remove();

+        $.tmpl("newMessagePopTmpl", s_newMsg).appendTo("#buttom-bubble");

+		if((window.location.hash == "#msg_main" || window.location.hash == "#msg_list") && i_type == "1"){

+            //sf_dealChosenNumber(s_newMsg.name, i_message.number);

+			var s_inChating = config.currentChatObject && config.currentChatObject == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH);

+			var s_itemId = getLastNumber(i_message.number, config.SMS_MATCH_LENGTH);

+			var item = $("#smslist-item-" + s_itemId);

+			if(item && item.length > 0){

+                // ÒÑ´æÔÚÄÚÈÝ£¬¸üÐÂÄÚÈݵ÷Õû˳Ðò

+				for(var i = 0; config.listMsgs && i < config.listMsgs.length; i++){

+					if(getLastNumber(config.listMsgs[i].number, config.SMS_MATCH_LENGTH) == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)){

+						config.listMsgs[i].id = i_message.id;

+						config.listMsgs[i].latestId = i_message.id;

+						config.listMsgs[i].latestSms = i_message.content;

+						config.listMsgs[i].latestTime = i_message.time;

+						if(!i_isUpdate){

+							config.listMsgs[i].newCount++;

+							config.listMsgs[i].totalCount++;

+						}

+						break;

+					}

+				}

+				item.find(".smslist-item-checkbox p.checkbox").attr("id", i_message.id);

+				item.find(".smslist-item-checkbox input:checkbox").val(i_message.id).attr("id", "checkbox" + i_message.id);

+				if(!i_isUpdate){

+					var s_itemCount = item.find(".smslist-item-total-count").text();

+					s_itemCount = Number(s_itemCount.substring(1, s_itemCount.length - 1));

+					item.find(".smslist-item-total-count").text("(" + (s_itemCount + 1) + ")");

+					if(!config.currentChatObject || config.currentChatObject != getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)){

+						var s_newNum = item.find(".smslist-item-new-count").removeClass("hide");

+						if(s_newNum && s_newNum.text().length > 0){

+							s_newNum.text(Number(s_newNum.text()) + 1);

+						}else{

+							s_newNum.text(1);

+						}

+					}

+				}

+				if(item.find(".smslist-item-draft-flag").length > 0){

+					if (config.currentChatObject && config.currentChatObject == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)) {

+					    item.find(" td:nth-child(2)").removeClass("font-weight-bold");

+				    } else {

+					    item.find(" td:nth-child(2)").addClass("font-weight-bold");

+				    }

+				}else{

+					var msgContent = item.find(".smslist-item-msg").text(i_message.content);

+				    msgContent.closest('td').prop('title', i_message.content);

+				    item.find("span.clock-time").text(i_message.time);

+					if (config.currentChatObject && config.currentChatObject == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)) {

+					    msgContent.closest('tr').removeClass("font-weight-bold");

+				    } else {

+					    msgContent.closest('tr').addClass("font-weight-bold");

+				    }

+				}

+				item.find(".smslist-item-repeat span").die().click(function() {

+					forwardClickHandler(i_message.id);

+				});

+				

+				var s_tmpItem = item;

+				item.hide().remove();

+				$("#smslist-table").prepend(s_tmpItem.show());

+			} else {

+                // Èç¹û¶ÌÐÅÁбíÖв»´æÔÚÏàÓ¦µÄÁªÏµÈ˶ÌÏ¢£¬Ó¦ÔÚ¶ÌÐÅÁбíÖÐÐÂÔöÊý¾Ý

+				var s_theName = "";

+				if(config.phonebook && config.phonebook.length > 0) {

+					for(i in config.phonebook){

+						if(getLastNumber(config.phonebook[i].pbm_number, config.SMS_MATCH_LENGTH) == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)){

+							s_theName = config.phonebook[i].pbm_name;

+							break;

+						}

+					}

+				}

+				var s_theNewMessage = {

+					id : i_message.id,

+					name : s_theName,

+					number : i_message.number,

+					latestId :i_message.id,

+					totalCount : 1,

+					newCount : s_inChating ? 0 : 1,

+					latestSms : i_message.content,

+					latestTime : i_message.time,

+					checked : false,

+					hasDraft : false,

+					itemId : getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)

+				};

+				if(sv_smsListTemplate == null){

+					sv_smsListTemplate = $.template("smsTableTmpl", $("#smsTableTmpl"));

+				}

+				$.tmpl("smsTableTmpl", {data: [s_theNewMessage]}).prependTo("#smslist-table");

+            }

+            if(config.HAS_PHONEBOOK){

+                $(".sms-add-contact-icon").removeClass("hide");

+            }else{

+                $(".sms-add-contact-icon").addClass("hide");

+            }

+			if(s_inChating){

+				var talkItem = $("#talk-item-" + i_message.id, "#chatlist");

+				if (talkItem && talkItem.length > 0) {// ¸üм¶Áª¶ÌÐÅÄÚÈÝ

+					$(".J_content pre", talkItem).html(dealContent(i_message.content));

+					$(".time .smslist-item-time", talkItem).text(i_message.time);

+					$(".smslist-item-repeat", talkItem).die().click(

+							function() {

+								forwardClickHandler(i_message.id);

+							});

+					$(".smslist-item-delete", talkItem).die().click(

+							function() {

+								deleteSingleItemClickHandler(i_message.id);

+							});

+				} else {// Ôö¼ÓеĻظ´ÄÚÈÝ

+					$("#smsOtherTmpl").tmpl(i_message).appendTo("#chatlist");

+					$(".clear-container", "#chatpanel").animate({

+						scrollTop : $("#chatlist").height()

+					});

+				}

+                if (!config.SMS_SET_READ_WHEN_COMPLETE) {

+                    service.setSmsRead({ids: [i_message.id]}, $.noop);

+                } else if (config.SMS_SET_READ_WHEN_COMPLETE && i_message.receivedAll) {

+                    service.setSmsRead({ids: [i_message.id]}, $.noop);

+                }

+			}

+            enableCheckbox($("#smslist-checkAll"));

+		}

+		if(window.location.hash == "#msg_sim" && i_type == "0"){

+			// Èç¹û¶ÌÐÅÁбíÖв»´æÔÚÏàÓ¦µÄÁªÏµÈ˶ÌÏ¢£¬Ó¦ÔÚ¶ÌÐÅÁбíÖÐÐÂÔöÊý¾Ý

+				var s_theName = "";

+				if(config.phonebook && config.phonebook.length > 0) {

+					for(i in config.phonebook){

+						if(getLastNumber(config.phonebook[i].pbm_number, config.SMS_MATCH_LENGTH) == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)){

+							s_theName = config.phonebook[i].pbm_name;

+							break;

+						}

+					}

+				}

+				var s_theNewMessage = {

+					id : i_message.id,

+					name : s_theName,

+					number : i_message.number,

+					content : i_message.content,

+					time : i_message.time,

+					tag: i_message.tag,

+					checked : false,

+					itemId : getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)

+				};

+				if(i_isUpdate){

+					var s_item = $(".simMsgList-item-class-" + s_theNewMessage.id);

+				    s_item.hide().remove();				

+				}

+				if(sv_simMessageListTemplate == null){

+					sv_simMessageListTemplate = $.template("ssimMessageListTemplate", $("#simMessageListTemplate"));

+				}

+				$.tmpl("simMessageListTemplate", {data: [s_theNewMessage]}).prependTo("#simMsgList_container");

+		}

+	}

+  

+ 	function sf_checkBatteryStatusForFota(){

+	  var s_state = service.getCurrentUpgradeState();

+	  if(s_state.current_upgrade_state == 'low_battery'){

+			showInfo('ota_low_battery');

+			clearInterval(sv_batteryCheckTimer);

+		}

+	} 

+  

+    // ½«SIM¿¨×´Ì¬×ª»¯ÎªÏìÓ¦µÄÎÄ×ÖÃèÊö

+    function sf_convertSimStatusToImage(i_status) {

+        var s_image;

+        switch (i_status) {

+            case "modem_destroy":

+                s_image = "./pic/simcard_undetected.png";//$.i18n.prop("sim_status_destroy");

+                break;

+            case "modem_imsi_waitnck":

+                s_image = "./pic/simcard_undetected.png";//$.i18n.prop("sim_status_waitnck");

+                break;				

+            case "modem_init_complete":

+                s_image = "./pic/simcard_detected.png";//$.i18n.prop("sim_status_ready");

+                break;	

+            case "modem_sim_destroy":

+                s_image = "./pic/simcard_undetected.png";//$.i18n.prop("sim_status_destroy");

+                break;				

+            case "modem_sim_undetected":

+                s_image = "./pic/simcard_undetected.png";//$.i18n.prop("sim_status_undetected");

+                break;

+            case "modem_undetected":

+                s_image = "./pic/simcard_undetected.png";

+                break;				

+            case "modem_waitpin":

+                s_image = "./pic/simcard_undetected.png";//$.i18n.prop("sim_status_waitpin");

+                break;

+            case "modem_waitpuk":

+                s_image = "./pic/simcard_undetected.png";//$.i18n.prop("sim_status_waitpuk");

+                break;

+

+            default:

+                s_image = "./pic/simcard_detected.png";//$.i18n.prop("sim_status_ready");

+                break;

+        }

+        return s_image;

+    }

+	

+    function sf_dealChosenNumber(i_choosenName, i_choosenNum) {

+        setTimeout(function () {

+            var s_choosen  = $("#chosenUserSelect");

+            var s_options = $("option", s_choosen);

+            for (var index  = 0; index < s_options.length; index++) {

+                if (getLastNumber(i_choosenNum, config.SMS_MATCH_LENGTH) == s_options[index].value) {

+				

+                    s_options[index].text  = i_choosenName + '/' + i_choosenNum;

+					s_options[index].value = i_choosenNum;

+                    

+                    break;

+                }

+            }

+            s_choosen.trigger("liszt:updated");

+        }, 0);

+    } 

+	

+	// Ë«Òì²½»ñÈ¡É豸²àºÍsim¿¨²âµÃ¶ÌÐÅÏ¢£¬²¢½«ÆäºÏ²¢

+	function sf_dealPhoneBooksResult(i_books){

+		if($.isArray(i_books.pbm_data) && i_books.pbm_data.length > 0){

+			config.phonebook = i_books.pbm_data;

+		}

+	}	

+  

+    // ¹ýÂË×îеÄ5Ìõ¶ÌÏûÏ¢£¬½«Î´Ìí¼Óµ½¶ÌÐÅÁбíÖеĵ¯³öÌáʾ

+    function sf_filterNewMessage(i_messages, i_type){

+    	if(!config.dbMsgs){

+    		config.dbMsgs = [];

+    	}

+    	if(sv_dbMessageIds.length == 0){

+    		$.each(config.dbMsgs, function(index_1, i_element){

+    			sv_dbMessageIds.push(i_element.id);

+    		});

+    	}

+    	$.each(i_messages, function(index_2, i_element){

+    		if($.inArray(i_element.id, sv_dbMessageIds) == -1){//Ôö¼ÓжÌÐÅ

+    			sv_dbMessageIds.push(i_element.id);

+    			config.dbMsgs.push(i_element);

+    			if(i_element.tag == '1'){

+    				sf_addNewMessage(i_element, false, i_type);

+    			}

+    		}else{

+    			for(var index = 0; index < config.dbMsgs.length; index++){//¸üм¶Áª¶ÌÐÅ

+    				if(config.dbMsgs[index].id == i_element.id && config.dbMsgs[index].content != i_element.content && i_element.tag == '1'){

+    					config.dbMsgs[index].content = i_element.content;

+    					sf_addNewMessage(i_element, true, i_type);

+    					break;

+    				}

+    			}

+    		}

+    	});

+    }

+	

+    // ½«µçÁ¿×ª»¯Îª¶ÔӦͼƬ

+    function sf_getBatteryLevelImage(pers, i_status) {

+    	var s_Image = null;

+		if ("0" == i_status) {

+			if ("1" == pers) {

+				s_Image = "pic/power_one.png";

+			} else if ("2" == pers) {

+				s_Image = "pic/power_two.png";

+			} else if ("3" == pers) {

+				s_Image = "pic/power_three.png";

+			} else if ("4" == pers) {

+				s_Image = "pic/power_full.png";

+			} else { //"5" == pers || "0" == pers

+				s_Image = "pic/power_out.png";

+			}

+		} else {

+			s_Image = "pic/power_charging.gif";

+		}

+		return s_Image;

+    }

+

+    // »ñÈ¡ÁªÍø×´Ì¬µÄCSSÑùʽ

+    function sf_getConnectionCssClass(i_fwVm, i_status, i_data_counter, i_wifiSSID, i_wifiStatus, i_rj45Status) {

+

+        var s_rj45ConnectionStatus = "icon_connection ";

+        var s_connectionStatus     = "icon_connection ";

+

+        if(i_rj45Status == "connect"){

+            s_rj45ConnectionStatus += "connecting";

+        }else if(i_rj45Status == "working"){

+            s_rj45ConnectionStatus += "rj45_connected";

+        }else{

+            s_rj45ConnectionStatus += "disconnect";			

+        }

+

+        if (i_status == "ppp_connecting" || i_status == "wifi_connecting") {

+            s_connectionStatus += "connecting";

+        } else if(i_status == "ppp_connected") {//CPE ppp_statusΪnone readyµÈÖµ

+            if (i_data_counter.uploadRate != '0' && i_data_counter.downloadRate != '0') {

+                s_connectionStatus += "connectionBoth";

+            } else if (i_data_counter.uploadRate != '0' && i_data_counter.downloadRate == '0') {

+                s_connectionStatus += "connectionUp";

+            } else if (i_data_counter.uploadRate == '0' && i_data_counter.downloadRate != '0') {

+                s_connectionStatus += "connectionDown";

+            } else {

+                s_connectionStatus += "connectionNone";

+            }

+        } else if (i_status == "ppp_disconnected") {

+            if (i_wifiSSID && i_wifiStatus == "connect") {

+                service.getHotspotList({}, function (data) {

+                    var s_cssName = "icon_connection ";

+                    var s_css = "connecting ";

+                    for (var i = 0, len = data.hotspotList.length; i < len; i++) {

+                        if (data.hotspotList[i].connectStatus == "1") {

+                            s_css = "wifi_connected";

+                            break;

+                        }

+                    }

+                    s_cssName += s_css;

+                    i_fwVm.connectionCssClass(s_cssName);

+                });

+                i_fwVm.rj45ConnectionCssClass(s_rj45ConnectionStatus);

+                return;

+            } else if (i_wifiSSID && (i_wifiStatus == "connecting" || i_wifiStatus =="dhcping")) {

+                s_connectionStatus += "connecting";

+            } else {

+                s_connectionStatus += "disconnect";

+            }

+        }  else {

+            s_connectionStatus += "disconnect";

+        }

+

+        i_fwVm.connectionCssClass(s_connectionStatus);

+        i_fwVm.rj45ConnectionCssClass(s_rj45ConnectionStatus);

+    }

+	

+	// »ñÈ¡µç»°±¾ÐÅÏ¢

+	function sf_getPhoneBooks() {

+		var s_books = service.getPhoneBooks({

+            page : 0,

+            data_per_page : 2000,

+            orderBy : "id",

+            isAsc : false

+		});

+		sf_dealPhoneBooksResult(s_books);

+	}

+

+	// »ñÈ¡ÐźÅÁ¿µÄCSSÑùʽ

+    function sf_getSignalCssClass(siganl, networkType, simStatus) {

+    	networkType = networkType.toLowerCase();

+    	simStatus = simStatus ? simStatus.toLowerCase() : '';

+    	if(networkType == '' || networkType == 'limited_service' || networkType == 'no_service' || networkType == 'limited service' || networkType == 'no service'

+            || simStatus != 'modem_init_complete'){

+    		siganl = '_none';

+    	}

+        return "signal signal" + siganl;

+    }

+	

+    function sf_getWifiStatusCssClass(i_status, i_deviceSize) {

+        if (i_status) {

+            if (i_deviceSize == 0) {

+                return "wifi_status0";

+            } else {

+                return "wifi_status" + i_deviceSize;

+            }

+        } else {

+            return "wifi_status_off";

+        }

+    }

+    

+    // ¸ù¾Ýwifi״̬»ñÈ¡wifiµÄͼƬ×ÊÔ´

+    function sf_getWifiStatusImage(i_status, i_deviceSize) {

+		if (i_status) {

+			if (i_deviceSize == 0) {

+				return "./pic/wlan0.png";

+			} else {

+				return "./pic/wlan" + i_deviceSize + ".png";

+			}

+		} else {

+			return "./pic/wlan_off.png";

+		}

+	}	

+

+    // »ñÈ¡ÒÑÏÂÔØÉý¼¶°ü´óС£¬¸üÐÂÏÂÔØ½ø¶È

+    function sf_refreshFotaDownloadProgress(){

+        service.getPackSizeInfo({}, function (data) {

+            var percents;

+            if (parseInt(data.fota_pkg_total_size) == 0) {

+                percents = 0;

+            } else {

+                percents = parseInt(parseInt(data.fota_dl_pkg_size) * 100 / parseInt(data.fota_pkg_total_size));

+            }

+            if (percents > 100) {

+                percents = 100;

+            }

+            if (percents >= 0) {

+                if (percents > 95) {

+                    showProgressBar("ota_update", "<br/>" + $.i18n.prop("ota_update_warning"));

+                }

+                setProgressBar(percents);

+            }

+        });

+    }		

+    

+    // ´¦Àí¶ÌÐÅ·¢Ëͱ¨¸æ

+    function sf_responseSmsReport(){

+    	if(sv_isFirstLoadNewMessage && config.phonebook && config.phonebook.length == 0){

+			

+    		sv_isFirstLoadNewMessage = false;

+			

+    		if(config.HAS_PHONEBOOK){

+				sf_getPhoneBooks();

+			}else{

+				config.phonebook = [];

+			}

+    	}

+    	service.getSMSDeliveryReport({

+    		page: 0,

+    		smsCount: 10

+    	}, function(data){

+    		var s_messages = data.messages;

+    		var s_nums = [];

+    		$.each(s_messages, function(i, i_message){

+    			if($.inArray(i_message.number, s_nums) == -1){

+    				s_nums.push(i_message.number);

+                    window.setTimeout(function(){

+    					var s_now = $.now();

+    					sv_messagePopStack["m" + s_now] = s_now;

+    					i_message.name = i_message.number;

+    					for(i in config.phonebook){

+    						if(getLastNumber(config.phonebook[i].pbm_number, config.SMS_MATCH_LENGTH) == getLastNumber(i_message.number, config.SMS_MATCH_LENGTH)){

+    							i_message.name = config.phonebook[i].pbm_name;

+    							break;

+    						}

+    					}

+    					var s_msgContent = $.i18n.prop("sms_delivery_report_" + i_message.content);

+						

+    					var s_newMsg = {

+    							mark : "m" + s_now,

+    							name: i_message.name,

+    							title: $.i18n.prop("sms_report"),

+    							titleTrans: "sms_report",

+    							content : s_msgContent,

+    							datetime : i_message.time,

+    							report : 'report'

+    					};

+						

+    					if(sv_newMessagePopTemplate == null){

+    						sv_newMessagePopTemplate = $.template("newMessagePopTmpl", $("#newMessagePopTmpl"));

+    					}

+						

+                        $(".report", "#buttom-bubble").remove();

+    					$.tmpl("newMessagePopTmpl", s_newMsg).appendTo("#buttom-bubble");

+    				}, 100);

+    			}

+    		});

+    	}, function(){

+    		//No Deal

+    	});

+    }

+	

+    function sf_simStatusInvalid(simStatus){

+        return simStatus == 'modem_sim_undetected' || simStatus == 'modem_undetected' || simStatus == 'modem_sim_destroy'

+            || simStatus == 'modem_waitpin' || simStatus == 'modem_waitpuk' || simStatus == 'modem_imsi_waitnck';

+    }	

+	

+    // ÏÔʾFOTAÉý¼¶µ±Ç°×´Ì¬

+    function sf_showFotaCurrentStatus() {

+        sv_fotaUpdateCancel = true;

+		var r = service.getNewVersionState();

+		

+        function showProgress() {

+            var upgradingState = ["downloading"];

+            var info = service.getCurrentUpgradeState();

+            if(info.current_upgrade_state.toLowerCase() == "idle") {

+                addTimeout(showProgress, 1000);

+            } else if(($.inArray(info.current_upgrade_state, upgradingState) != -1)&&(r.fota_new_version_state != "already_has_pkg")) {

+                hideLoading();

+                sf_showFotaUpgradeStatus();

+            }

+        }

+        if (!($("#progress").is(":visible"))) {

+            showProgress();

+        }

+        var times = 0;

+        var getOTAUpgradeState = function () {

+            var data = null;

+            if (times <= 3) {

+                times = times + 1;

+                data = service.getCurrentUpgradeState();

+            } else {

+                data = getCurrentStatusInfo();

+            }

+            var state = data.current_upgrade_state;

+            if(sv_fotaUpdateCancel && isLoggedIn == true){

+

+				if(r.fota_new_version_state == "already_has_pkg"){

+					if(state == 'low_battery'){

+                        hideProgressBar();

+                        sv_fotaUpdateCancel = false;

+					    service.removeTimerThings('fota_current_upgrade_state',function(){});

+                        showInfo('ota_pkg_low_battery');

+                        window.clearTimeout(sv_timer);

+                        return;

+                    }else if(state == 'prepare_install'){

+                        hideProgressBar();

+                        sv_fotaUpdateCancel = false;

+                        service.removeTimerThings('fota_current_upgrade_state',function(){});

+                        showInfo('ota_pkg_download_success');

+                        window.clearTimeout(sv_timer);

+                        sv_batteryCheckTimer = setInterval(function () {

+                            sf_checkBatteryStatusForFota();

+                            }, 1000);

+                        return;

+				    } 

+				}else if(state == 'downloading') {

+                    sf_refreshFotaDownloadProgress();

+                }else if(state == 'download_failed') {

+                    hideProgressBar();

+                    sv_fotaUpdateCancel = false;

+                    showAlert('ota_download_failed');

+                    window.clearTimeout(sv_timer);

+                    return;

+                }else if(state == 'low_battery'){

+                    hideProgressBar();

+                    sv_fotaUpdateCancel = false;

+					service.removeTimerThings('fota_current_upgrade_state',function(){});

+                    showInfo('ota_low_battery');

+                    window.clearTimeout(sv_timer);

+                    return;

+                }else if(state == 'prepare_install'){

+                    hideProgressBar();

+                    sv_fotaUpdateCancel = false;

+                    service.removeTimerThings('fota_current_upgrade_state',function(){});

+                    showInfo('ota_download_success');

+                    window.clearTimeout(sv_timer);

+                    sv_batteryCheckTimer = setInterval(function () {

+                        sf_checkBatteryStatusForFota();

+                    }, 1000);

+                    return;

+                }else{

+                    sv_fotaUpdateCancel = false;

+                    hideProgressBar();

+                    window.clearTimeout(sv_timer);

+                    return;

+                }

+                sv_timer = window.setTimeout(getOTAUpgradeState , 1000);

+            }

+        };

+

+        if(sv_fotaUpdateCancel && isLoggedIn == true){

+            sv_timer = window.setTimeout(getOTAUpgradeState , 100);

+        }else{

+            window.clearTimeout(sv_timer);

+        }

+    }	

+	

+    // ÏÔʾFotaÉý¼¶½á¹û

+    function sf_showFotaUpdateResult(i_otaResult) {

+        if ((!($("#loading").is(":visible"))) && (!($("#confirm").is(":visible")))) {

+            var s_message = i_otaResult ? "ota_update_success" : "ota_update_failed";

+            sv_fotaResultAlertPopuped = true;

+            showAlert(s_message, function () {

+                sv_fotaResultAlertPopuped = false;

+                if (config.UPGRADE_TYPE == "OTA") {

+                    service.clearUpdateResult({}, $.noop());

+                }

+            });

+        } else {

+            window.setTimeout(function () {

+                sf_showFotaUpdateResult(i_otaResult)

+            }, 1000);

+        }

+    }	

+	

+    // ÏÔʾµ±Ç°Éý¼¶×´Ì¬

+    function sf_showFotaUpgradeStatus() {

+        var s_data        = service.getMandatory();

+        var s_isMandatory = s_data.is_mandatory;

+        var s_sizeInfo    =service.getPackSizeInfo();

+		var s_percents;

+		

+        if (parseInt(s_sizeInfo.fota_pkg_total_size) == 0) {

+            s_percents = 0;

+        } else {

+            s_percents = parseInt(parseInt(s_sizeInfo.fota_dl_pkg_size) * 100 / parseInt(s_sizeInfo.fota_pkg_total_size));

+        }

+        if (s_percents > 100) {

+            s_percents = 100;

+        }

+		

+        if (s_isMandatory) {

+            showProgressBar("ota_update", "<br/>" + $.i18n.prop("ota_update_warning"));

+        } else {

+            var cancelHtml = "";

+            if (config.UPGRADE_TYPE == "OTA") {

+                cancelHtml = "<br/><br/><button id='btnStopUpgrade' onclick='stopOTAUpgrade();' class='btn-1 btn-primary'>" + $.i18n.prop("cancel") + "</button>";

+            }

+            showProgressBar("ota_update", "<br/>" + $.i18n.prop("ota_update_warning") + cancelHtml);

+        }

+		

+        //setProgressBar(0);

+       if (s_percents >= 0) {

+            setProgressBar(s_percents);       

+       }

+    }

+	

+

+

+

+

+    function sf_startFotaUpgrade(){

+        service.setUpgradeSelectOp({selectOp:'1'},function(result){

+            if (result.result == "success"){

+                sf_showFotaCurrentStatus();

+            }});

+    }

+

+    function cancelFotaUpgrade(){

+        service.setUpgradeSelectOp({selectOp:'0'},function(result){ });

+    }

+	

+	

+    function refreshFotaStatusForUserSelector(choice){

+        var info = getCurrentStatusInfo();

+        if(choice){

+			var modeData = service.getOpMode();

+            if (!checkConnectedStatus(info.connectStatus, modeData.rj45_state, info.connectWifiStatus)) {

+                showAlert("ota_network_disconnected");

+                return;

+            }

+

+            if(info.fota_user_selector == 'none'){

+                sf_startFotaUpgrade();

+            }else if(info.fota_user_selector == 'accept'){

+                sf_showFotaCurrentStatus();

+            }else if(info.fota_user_selector == 'cancel'){

+                showAlert("ota_have_cancel");

+            }else if(info.fota_user_selector == 'downloading_cancel'){

+                showAlert("ota_have_cancel");

+            }

+        }else{

+            if(info.fota_user_selector == 'none'){

+                cancelFotaUpgrade();

+            }else if(info.fota_user_selector == 'accept'){

+                sf_showFotaCurrentStatus();

+            }else if(info.fota_user_selector == 'cancel'){

+                // todo: 

+            }else if(info.fota_user_selector == 'downloading_cancel'){

+                // todo: 

+            }

+        }

+    }

+

+

+    // ÏÔʾÓÐа汾»òÏÂÔØÖжÏÊÇ·ñ¼ÌÐøÌáʾ

+    function showFotaStatusForUserToConfirm(upgradeState) {

+        var upgState = upgradeState.current_upgrade_state;

+        if (upgState == 'upgrade_pack_redownload') {

+            showConfirm("ota_interrupted", {ok: function () {

+                refreshFotaStatusForUserSelector(1);

+            }, no: function () {

+                refreshFotaStatusForUserSelector(0);

+            }});

+        } else {

+            var upgradingState = ["prepare_install", "low_battery",

+                "connecting_server", "connect_server_success", "downloading", "accept"];

+            if ($.inArray(upgState, upgradingState) != -1) {

+                sf_showFotaCurrentStatus();

+            } else {

+                

+                showConfirm($.i18n.prop('ota_new_version'), {ok: function () {

+                    refreshFotaStatusForUserSelector(1);

+					config.ISNOW_NOTICE = false;

+                }, no: function () {

+                    refreshFotaStatusForUserSelector(0);

+					config.ISNOW_NOTICE = false;

+                }});

+            }

+        }

+    }

+

+    showOTAAlert = function () {

+		config.ISNOW_NOTICE = true;

+        var is_mandatory = service.getMandatory().is_mandatory;

+        if (is_mandatory) {

+            sf_showFotaCurrentStatus();

+        } else {

+            var upgradeState = {};

+            upgradeState = service.getCurrentUpgradeState();

+            showFotaStatusForUserToConfirm(upgradeState);

+        }

+    };

+

+    // ÖÕÖ¹FotaÉý¼¶

+    stopOTAUpgrade = function () {

+        service.setUpgradeSelectOp({selectOp:'2'},function(result){ });

+        sv_fotaUpdateCancel = false;

+        window.clearTimeout(sv_timer);

+        hideLoading();

+        showAlert('ota_cancel');

+    };

+

+    // ÉèÖÃÁ÷Á¿ÌáÐÑÊÇ·ñÌáÐѹý

+    function setTrafficAlertPopuped(val){

+    	sv_trafficAlertPopuped = !!val;

+        sv_trafficAlertPopuped_100 = !!val;

+        if(!val){

+            sv_resetTrafficAlertPopuped = true;

+        }

+    }

+

+    function setTrafficAlert100Popuped(val){

+        sv_trafficAlertPopuped_100 = !!val;

+        if(!val){

+            sv_resetTrafficAlertPopuped = true;

+        }

+    }

+

+    // ¼ÆËãÁ÷Á¿½á¹¹

+    function getTrafficResult(info){

+        var s_trafficResult = {

+            showConfirm : false,

+            limitPercent : info.limitVolumePercent

+        };

+        if(info.limitVolumeType == '1'){

+            var monthlyTraffic = parseInt(info.data_counter.monthlySent, 10) + parseInt(info.data_counter.monthlyReceived, 10);

+            s_trafficResult.usedPercent = monthlyTraffic / info.limitVolumeSize * 100;

+            if(s_trafficResult.usedPercent > s_trafficResult.limitPercent){

+                s_trafficResult.showConfirm = true;

+                s_trafficResult.type = 'data';

+            }

+        }else{

+            s_trafficResult.usedPercent = info.data_counter.monthlyConnectedTime / info.limitVolumeSize * 100;

+            if(s_trafficResult.usedPercent > s_trafficResult.limitPercent){

+                s_trafficResult.showConfirm = true;

+                s_trafficResult.type = 'time';

+            }

+        }

+        return s_trafficResult;

+    }

+

+	// ³õʼ»¯ ViewModel£¬²¢½øÐÐÊÓͼ°ó¶¨

+    function init() {

+        if(config.PRODUCT_TYPE == 'DATACARD') {

+            $('#statusBar').addClass('padding-right-90');

+            $('#language').addClass('data-card-language');

+        }

+        //preload img 

+        var imgAlert   = $('<img />').attr('src', 'pic/res_alert.png');

+        var imgConfirm = $('<img />').attr('src', 'pic/res_confirm.png');

+        var imgInfo    = $('<img />').attr('src', 'pic/res_info.png');

+        

+        window.setTimeout(function () {

+		

+            var fwVm = new statusViewModel();

+			

+            ko.applyBindings(fwVm, $('#statusBar')[0]);

+			

+            window.setInterval(function () {

+                var info          = getCurrentStatusInfo();

+				var s_roamStatus    = info.roamingStatus ? true : false;

+                var $langLogoBar  = $("#langLogoBar");

+                isLoggedIn        = info.isLoggedIn;

+				

+				

+                //fwVm.attachedDevices(info.attachedDevices);	

+                fwVm.batteryLevel(info.batteryLevel + '%');				

+                fwVm.batteryPers(sf_getBatteryLevelImage(info.batteryPers, info.batteryStatus));

+                fwVm.batteryStatus(info.batteryStatus);				

+				fwVm.isShowFotaNewversionIcon(info.new_version_state && info.fota_user_selector && info.fota_package_already_download != "yes" && config.ISNOW_NOTICE && fwVm.updateType() == 'mifi_fota');

+				fwVm.isShowRj45ConnectionIcon(config.RJ45_SUPPORT);

+                fwVm.networkOperator(sf_getNetWorkProvider(info.spn_b1_flag,info.spn_name_data,info.spn_b2_flag,info.networkOperator,s_roamStatus));

+                fwVm.networkType(getNetworkType(info.networkType));

+                fwVm.pinStatus(info.pinStatus);

+                fwVm.roamingStatus(info.roamingStatus ? "R" : "");

+                fwVm.showAttachedDevices(info.wifiStatus);

+                fwVm.simStatus(sf_convertSimStatusToImage(info.simStatus));				

+                fwVm.signalCssClass(sf_getSignalCssClass(info.signalImg, info.networkType, info.simStatus));				

+                fwVm.isLoggedIn(info.isLoggedIn);

+                fwVm.wifiStatusCssClass(sf_getWifiStatusCssClass(info.wifiStatus, info.wirelessDeviceNum));

+                fwVm.wifiStatusImg(sf_getWifiStatusImage(info.wifiStatus, info.wirelessDeviceNum));	

+							

+				if(config.HAS_SMS ){

+					if(!sv__hasCheckedSMSCapacity && info.isLoggedIn){

+						checkSMSCapacity(info.smsUnreadCount);

+					} else {

+						fwVm.smsUnreadCount(info.smsUnreadCount);

+					}

+                }

+				

+                sf_getConnectionCssClass(fwVm, info.connectStatus, info.data_counter, info.connectWifiSSID, info.connectWifiStatus, info.rj45ConnectStatus);

+                refreshWifiConnectStatus(fwVm, info.connectStatus,info.connectWifiSSID,info.connectWifiStatus);

+                checkTrafficLimitAlert(fwVm, info);

+                updateStatusBarTrans({simStatus: info.simStatus, wifiStatus: info.wifiStatus, deviceSize: info.wirelessDeviceNum, networkType: info.networkType});

+				

+                if(info.isLoggedIn){

+                	$("#statusBar:hidden").show();

+                } else {

+                	$("#statusBar:visible").hide();

+                }

+            }, 500);

+

+            if(config.HAS_SMS){

+                window.setInterval(function(){

+                    if(fwVm.isLoggedIn()){

+                        checkSMSCapacity();

+                    }

+                }, 10000);

+                checkSmsModelReady();

+            }

+

+            window.setInterval(function() {

+                var data = getCurrentStatusInfo();

+				var upgradingState = ["prepare_install", "low_battery", "download_success","downloading"];

+       

+                if (fwVm.isLoggedIn() == true && !($("#progress").is(":visible")) && data.defaultWanName != ""){                    

+					 	if ($.inArray(data.current_upgrade_state, upgradingState) != -1){

+                        if(null == sv_fotaUpdateCancel){

+                            if(!data.is_mandatory){

+                                $.modal.close();

+                            }

+                            sf_showFotaCurrentStatus();

+                        }else if(false == sv_fotaUpdateCancel){

+                            sv_fotaUpdateCancel = null;

+                        }

+                    }

+                }

+            }, 1000);

+

+            var checkFotaUpgradeResult = function () {

+                var info = service.getStatusInfo();

+                if (info.isLoggedIn) {

+                    service.getUpgradeResult({}, function (data) {

+                        if (data.upgrade_result == "success") {

+                            sf_showFotaUpdateResult(true);

+                        } else if (data.upgrade_result == "fail") {

+                            sf_showFotaUpdateResult(false);

+                        } else {

+                            window.setTimeout(checkFotaUpgradeResult, 1000);

+                        }

+                    }, function () {

+                        window.setTimeout(checkFotaUpgradeResult, 1000);

+                    });

+                } else {

+                    window.setTimeout(checkFotaUpgradeResult, 1000);

+                }

+            };

+            if(fwVm.updateType() == "mifi_fota"){

+                checkFotaUpgradeResult();

+                window.setInterval(function () {

+                    var info = getCurrentStatusInfo();

+                    if (info.isLoggedIn && info.defaultWanName != "") { 

+                        if(info.new_version_state && info.fota_package_already_download != "yes" && !config.ALREADY_NOTICE){

+                            service.getUpgradeResult({}, function (data) {

+                                if (data.upgrade_result == "success") {

+                                    sf_showFotaUpdateResult(true);

+                                } else if (data.upgrade_result == "fail") {

+                                    sf_showFotaUpdateResult(false);

+                                } else {

+                                    if(sv_fotaResultAlertPopuped == false){

+                                        config.ALREADY_NOTICE = true;

+                                        showOTAAlert();

+                                    }

+                                }

+                            });

+                        }

+                    }

+                }, 1000);

+            }

+			function checkSMSCapacity(unreadCount){

+				service.getSmsCapability({}, function(info){

+					var showSmsConfirm = false;

+					if(info.nvTotal != 0 && info.nvUsed >= info.nvTotal){

+						$("#sms_unread_count").attr("tipTitle", "sms_capacity_is_full");

+						showSmsConfirm = true;

+					} else if(info.nvTotal != 0 && info.nvUsed + 5 >= info.nvTotal) {

+						$("#sms_unread_count").attr("tipTitle", "sms_capacity_will_full");

+						showSmsConfirm = true;

+					} else {

+						$("#sms_unread_count").attr("tipTitle", "sms_unread_count");

+					}

+					fwVm.showSmsDeleteConfirm(showSmsConfirm);

+					if(typeof unreadCount != "undefined"){

+						fwVm.smsUnreadCount(unreadCount);

+					}

+					sv__hasCheckedSMSCapacity = true;

+				});

+			}

+        }, 1200);

+        

+        tooltip.init();

+        

+        // ¼ì²é¶ÌϢģ¿é³õʼ»¯×´Ì¬

+        function checkSmsModelReady(){

+            var info = getCurrentStatusInfo();

+            if(info.isLoggedIn){

+                service.getSMSReady({}, function (data) {

+                    if (data.sms_cmd_status_result == "1") {

+                        window.setTimeout(function(){checkSmsModelReady();}, 1000);

+                    } else {

+                        sv__initSMSCompleted = true;

+                    }

+                });

+            } else {

+                window.setTimeout(function(){checkSmsModelReady();}, 1000);

+            }

+        }

+        

+        // ¼ì²éä¯ÀÀÌáÐÑ״̬

+        checkTrafficLimitAlert = function(fwVm, info){

+	    if(window.location.hash == '#entry'){

+                return false;

+            }

+            var APStationEnabled = config.AP_STATION_SUPPORT ? service.getStatusInfo().ap_station_enable : 'undefined';

+			var trafficResult    = getTrafficResult(info);

+            var inShow           = $("#confirm-container:visible").length > 0;

+            var notPPP           = (config.PRODUCT_TYPE == 'CPE' && checkCableMode(info.blc_wan_mode)) ? true : false;

+			

+            // »ñÈ¡Ap StationʹÄÜ״̬£¬ÉèÖÃÌáÐÑ·½Ê½

+            if (config.AP_STATION_SUPPORT && (typeof APStationEnabled == "undefined" || APStationEnabled === '')) {

+                service.refreshAPStationStatus({}, $.noop());

+                return false;

+            }

+            APStationEnabled = APStationEnabled == 1;

+

+            if (!info.isLoggedIn || inShow || (sv_trafficAlertPopuped && sv_trafficAlertPopuped_100) || !info.limitVolumeEnable || (!APStationEnabled && !(info.connectStatus == "ppp_connected")) || notPPP) {

+                return false;

+            }

+			

+            if(sv_resetTrafficAlertPopuped){

+                window.setTimeout(function () {

+                    sv_resetTrafficAlertPopuped = false;

+                }, 2000);

+                return false;

+            }

+

+        	if(trafficResult.showConfirm){

+			

+                var confirmMessage = null;

+				

+                if(trafficResult.usedPercent > 100 && !sv_trafficAlertPopuped_100){

+				

+                    sv_trafficAlertPopuped     = true;

+					sv_trafficAlertPopuped_100 = true;

+					

+                    confirmMessage = {msg: APStationEnabled ? 'traffic_beyond_msg' : 'traffic_beyond_disconnect_msg'};

+					

+                } else if (!sv_trafficAlertPopuped) {

+				

+                    sv_trafficAlertPopuped     = true;

+                    sv_trafficAlertPopuped_100 = false;

+                    confirmMessage = {msg: APStationEnabled ? 'traffic_limit_msg' : 'traffic_limit_disconnect_msg',

+                        params: [trafficResult.limitPercent]};

+                }

+				

+                if (confirmMessage != null) {

+                    if (APStationEnabled) {

+                        showAlert(confirmMessage);

+                    } else {

+                        showConfirm(confirmMessage, function () {

+                            showLoading("disconnecting");

+                            service.disconnect({}, function (data) {

+                                if (data.result) {

+                                    successOverlay();

+                                } else {

+                                    errorOverlay();

+                                }

+                            });

+                        });

+                    }

+                }

+            }

+            return true;

+        };

+        

+        // ¸üÐÂ״̬ÖеÄtooltip

+        function updateStatusBarTrans(status){

+    		$("#statusItemSimStatus").attr("tipTitle", "sim_status_" + status.simStatus);

+    		if (status.wifiStatus) {

+				if (status.deviceSize == 0) {

+					$("#wifi_status").attr("tipTitle","wifi_status_on");

+				} else {

+					$("#wifi_status").attr("tipTitle","wifi_status" + status.deviceSize);

+				}

+			} else {

+				$("#wifi_status").attr("tipTitle","wifi_status_off");

+			}

+        }

+

+

+        // Ë¢ÐÂwifiÍøÂçÁ¬½Ó״̬

+        function refreshWifiConnectStatus(fwVm, status, wifiSSID, wifiStatus) {

+            fwVm.connectStatus(status);

+            if (status == "ppp_disconnecting") {

+                fwVm.connectStatusTrans("disconnecting");

+                fwVm.connectStatusText($.i18n.prop("disconnecting"));

+            } else if (status == "ppp_connecting") {

+                fwVm.connectStatusTrans("connecting");

+                fwVm.connectStatusText($.i18n.prop("connecting"));

+            } else if (status == "ppp_connected") {

+                fwVm.connectStatusTrans("connected");

+                fwVm.connectStatusText($.i18n.prop("connected"));

+            } else if(wifiSSID){

+                if(wifiStatus =="dhcping" || wifiStatus =="connecting"){

+                    fwVm.connectStatus("wifi_connecting");

+                    fwVm.connectStatusTrans("connecting");

+                    fwVm.connectStatusText($.i18n.prop("connecting"));

+                }else if(wifiStatus =="connect"){

+                    fwVm.connectStatus("wifi_connect");

+                    fwVm.connectStatusTrans("connected");

+                    fwVm.connectStatusText($.i18n.prop("connected"));

+                }else{

+                    fwVm.connectStatus("ppp_disconnected");

+                    fwVm.connectStatusTrans("disconnected");

+                    fwVm.connectStatusText($.i18n.prop("disconnected"));

+                }

+            }else{

+                fwVm.connectStatusTrans("disconnected");

+                fwVm.connectStatusText($.i18n.prop("disconnected"));

+            }

+        }

+        

+        // »ñÈ¡µ±Ç°ÍøÂç״̬

+        getNetworkType = function(networkType) {

+			var networkTypeTmp = networkType.toLowerCase();

+			if (networkTypeTmp == '' || networkTypeTmp == 'limited service') {

+				networkTypeTmp = 'limited_service';

+			}

+			if(networkTypeTmp == 'no service') {

+				networkTypeTmp = 'no_service';

+			}

+			if (networkTypeTmp == 'limited_service' || networkTypeTmp == 'no_service') {

+				$("#networkType", "#statusBar").attr("data-trans", "network_type_" + networkTypeTmp);

+				return $.i18n.prop("network_type_" + networkTypeTmp);

+			} else {

+                $("#networkType", "#statusBar").removeAttr("data-trans");

+                return networkType;

+            }

+		};

+        

+		if(config.HAS_SMS && menu.checkIsMenuExist("sms_list")){

+            window.setInterval(function () {

+                var info = getCurrentStatusInfo();

+        		if(window.location.hash == "#entry" || sf_simStatusInvalid(info.simStatus)){

+        			return;

+        		}

+        		for(key in sv_messagePopStack){

+        			var val = sv_messagePopStack[key];

+        			if($.now() - val > 5000){

+        				delete(sv_messagePopStack["m" + val]);

+        				var node = $(".bubbleItem#m" + val, "#buttom-bubble");

+        				node.fadeOut(1000, function(){

+        					$(this).remove();

+        				});

+        			}

+        		}

+        		if(info.isLoggedIn){

+        			if(info.newSmsReceived && !sv_newSMSMessageInDealing){

+                        sv_newSMSMessageInDealing = true;

+        				service.resetNewSmsReceivedVar();

+        				sf_checkNewMessages();

+        			}

+        			if(info.smsReportReceived){

+        				service.resetSmsReportReceivedVar();

+        				sf_responseSmsReport();

+        			}

+        		}

+			}, 1000);

+

+            if(config.SMS_DATABASE_SORT_SUPPORT){

+                window.setInterval(function(){

+                    if(menu.checkIsMenuExist("sms_list")){

+                        var info = getCurrentStatusInfo();

+                        if(info.isLoggedIn && sv__initSMSCompleted && !sv_newSMSMessageInDealing && !sf_simStatusInvalid(info.simStatus)){

+                            sv_newSMSMessageInDealing = true;

+                            sf_checkNewMessages();

+                        }

+                    }

+                }, 20001);

+            }

+		}

+

+    	function sf_checkNewMessages(){

+		

+            var s_tags     = 1;		

+            var s_smsCount = 5;

+

+            if(!config.dbMsgs || config.dbMsgs.length == 0){

+                s_smsCount = 500;

+                s_tags     = 10;

+            }

+            service.getSMSMessages({

+                page : 0,

+                smsCount : s_smsCount,

+                nMessageStoreType : 0,

+                tags : s_tags,

+                orderBy : "order by id desc"

+            }, function(data){

+                if(data && data.messages){

+                    sf_filterNewMessage(data.messages, 0);

+                }

+                sv_newSMSMessageInDealing = false;

+            });	

+            service.getSMSMessages({

+                page : 0,

+                smsCount : s_smsCount,

+                nMessageStoreType : 1,

+                tags : s_tags,

+                orderBy : "order by id desc"

+            }, function(data){

+                if(data && data.messages){

+                    sf_filterNewMessage(data.messages, 1);

+                }

+                sv_newSMSMessageInDealing = false;

+            });

+    	}

+

+        if(config.HAS_SMS){

+            $(".bubbleItem", "#buttom-bubble").live("mouseover", function(){

+                var $this = $(this);

+                delete(sv_messagePopStack[$this.attr("id")]);

+            }).live("mouseout", function(){

+                    var $this = $(this);

+                    var now = $.now();

+                    sv_messagePopStack["m" + now] = now;

+                    $this.attr("id", "m" + now);

+                    $(".bubbleItem h3 a.bubbleCloseBtn", "#buttom-bubble").data("targetid", "m" + now);

+                });

+

+            $(".bubbleItem h3 a.bubbleCloseBtn", "#buttom-bubble").die().live("click", function(){

+                var id = $(this).data("targetid");

+                delete(sv_messagePopStack[id]);

+                var node = $(".bubbleItem#" + id, "#buttom-bubble");

+                node.fadeOut(1000, function(){

+                    $(this).remove();

+                });

+            });

+        }

+    }

+	

+	

+    return {

+        init:init,

+        setTrafficAlertPopuped: setTrafficAlertPopuped,

+        setTrafficAlert100Popuped: setTrafficAlert100Popuped,

+        getTrafficResult: getTrafficResult,

+        showOTAAlert:showOTAAlert

+    };

+});

+

+// Á÷Á¿Í³¼ÆÌáÐÑÄ£¿é

+define("status_traffic_alert","jquery knockout service statusBar echarts".split(" "), 

+

+    function ($, ko, service, status, echarts) {

+	

+    var sv_trafficGraph          = null;

+    var sv_sourceData     = null;

+    var sv_usedDataModified = false;

+    var sv_usedTimeModified = false;	

+

+    var sv_trafficStaticalInfo = {

+        // Á÷Á¿Í¼³õʼֵ

+        data: {

+            alarm: {          

+                

+                itemStyle: {

+                    normal: {

+                        color: '#8CC916'

+                    }

+                },

+				name: '¾¯½äÇø',

+				value: 19.7

+            },

+            alert: {      

+                

+                itemStyle: {

+                    normal: {

+                        color: '#FF5500'

+                    }

+                },

+				name: 'ÌáÐÑÖµ',

+				value: 1

+            },	

+            free: {             

+                

+                itemStyle: {

+                    normal: {

+                        color: '#D8D8D8'

+                    }

+                },

+				name: 'δʹÓÃ',

+				value: 50

+            },

+            full: {

+                

+                

+                itemStyle: {

+                    normal: {

+                        color: '#DF4313'

+                    }

+                },

+				name: 'Á÷Á¿³¬³ö',

+				value: 30

+            },			

+            left1: {            

+                

+                itemStyle: {

+                    normal: {

+                        color: '#D8D8D8'

+                    }

+                },

+				name: 'ÌáÐÑÖµÄÚδʹÓÃ',

+				value: 50,

+            },			

+            start: {

+                

+                itemStyle: {

+                    normal: {

+                        color: '#D8D8D8'

+                    }

+                },

+				name: 'ÌáÐÑÖµÄÚδʹÓÃ',

+				value: 50

+            },

+            used: {

+                

+                itemStyle: {

+                    normal: {

+                        color: '#8CC916'

+                    }

+                },

+				name: 'ÒÑʹÓÃ',

+				value: 30

+            }

+        },	

+        cacheEle: {},

+        // ÔªËØ»ñÈ¡

+        getEle: function (i_elementId) {

+            if (this.cacheEle.hasOwnProperty('id')) {

+                return this.cacheEle[i_elementId];

+            } else {

+                this.cacheEle[i_elementId] = $("#" + i_elementId);

+                return this.cacheEle[i_elementId];

+            }

+        },

+        // »ñÈ¡Á÷Á¿¸æ¾¯×´Ì¬Öµ

+        fetchTrafficAlertInfo: function(){

+            sv_sourceData = getTrafficAlertInfo();

+            return sv_sourceData;

+        },		

+        // »ñÈ¡Á÷Á¿ÖµºÍ¶ÔÓ¦µ¥Î»Öµ

+        getTrafficStatisticalDatalnfo: function (i_valueInfo) {

+            return {

+                data: /\d+(.\d+)?/.exec(i_valueInfo)[0],

+                unit: /[A-Z]{1,2}/.exec(i_valueInfo)[0]

+            }

+        },

+			

+        // »ñȡʱ¼äʱ¡¢·Ö¡¢Ãë

+        getTrafficTimeHours: function (i_time) {

+            var s_timeArray = i_time.split(':');

+            return {

+                h: parseInt(s_timeArray[0], 10),

+                m: parseInt(s_timeArray[1], 10),

+                s: parseInt(s_timeArray[2], 10)

+            }

+        },

+        // »ñȡͳ¼ÆÊ±¼äºÍ¶ÔÓ¦µ¥Î»Öµ

+        getTrafficTimeInfo: function (i_valueInfo) {

+            return {

+                data: /\d+(.\d+)?/.exec(i_valueInfo)[0],

+                unit: /[a-z]{4,6}/.exec(i_valueInfo)[0]

+            }

+        },

+        // ʱ¼ä»»Ëã³ÉS

+        getTrafficTimeToSeconds: function (i_time) {

+            var s_FormattedTime = this.getTrafficTimeHours(i_time);

+            return s_FormattedTime.h * 3600 + s_FormattedTime.m * 60 + s_FormattedTime.s;

+        },			

+        // ͨ¹ý½øÖÆ»ñÈ¡Á÷Á¿µ¥Î»

+        getTrafficUnitByScale: function (i_scale) {

+            if (i_scale == '1024') {

+                return 'GB';

+            } else if (i_scale == '1048576') {

+                return 'TB';

+            } else {

+                return 'MB';

+            }

+        },			

+        // µ¥Î»¶ÔÓ¦Öµ»ñÈ¡

+        getTrafficValueByStatisticalUnit: function (i_unit) {

+            i_unit = i_unit.toLowerCase();

+            if(i_unit == 'minute'){

+				return '60';

+			} else if (i_unit == 'gb') {

+                return '1024';

+            } else if(i_unit == 'hour'){

+				return '3600';

+			} else if (i_unit == 'tb') {

+                return '1048576';

+            } else {

+                return '1';

+            }

+        },

+

+        // ¼ì²é±íµ¥ÊÇ·ñ¿É±à¼­

+        isFormEditable: function (fwVm) {

+            var s_dataPageEditState = fwVm.dataLimitTypeChecked() == '1' && (fwVm.viewEditUsedData() || fwVm.viewEditAlertData() || fwVm.viewEditTotalData());

+            var s_timePageEditState = fwVm.dataLimitTypeChecked() == '0' && (fwVm.viewEditUsedTime() || fwVm.viewEditAlertTime() || fwVm.viewEditTotalTime());

+            if (s_dataPageEditState || s_timePageEditState) {

+                $('.border-color-transition:visible').addClass('attention-focus');

+                addTimeout(function () {

+                    $('.border-color-transition:visible').removeClass('attention-focus');

+                }, 1500);

+                return true;

+            } else {

+                var s_result = false;

+                if (fwVm.dataLimitTypeChecked() == 1) {

+                    if (fwVm.alertDataReach() == '0') {

+                        fwVm.editAlertDataHandler();

+                        s_result = true;

+                    }

+                    if (fwVm.limitDataMonth() == '0') {

+                        fwVm.editTotalDataHandler();

+                        s_result = true;

+                    }

+                } else {

+					if (fwVm.alertTimeReach() == '0') {

+                        fwVm.editAlertTimeHandler();

+                        s_result = true;

+                    }

+                    if (fwVm.limitTimeMonth() == '0') {

+                        fwVm.editTotalTimeHandler();

+                        s_result = true;

+                    }

+                }

+				

+                if (s_result) {

+                    $('.border-color-transition:visible').addClass('attention-focus');

+                    addTimeout(function () {

+                        $('.border-color-transition:visible').removeClass('attention-focus');

+                    }, 1500);

+                }

+                return s_result;

+            }

+        },

+ 

+        // Ë¢ÐÂÁ÷Á¿Í¼ÐÅÏ¢£¬Èç¸÷ÇøÓòÊýÖµ¡¢ÌáʾÓïµÈ

+

+        refreshFlowDiagramInfo: function (fwVm) {

+            var s_alarm  = 0;

+            var s_left   = 0;

+            var s_left1  = 0;

+            var s_reach  = 0;	

+            var s_total  = 0;

+            var s_used   = 0;

+

+

+            var s_startName = $.i18n.prop("echarts_no");

+

+            if (sv_sourceData.dataLimitChecked == '1') { //if (fwVm.dataLimitChecked() == '1') { //¿ªÆô

+	        	s_startName = $.i18n.prop("echarts_used");

+	        	sv_trafficGraphOptions.series[0].data = [];    

+		

+				if (fwVm.dataLimitTypeChecked() == '1') { // Êý¾Ý

+                    sv_trafficGraphOptions.title.text = "";

+                    sv_trafficGraphOptions.series[0].data = [];

+			

+                    if (fwVm.limitDataMonth() == 0) {

+                        var s_usedData = sv_trafficStaticalInfo.data.used;

+                        s_usedData.value = 1;

+                        s_usedData.name = $.i18n.prop("echarts_used");

+                        s_usedData.selected = false;

+                        sv_trafficGraphOptions.series[0].data.push(s_usedData);

+                    } else {

+                        s_total = fwVm.limitDataMonth() * fwVm.selectedDataUnit() * 1048576;

+                        s_used  = parseInt(sv_sourceData.monthlySent, 10) + parseInt(sv_sourceData.monthlyReceived, 10);

+                        s_reach = s_total * fwVm.alertDataReach() / 100;

+

+                        if (s_used >= s_total) {

+                            var s_fullData    = sv_trafficStaticalInfo.data.full;

+                            s_fullData.value  = 100;

+                            s_fullData.name   = $.i18n.prop("echarts_full");

+                            sv_trafficGraphOptions.series[0].data.push(s_fullData);

+                            s_startName = $.i18n.prop("echarts_full");

+                        } else {

+                            if (s_reach > s_used) { 

+                                s_left1 = s_reach - s_used;

+                                s_left  = s_total - s_reach;

+                            } else { 

+                                s_alarm = s_used - s_reach;

+                                s_left  = s_total - s_used;

+                            }

+

+                            var s_usedData = sv_trafficStaticalInfo.data.used;

+                            if (s_reach - s_used > 0) {

+                                s_usedData.value = s_used;

+                            } else {

+                                s_usedData.value = s_reach;

+                            }

+                            s_usedData.name = $.i18n.prop("echarts_used");

+                            sv_trafficGraphOptions.series[0].data.push(s_usedData);

+

+                            if (s_left1 > 0) {

+                                var s_left1Data     = sv_trafficStaticalInfo.data.left1;

+                                s_left1Data.value   = s_left1;

+                                s_left1Data.name    = $.i18n.prop("echarts_left1");

+                                sv_trafficGraphOptions.series[0].data.push(s_left1Data);

+                            }

+

+                            var s_alertData         = sv_trafficStaticalInfo.data.alert;

+                            s_alertData.value       = s_total / 200;

+                            s_alertData.name        = $.i18n.prop("echarts_alert");

+                            sv_trafficGraphOptions.series[0].data.push(s_alertData);

+

+                            if (s_alarm > 0) {

+                                var s_alarmData     = sv_trafficStaticalInfo.data.alarm;

+                                s_alarmData.value   = s_alarm;

+                                s_alarmData.name    = $.i18n.prop("echarts_alarm");

+                                sv_trafficGraphOptions.series[0].data.push(s_alarmData);

+                            }

+

+                            var s_freeData          = sv_trafficStaticalInfo.data.free;

+                            s_freeData.value        = s_left;

+                            s_freeData.name         = $.i18n.prop("echarts_free");

+                            sv_trafficGraphOptions.series[0].data.push(s_freeData);

+                        }

+                    }	

+				

+				}else{// ʱ¼ä

+            

+                    sv_trafficGraphOptions.series[0].data = [];

+			

+                    if (fwVm.limitTimeMonth() == 0) {

+                        var s_usedData        = sv_trafficStaticalInfo.data.used;

+                        s_usedData.value      = 1;

+                        s_usedData.selected   = false;

+                        s_usedData.name       = $.i18n.prop("echarts_used");

+                        sv_trafficGraphOptions.series[0].data.push(s_usedData);

+                    } else {

+                        s_total  = fwVm.limitTimeMonth() * fwVm.selectedTimeUnit();

+                        s_used   = sv_sourceData.monthlyConnectedTime;

+                        s_reach  = s_total * fwVm.alertTimeReach() / 100;

+				

+                        if (s_used >= s_total) {

+                            var fullTime   = sv_trafficStaticalInfo.data.full;

+                            fullTime.value = 100;

+                            fullTime.name  = $.i18n.prop("echarts_full");

+                            sv_trafficGraphOptions.series[0].data.push(fullTime);

+                            s_startName    = $.i18n.prop("echarts_full");

+                        } else {

+                            if (s_reach - s_used > 0) {

+                                s_left1 = s_reach - s_used;

+                                s_left  = s_total - s_reach;

+                            } else {

+                                s_alarm = s_used  - s_reach;

+                                s_left  = s_total - s_used;

+                            }

+

+                            var s_usedTime = sv_trafficStaticalInfo.data.used;

+                            if (s_reach - s_used > 0) {

+                                s_usedTime.value = s_used;

+                            } else {

+                                s_usedTime.value = s_reach;

+                            }

+                            s_usedTime.name = $.i18n.prop("echarts_used");

+                            sv_trafficGraphOptions.series[0].data.push(s_usedTime);

+

+                            if (s_left1 > 0) {

+                                var s_left1Time    = sv_trafficStaticalInfo.data.left1;

+                                s_left1Time.value  = s_left1;

+                                s_left1Time.name   = $.i18n.prop("echarts_left1");

+                                sv_trafficGraphOptions.series[0].data.push(s_left1Time);

+                            }

+

+                            var s_alertTime        = sv_trafficStaticalInfo.data.alert;

+                            s_alertTime.value      = s_total / 200;

+                            s_alertTime.name       = $.i18n.prop("echarts_alert");

+                            sv_trafficGraphOptions.series[0].data.push(s_alertTime);

+

+                            if (s_alarm > 0) {

+                                var s_alarmTime      = sv_trafficStaticalInfo.data.alarm;

+                                s_alarmTime.value    = s_alarm;

+                                s_alarmTime.name     = $.i18n.prop("echarts_alarm");

+                                sv_trafficGraphOptions.series[0].data.push(s_alarmTime);

+                            }

+

+                            var s_freeTime         = sv_trafficStaticalInfo.data.free;

+                            s_freeTime.value       = s_left;

+                            s_freeTime.name        = $.i18n.prop("echarts_free");

+                            sv_trafficGraphOptions.series[0].data.push(s_freeTime);

+                        }

+                    }		

+                } 

+            } else {

+                var s_usedData      = sv_trafficStaticalInfo.data.used;

+                s_usedData.value    = 1;

+                s_usedData.selected = false;

+                s_usedData.name     = $.i18n.prop("echarts_no");

+		

+                sv_trafficGraphOptions.series[0].data = [s_usedData];

+                sv_trafficGraphOptions.title.text     = '';			

+            }

+            sv_trafficStaticalInfo.setFlowDiagramInfo(sv_trafficGraphOptions, s_startName);

+        },

+

+		

+		// ÖØ»æÁ÷Á¿Í¼

+        setFlowDiagramInfo: function (i_options, i_startName) {

+            var s_startPart = sv_trafficStaticalInfo.data.start;

+

+            s_startPart.name     = i_startName;			

+            s_startPart.selected = false;

+            s_startPart.value    = 0;

+			

+            var s_arr = [s_startPart].concat(i_options.series[0].data);

+            i_options.series[0].data = s_arr;

+            sv_trafficGraph.setOption(i_options, true);

+			

+            addTimeout(function () {

+                sv_trafficGraph.resize();

+            }, 1000);

+        }

+    };

+

+

+    // Á÷Á¿Í¼»ù±¾ÅäÖÃ

+    var sv_trafficGraphOptions = {

+        animation: false,

+        color: ['red', 'red', 'red', 'red', 'red'],

+        series: [

+            {

+                name: 'Á÷Á¿¿ØÖÆ',

+                radius: ['0', '75'],

+                selectedOffset: 3,				

+                type: 'pie',				

+                data: [

+

+                ],			

+                itemStyle: {

+                    normal: {

+                        labelLine: {

+                            show: false

+                        },

+                        label: {

+                            show: false

+                        }

+                    }

+                }				

+            }

+        ],		

+        title: {

+            itemGap: 0,

+			      text: '',

+            subtextStyle: {

+                color: '#FFF',

+                fontFamily: '΢ÈíÑźÚ',

+                fontSize: 16,

+                fontWeight: 'bolder'

+            },				  

+            textStyle: {

+                color: '#FFF',

+                fontFamily: '΢ÈíÑźÚ',

+                fontSize: 20,

+                fontWeight: 'bolder'

+            },

+            x: 'center',

+            y: 'center'			

+        },

+		tooltip: {

+            formatter: "{b}"

+        }      

+    };

+

+

+    // »ñÈ¡Á÷Á¿ÌáÐÑÊý¾Ý

+    function getTrafficAlertInfo() {

+        return service.getTrafficAlertInfo();

+    }

+

+

+	

+    // Á÷Á¿ÌáÐÑViewModel

+

+    function trafficViewModel() {

+

+        var target         = this;

+		

+        var info                    = sv_trafficStaticalInfo.fetchTrafficAlertInfo();	

+        var dataMonth               = info.limitDataMonth.split("_");

+		

+        sv_usedDataModified         = false;

+        sv_usedTimeModified         = false;

+

+        target.alertDataReach               = ko.observable(info.alertDataReach || 0);		

+        target.alertTimeReach               = ko.observable(info.alertTimeReach || 0);

+        target.dataLimitChecked             = ko.observable(info.dataLimitChecked == '0' ? '0' : '1');

+        target.dataLimitTypeChecked         = ko.observable(info.dataLimitTypeChecked == '0' ? '0' : '1');

+        target.limitTimeMonth               = ko.observable(info.limitTimeMonth || 0);	

+

+		

+        // ×¢Òâ˳Ðò 

+        target.usedDataText                 = ko.observable(transUnit(parseInt(info.monthlySent, 10) + parseInt(info.monthlyReceived, 10), false));

+        var sv_staticalDataInfo             = sv_trafficStaticalInfo.getTrafficStatisticalDatalnfo(target.usedDataText());

+        var sv_staticalInfoData             = sv_staticalDataInfo.data;

+        target.dataUsed                     = ko.observable(sv_staticalInfoData);	

+        var sv_staticalInfoUnit             = sv_staticalDataInfo.unit;

+        target.selectedDataUsedUnit         = ko.observable(sv_trafficStaticalInfo.getTrafficValueByStatisticalUnit(sv_staticalInfoUnit));

+        target.usedDataTextDescData         = ko.observable("");

+		

+        target.limitDataMonth               = ko.observable(dataMonth[0] || 0);		

+        target.selectedDataUnit             = ko.observable(dataMonth[1] || 1);		

+

+        var limitDataMonthTmp               = transUnit(target.limitDataMonth() * target.selectedDataUnit() * 1024 * 1024, false);

+        var limitDataMonthUnitTmp           = limitDataMonthTmp.substring(limitDataMonthTmp.length-2);

+        target.limitDataMonth(limitDataMonthTmp.substring(0, limitDataMonthTmp.length-2));

+        target.selectedDataUnit(sv_trafficStaticalInfo.getTrafficValueByStatisticalUnit(limitDataMonthUnitTmp));	

+		

+        target.usedDataTextDesc             = ko.computed(sf_usedDataTextDesc);	

+        target.limitDataMonthDescData       = ko.observable("");

+        target.limitDataMonthDesc           = ko.computed(sf_limitDataMonthDesc);	

+        target.alertDataReachDescData       = ko.observable("");		

+        target.alertDataReachDesc           = ko.computed(sf_alertDataReachDesc);	

+        target.leftDataDescData             = ko.observable("");

+        target.leftDataDesc                 = ko.computed(sf_leftDataDesc);	

+        target.monthlyConnectedTime         = ko.observable(transSecond2Time(info.monthlyConnectedTime));

+		

+		var sv_timeInfo1                    = sv_trafficStaticalInfo.getTrafficTimeInfo(transTimeUnit(info.monthlyConnectedTime));

+        target.usedTime                     = ko.observable(sv_timeInfo1.data);		

+		target.selectedTimeUsedUnit         = ko.observable(sv_trafficStaticalInfo.getTrafficValueByStatisticalUnit(sv_timeInfo1.unit));	

+		

+        target.usedTimeTextDescData         = ko.observable("");

+        target.usedTimeTextDesc             = ko.computed(sf_usedTimeTextDesc);		

+		

+		var  sv_timeInfoNew                 = sv_trafficStaticalInfo.getTrafficTimeInfo(transTimeUnit(parseFloat(target.limitTimeMonth()) * 3600));

+		target.selectedTimeUnit             = ko.observable(sv_trafficStaticalInfo.getTrafficValueByStatisticalUnit(sv_timeInfoNew.unit));

+		target.limitTimeMonth(sv_timeInfoNew.data);

+		

+		

+        target.limitTimeMonthDescData       = ko.observable("");

+		target.limitTimeMonthDescText       = ko.observable("traffic_limit_time_h");		        

+        target.limitTimeMonthDesc           = ko.computed(sf_limitTimeMonthDesc);

+        target.alertTimeReachDescData       = ko.observable("");       	

+        target.alertTimeReachDesc           = ko.computed(sf_alertTimeReachDesc);

+        target.leftTimeDescData             = ko.observable("");        

+        target.leftTimeDesc                 = ko.computed(sf_leftTimeDesc);

+        target.save                         = sf_save;		

+        target.viewEditUsedData             = ko.observable(false);

+        target.editUsedDataHandler          = sf_editUsedDataHandler;

+        target.editUsedDataSaveHandler      = sf_editUsedDataSaveHandler;		

+        target.saveUsedData                 = sf_saveUsedData;		

+        target.editUsedDataCancelHandler    = sf_editUsedDataCancelHandler;

+        target.viewEditTotalData            = ko.observable(false);

+		target.editTotalDataHandler         = sf_editTotalDataHandler;

+		target.editTotalDataSaveHandler     = sf_editTotalDataSaveHandler;

+        target.editTotalDataCancelHandler   = sf_editTotalDataCancelHandler;

+        target.viewEditAlertData            = ko.observable(false);

+		target.editAlertDataHandler         = sf_editAlertDataHandler;

+		target.editAlertDataSaveHandler     = sf_editAlertDataSaveHandler;

+		target.editAlertDataCancelHandler   = sf_editAlertDataCancelHandler;

+        target.viewEditUsedTime             = ko.observable(false);

+		target.editUsedTimeHandler          = sf_editUsedTimeHandler;	

+		target.saveUsedTime                 = sf_saveUsedTime;

+		target.editUsedTimeSaveHandler      = sf_editUsedTimeSaveHandler;

+		target.editUsedTimeCancelHandler    = sf_editUsedTimeCancelHandler;

+		target.viewEditTotalTime            = ko.observable(false);

+		target.editTotalTimeHandler         = sf_editTotalTimeHandler ;

+        target.editTotalTimeSaveHandler     = sf_editTotalTimeSaveHandler;	

+		target.editTotalTimeCancelHandler   = sf_editTotalTimeCancelHandler;

+		target.viewEditAlertTime            = ko.observable(false);

+        target.editAlertTimeHandler         = sf_editAlertTimeHandler;		

+        target.editAlertTimeSaveHandler     = sf_editAlertTimeSaveHandler;

+        target.editAlertTimeCancelHandler   = sf_editAlertTimeCancelHandler;

+        sv_trafficStaticalInfo.refreshFlowDiagramInfo(target);		

+		

+

+        // Á÷Á¿ÌáÐÑÃèÊöÓï

+		function sf_alertDataReachDesc() {

+            if(isNaN(target.limitDataMonth() * target.selectedDataUnit() * target.alertDataReach())) {

+                target.alertDataReachDescData(target.alertDataReach() + ', ');

+                return $.i18n.prop('traffic_alert_reach_text', target.alertDataReach(), ' ');

+            }

+

+            var s_value = transUnit(target.limitDataMonth() * target.selectedDataUnit() * target.alertDataReach() * 1048576 / 100, false);

+            target.alertDataReachDescData(target.alertDataReach() + ',' + s_value);

+            return $.i18n.prop('traffic_alert_reach_text', target.alertDataReach(), s_value);

+        }

+		// ʱ¼äÌáÐÑÃèÊöÓï

+        function sf_alertTimeReachDesc() {

+            if(isNaN(target.limitTimeMonth() * target.alertTimeReach())) {

+                target.alertTimeReachDescData(target.alertTimeReach() + ', ');

+                return $.i18n.prop('traffic_alert_reach_text', target.alertTimeReach(), ' ');

+            }

+            var s_value = transSecond2Time(target.limitTimeMonth() * target.selectedTimeUnit() * target.alertTimeReach() / 100);

+            target.alertTimeReachDescData(target.alertTimeReach() + ',' + s_value);

+            return $.i18n.prop('traffic_alert_reach_text', target.alertTimeReach(), s_value);

+        }	

+	

+		

+        // Á÷Á¿ÌáÐÑֵȡÏû±à¼­°´Å¥Ê¼þ

+		function sf_editAlertDataCancelHandler() {

+            target.alertDataReach(sv_trafficStaticalInfo.getEle('editAlertData').data('oldValue'));

+            target.viewEditAlertData(false);

+        }		

+				

+        // Á÷Á¿ÌáÐÑÖµ±à¼­°´Å¥Ê¼þ

+		function sf_editAlertDataHandler() {

+            sv_trafficStaticalInfo.getEle('editAlertData').data('oldValue', target.alertDataReach());

+            target.viewEditAlertData(true);

+        }

+        

+        // Á÷Á¿ÌáÐÑÖµ±£´æ±à¼­°´Å¥Ê¼þ

+		function sf_editAlertDataSaveHandler() {

+            if (sv_trafficStaticalInfo.getEle('alertDataReach').valid()) {

+                target.viewEditAlertData(false);

+            }

+        }

+		

+        // ʱ¼äÌáÐÑֵȡÏû±à¼­°´Å¥Ê¼þ

+		function sf_editAlertTimeCancelHandler() {

+            target.alertTimeReach(sv_trafficStaticalInfo.getEle('editAlertTime').data('oldValue'));

+            target.viewEditAlertTime(false);

+        }	 

+        // ʱ¼äÌáÐÑÖµ±à¼­°´Å¥Ê¼þ

+		function sf_editAlertTimeHandler() {

+            sv_trafficStaticalInfo.getEle('editAlertTime').data('oldValue', target.alertTimeReach());

+            target.viewEditAlertTime(true);

+        } 		

+        // ʱ¼äÌáÐÑÖµ±£´æ±à¼­°´Å¥Ê¼þ

+		function sf_editAlertTimeSaveHandler() {

+            if (sv_trafficStaticalInfo.getEle('alertTimeReach').valid()) {

+                target.viewEditAlertTime(false);

+            }

+        }		

+	

+        // ÌײÍÁ÷Á¿±à¼­°´Å¥Ê¼þ

+		function sf_editTotalDataHandler() {

+            sv_trafficStaticalInfo.getEle('editTotalData').data('oldValue', target.limitDataMonth());

+            sv_trafficStaticalInfo.getEle('selectedDataUnit').data('oldValue', target.selectedDataUnit());

+            target.viewEditTotalData(true);

+        }

+        

+        // ÌײÍÁ÷Á¿±£´æ±à¼­°´Å¥Ê¼þ

+		function sf_editTotalDataSaveHandler() {

+            if (sv_trafficStaticalInfo.getEle('limitDataMonth').valid()) {

+                target.usedDataText(transUnit(target.limitDataMonth() * target.selectedDataUnit() * 1048576, false));

+                target.viewEditTotalData(false);

+            }

+        }

+        

+        // ÌײÍÁ÷Á¿È¡Ïû±à¼­°´Å¥Ê¼þ

+		function sf_editTotalDataCancelHandler() {

+            target.limitDataMonth(sv_trafficStaticalInfo.getEle('editTotalData').data('oldValue'));

+            target.selectedDataUnit(sv_trafficStaticalInfo.getEle('selectedDataUnit').data('oldValue'));

+            target.viewEditTotalData(false);

+        }

+        // ÌײÍʱ¼äÈ¡Ïû±à¼­°´Å¥Ê¼þ

+		function sf_editTotalTimeCancelHandler() {

+            target.limitTimeMonth(sv_trafficStaticalInfo.getEle('editTotalTime').data('oldValue'));

+            target.viewEditTotalTime(false);

+        }       

+        // ÌײÍʱ¼ä±à¼­°´Å¥Ê¼þ

+		function sf_editTotalTimeHandler() {

+            sv_trafficStaticalInfo.getEle('editTotalTime').data('oldValue', target.limitTimeMonth());

+            target.viewEditTotalTime(true);

+        }       

+        // ÌײÍʱ¼ä±£´æ±à¼­°´Å¥Ê¼þ

+		function sf_editTotalTimeSaveHandler() {

+            if (sv_trafficStaticalInfo.getEle('limitTimeMonth').valid()) {

+                target.viewEditTotalTime(false);

+            }

+        }		

+

+        // ÒÑÓÃÁ÷Á¿È¡Ïû±à¼­°´Å¥Ê¼þ

+		function sf_editUsedDataCancelHandler() {

+            target.dataUsed(sv_trafficStaticalInfo.getEle('editUsedData').data('oldValue'));

+            target.selectedDataUsedUnit(sv_trafficStaticalInfo.getEle('selectedDataUsedUnit').data('oldValue'));

+            sv_trafficStaticalInfo.getEle('editUsedDataCancel').siblings('label.error').hide();

+            target.viewEditUsedData(false);

+        }	

+        // ÒÑÓÃÁ÷Á¿±à¼­°´Å¥Ê¼þ

+		function sf_editUsedDataHandler() {

+            sv_trafficStaticalInfo.getEle('editUsedData').data('oldValue', target.dataUsed());

+            sv_trafficStaticalInfo.getEle('selectedDataUsedUnit').data('oldValue', target.selectedDataUsedUnit());

+            target.dataUsed(target.dataUsed());

+            target.viewEditUsedData(true);

+        }	

+        // ÒÑÓÃÁ÷Á¿±£´æ°´Å¥Ê¼þ

+		function sf_editUsedDataSaveHandler() {

+            if (sv_trafficStaticalInfo.getEle('dataUsed').valid()) {

+                sv_usedDataModified = true;

+                target.viewEditUsedData(false);

+            }

+        }		

+        // ÒÑÓÃʱ¼äÈ¡Ïû±à¼­°´Å¥Ê¼þ

+		function sf_editUsedTimeCancelHandler() {

+            target.usedTime(sv_trafficStaticalInfo.getEle('editUsedTime').data('oldValue'));

+            target.viewEditUsedTime(false);

+        }		

+        // ÒÑÓÃʱ¼ä±à¼­°´Å¥Ê¼þ

+		function sf_editUsedTimeHandler() {

+            sv_trafficStaticalInfo.getEle('editUsedTime').data('oldValue', target.usedTime());

+            target.viewEditUsedTime(true);

+        }

+

+        // ÒÑÓÃʱ¼ä±£´æ±à¼­°´Å¥Ê¼þ

+		function sf_editUsedTimeSaveHandler() {

+            if (sv_trafficStaticalInfo.getEle('usedTime').valid()) {

+                target.monthlyConnectedTime(transSecond2Time(parseFloat(target.usedTime()) * target.selectedTimeUsedUnit()));

+                target.viewEditUsedTime(false);

+                sv_usedTimeModified = true;

+            }

+        }

+

+		// Ê£ÓàÁ÷Á¿ÃèÊöÓï	

+        function sf_leftDataDesc() {

+            var s_left = (target.limitDataMonth() * target.selectedDataUnit() - target.dataUsed() * target.selectedDataUsedUnit()) * 1048576;

+            if(s_left < 0) {

+                s_left = 0;

+            }

+

+            if(isNaN(s_left)) {

+                target.leftDataDescData('');

+                return $.i18n.prop('traffic_data_left_text', ' ');

+            }

+

+            target.leftDataDescData(transUnit(s_left, false));

+            return $.i18n.prop('traffic_data_left_text', transUnit(s_left, false));

+        }	

+		//Ê£Óàʱ¼äÃèÊöÓï

+		function sf_leftTimeDesc() {

+            var s_surplus = target.limitTimeMonth() * target.selectedTimeUnit() - sv_trafficStaticalInfo.getTrafficTimeToSeconds(target.monthlyConnectedTime());

+            if(s_surplus < 0) {

+                s_surplus = 0;

+            }

+

+            if(isNaN(s_surplus)) {

+                target.leftTimeDescData(' ');

+                return $.i18n.prop('traffic_data_left_text', ' ');

+            }

+            target.leftTimeDescData(transSecond2Time(s_surplus));

+            return $.i18n.prop('traffic_data_left_text', transSecond2Time(s_surplus));

+        }

+		// ÌײÍÁ÷Á¿ÃèÊöÓï

+		function sf_limitDataMonthDesc() {

+            if(isNaN(target.limitDataMonth())) {

+                target.limitDataMonthDescData("");

+                return $.i18n.prop('traffic_limit_data_text', ' ');

+            }else{

+			    // todo

+			}

+			

+            target.limitDataMonthDescData(target.limitDataMonth() + sv_trafficStaticalInfo.getTrafficUnitByScale(target.selectedDataUnit()));

+            return $.i18n.prop('traffic_limit_data_text', target.limitDataMonth() + sv_trafficStaticalInfo.getTrafficUnitByScale(target.selectedDataUnit()));

+        }	

+		// ÌײÍʱ¼äÃèÊöÓï	

+		function sf_limitTimeMonthDesc() {

+            if(isNaN(target.limitTimeMonth())) {

+                target.limitTimeMonthDescData(' ');

+				target.limitTimeMonthDescText('traffic_limit_time_h');

+                return $.i18n.prop('traffic_limit_time_h', ' ');

+            }else{

+			    // todo:

+			}

+			

+            target.limitTimeMonthDescData(target.limitTimeMonth());

+			

+			if(target.selectedTimeUnit() == "60"){

+				target.limitTimeMonthDescText('traffic_limit_time_m');

+				return $.i18n.prop('traffic_limit_time_m', target.limitTimeMonth());

+			}else{

+				target.limitTimeMonthDescText('traffic_limit_time_h');

+				return $.i18n.prop('traffic_limit_time_h', target.limitTimeMonth());

+			}		

+        }

+		

+        // Ó¦Óð´Å¥Ê¼þ

+        function sf_save() {

+            if (sv_trafficStaticalInfo.isFormEditable(target) && target.dataLimitChecked() == '1') {

+                return false;

+            }

+			

+            if (target.selectedDataUnit() == '1' && target.selectedDataUsedUnit() == '1048576' && target.dataLimitTypeChecked() == "1" && target.dataLimitChecked() == '1' && !(parseInt(target.dataUsed(), 10) < parseInt('4096', 10)) ) {

+                showAlert('traffic_over_note');

+				return false;

+            }

+			

+            showLoading();

+            service.setTrafficAlertInfo({

+			    alertDataReach: parseInt(target.alertDataReach(), 10),

+				alertTimeReach: parseInt(target.alertTimeReach(), 10),

+                dataLimitChecked: target.dataLimitChecked(),

+                dataLimitTypeChecked: target.dataLimitTypeChecked(),

+                limitDataMonth: target.limitDataMonth() + "_" + target.selectedDataUnit(),             

+                limitTimeMonth: target.selectedTimeUnit() == "60" ? target.limitTimeMonth()/60 : target.limitTimeMonth()//save by hours               

+            }, function (data) {

+                if (data.result == 'success') {

+                    if(target.dataLimitTypeChecked() == "1" && sv_usedDataModified) {

+                        target.saveUsedData();

+                    } else if(target.dataLimitTypeChecked() == "0" && sv_usedTimeModified) {

+                        target.saveUsedTime();

+                    } else {

+                        sv_trafficStaticalInfo.fetchTrafficAlertInfo();

+                        sv_trafficStaticalInfo.refreshFlowDiagramInfo(target);

+                        status.setTrafficAlertPopuped(false);

+                        successOverlay();

+                    }

+                } else {

+                    errorOverlay();

+                }

+            }, function () {

+                sv_trafficStaticalInfo.refreshFlowDiagramInfo(target);

+                errorOverlay();

+            });

+        }		

+		

+        // ±£´æÒÑÓÃÊý¾ÝÁ÷Á¿	

+		function sf_saveUsedData() {

+            var val = target.dataUsed() * target.selectedDataUsedUnit();

+            service.trafficCalibration({

+                way: 'data',

+                value: val

+            }, function(){

+                sv_trafficStaticalInfo.fetchTrafficAlertInfo();

+                sv_trafficStaticalInfo.refreshFlowDiagramInfo(target);

+                successOverlay();

+                target.viewEditUsedData(false);

+                status.setTrafficAlertPopuped(false);

+                sv_usedDataModified = false;

+            }, function(){

+                sv_trafficStaticalInfo.fetchTrafficAlertInfo();

+                sv_trafficStaticalInfo.refreshFlowDiagramInfo(target);

+                errorOverlay();

+            });

+        }	

+

+

+		

+		function sf_saveUsedTime() {

+            service.trafficCalibration({

+                way: 'time',

+                value: target.selectedTimeUsedUnit() == "60" ? parseFloat(target.usedTime())/60 : target.usedTime()

+            }, function(){

+                sv_trafficStaticalInfo.fetchTrafficAlertInfo();

+                sv_trafficStaticalInfo.refreshFlowDiagramInfo(target);

+                successOverlay();

+                target.monthlyConnectedTime(transSecond2Time(parseFloat(target.usedTime()) * target.selectedTimeUsedUnit()));

+                target.viewEditUsedTime(false);

+                status.setTrafficAlertPopuped(false);

+                sv_usedTimeModified = false;

+            }, function(){

+                sv_trafficStaticalInfo.fetchTrafficAlertInfo();

+                sv_trafficStaticalInfo.refreshFlowDiagramInfo(target);

+                errorOverlay();

+            });

+        }	

+

+		

+        // ÒÑÓÃÁ÷Á¿ÃèÊöÓï	

+		function sf_usedDataTextDesc() {

+            if(isNaN(target.dataUsed())) {

+                target.usedDataTextDescData("");

+                return $.i18n.prop('traffic_used_text', ' ');

+            }

+            target.usedDataTextDescData(target.dataUsed() + sv_trafficStaticalInfo.getTrafficUnitByScale(target.selectedDataUsedUnit()));

+            return $.i18n.prop('traffic_used_text', target.dataUsed() + sv_trafficStaticalInfo.getTrafficUnitByScale(target.selectedDataUsedUnit()));

+        }		

+        // ÒÑÓÃʱ¼äÃèÊöÓï

+        function sf_usedTimeTextDesc() {

+            target.usedTimeTextDescData(target.monthlyConnectedTime());

+            return $.i18n.prop('traffic_used_text', target.monthlyConnectedTime());

+        }			

+

+        

+    }

+	

+    function init() {

+        sv_trafficGraph = echarts.init($("#traffic_graphic")[0]);

+        window.onresize = sv_trafficGraph.resize;

+        var s_container = $('#container');

+        ko.cleanNode(s_container[0]);

+        var fwVm = new trafficViewModel();

+        ko.applyBindings(fwVm, s_container[0]);

+        $('#trafficAlertForm').validate({

+            submitHandler: function () {

+                fwVm.save();

+            },

+            

+			

+            errorPlacement: function (error, para) {

+                if (para.attr("name") == "alertDataReach") {

+                    error.insertAfter("#editAlertDataDiv");

+                } else if (para.attr("name") == "alertTimeReach") {

+                    error.insertAfter("#editAlertTimeDiv");

+                } else if (para.attr("name") == "dataUsed") {

+                    error.insertAfter("#editUsedDataDiv");

+                } else if (para.attr("name") == "limitDataMonth") {

+                    error.insertAfter("#editTotalDataDiv");

+                } else if (para.attr("name") == "limitTimeMonth") {

+                    error.insertAfter("#editTotalTimeDiv");

+                } else if (para.attr("name") == "usedTime") {

+                    error.insertAfter("#editUsedTimeDiv");

+                } else {

+                    error.insertAfter(para);

+                }

+            },

+

+            rules: {

+			    alertDataReach: {

+                    range: [ 1, 100 ],

+					digits: true

+                },

+                alertTimeReach: {

+                    range: [ 1, 100 ],

+                    digits: true

+                },

+                dataUsed: {

+					range : [ 0, 9999 ],

+					decimalRange : true

+                },

+                limitDataMonth: {

+					range : [ 1, 9999 ],

+					decimalRange : true

+                },

+                limitTimeMonth: {

+					range : [ 1, 9999 ],

+					decimalRange : true

+                },

+				usedTime: {

+					range : [ 0, 9999 ],

+					decimalRange : true

+                }  

+            }			

+			

+        });

+		

+		var sv_originalLan = window.language;

+		window.setInterval(function(){			

+			if(sv_originalLan != window.language){

+				sv_originalLan = window.language;

+				sv_trafficStaticalInfo.refreshFlowDiagramInfo(fwVm);

+			}

+        }, 1000);

+

+    }

+

+    return {

+        init: init

+    };

+});

+

+// ״̬À¸ÌáʾÓïʵÏÖ

+define("tooltip",[ "jquery" ], 

+    

+	function($) {	

+

+

+			// ¼ÆËãÔªËØÎ»ÖÃÐÅÏ¢

+			// @method calculatePositionInfo

+			// @param trigger ÔªËØ

+			// @param tooltip ״̬À¸

+			// @param {JSON} config λÖÃÅäÖÃ

+			

+			function calculatePositionInfo(trigger, tooltip, config) {

+				var top      = trigger.offset().top; 

+				var left     = trigger.offset().left; 

+				var position = config.position[0];

+				var height   = tooltip.outerHeight() + trigger.outerHeight();

+				var width    = tooltip.outerWidth() + trigger.outerWidth();

+

+				top         -= tooltip.outerHeight() - config.offset[0];

+				left        += trigger.outerWidth()  + config.offset[1];

+

+				if (/iPad/i.test(navigator.userAgent)) {

+					top -= $(window).scrollTop();

+				}

+

+				if (position == 'center') {

+					top += height / 2;

+				}

+				if (position == 'bottom') {

+					top += height;

+				}

+				position = config.position[1];

+				if (position == 'center') {

+					left -= width / 2;

+				}else if (position == 'left') {

+					left -= width;

+				}

+				

+				return {

+					top : top,

+					left : left

+				};

+			}	

+	

+			// ״̬À¸³õʼ»¯

+			function init() {

+

+				$(".statusItem", "#statusBar").each(function(i, n){

+					var $this = $(this);

+					$this.attr("tipTitle", $this.attr("title")).removeAttr("title");

+				}).hover(

+						function() {

+							var $this = $(this);

+							var title = $this.attr("tipTitle");

+							var tooltip = $("<div>").addClass("tooltip in").appendTo(document.body).hide()

+									.append($this.attr("i18n") ? $.i18n.prop(title) : title);

+							if ($this.attr("i18n")) {

+								tooltip.attr("data-trans", title).attr("id", "tooltip_" + $this.attr("id"));

+							}

+							var pos = calculatePositionInfo($this, tooltip, {

+								position : [ 'bottom', 'center' ],

+								offset : [ 0, 0 ]

+							});

+							tooltip.css({

+								position : 'absolute',

+								top : pos.top,

+								left : pos.left

+							}).show();

+						}, function() {

+							$(".tooltip").hide().remove();

+						});

+			}

+					

+			return {

+				init : init

+			};

+		});

+

+define("menu","set service knockout underscore jquery".split(" "),

+    function (set, fnc, libko, libus, libjq) {

+    var displayMenuWhenLogout = false;

+    var vmMenu;

+    var menu = [];

+    var menuResource = "";

+

+    function menuExistCheck(path) {

+        for (var i = 0; i < menu.length; i++) {

+            if (menu[i].path == path) {

+                return true;

+            }

+        }

+        return false;

+    }

+

+    function getIsLoggedin() {

+        var loginStatus = fnc.getLoginStatus();

+        return (loginStatus.status == "loggedIn");

+    }

+

+    function buildNew() {

+        var loggedIn = getIsLoggedin();

+        var menuMain = libus.filter(menu, function (param) {

+            return (param.level == '1' && ((param.requireLogin && loggedIn) || !param.requireLogin) && param.hash != "#entry");

+        });

+        vmMenu.menuMain(menuMain);

+        vmMenu.loggedIn(loggedIn);

+

+        getMainWth(vmMenu.menuMain().length);

+        vmMenu.showMenu(loggedIn || displayMenuWhenLogout);

+        libjq("#nav").translate();

+    }

+

+    function getMainWth(len) {

+        var width = 100 / len;

+        libjq('ul#list-nav li').each(function () {

+            libjq(this).css('width', width + '%');

+        });

+    }

+

+    function menuRefresh() {

+        var currentHash = window.location.hash;

+        var itmRoot = libus.find(menu, function (param) {

+            return param.hash == currentHash;

+        });

+        while (itmRoot.parent) {

+            itmRoot = libus.find(menu, function (param) {

+                return param.hash == itmRoot.parent;

+            });

+        }

+        if (!itmRoot.parent) {

+            libjq("#list-nav li").removeClass("active");

+            var mid = itmRoot.hash.substring(1, itmRoot.hash.length);

+            libjq("#list-nav li[mid=" + mid + "]").addClass("active");

+        }

+        vmMenu.changeMenu(itmRoot);

+    }

+

+    function menuSearch(hashVal) {

+        hashVal = hashVal || window.location.hash;

+        var loggedIn = getIsLoggedin();

+        return libus.filter(menu, function (param) {

+            return (hashVal == param.hash && ((param.requireLogin && loggedIn) || !param.requireLogin));

+        });

+    }

+

+    function menuRenderSub(level, baseItem) {

+        var levelItem = libus.find(menu, function (param) {

+            return param.parent == baseItem.hash && param.path == baseItem.path;

+        });

+        libjq(".menu-" + level + "-level").removeClass("active");

+        if (levelItem) {

+            if (level == "two") {

+                menuRenderSub("three", levelItem);

+                //forward/backward support

+                clickMenuTrig(levelItem.hash, level);

+            }

+            libjq(".menu-" + level + "-level." + levelItem.hash.substring(1)).addClass("active");

+        }

+    }

+

+    function menuActSub() {

+        var currentHash = window.location.hash;

+        var itmRoot = libus.find(menu, function (param) {

+            return param.hash == currentHash;

+        });

+        if (itmRoot.level == 1) {

+            menuRenderSub("two", itmRoot);

+        }

+        if (itmRoot.level == 2) {

+            menuRenderSub("three", itmRoot);

+            //forward/backward support

+            clickMenuTrig(itmRoot.hash, itmRoot.level);

+        }

+        if (itmRoot.level == 3) {

+            //forward/backward support

+            clickMenuTrig(itmRoot.parent, itmRoot.level);

+            libjq(".menu-three-level").removeClass("active");

+            libjq(".menu-three-level." + itmRoot.hash.substring(1)).addClass("active");

+        }

+    }

+

+    function clickMenuTrig(hash, level) {

+        libjqobj = libjq(".menu-two-level." + hash.substring(1));

+        var levelArr = ['3', 'three', '2', 'two'];

+        if (libus.indexOf(levelArr, level) != -1 && libjqobj.hasClass('active')) {

+            return;

+        }

+

+        libjqobj.siblings().removeClass('active');

+        libjqobj.addClass('active');

+

+        libjqobj.siblings().not('.menu-two-level').slideUp();

+        libjqobj.next().has('ul li').slideDown();

+    }

+

+    set.blc_wan_mode = fnc.getOpMode().blc_wan_mode;

+    if (!set.RJ45_SUPPORT) {

+        menuResource = "menu";

+    } else {

+        switch (set.blc_wan_mode) {

+        case "PPPOE":

+        case "AUTO_PPPOE":

+            menuResource = "menu_pppoe";

+            break;

+        default:

+            menuResource = "menu";

+            break;

+        }

+    }

+

+    require([set.DEVICE + '/' + menuResource], function (otherMenu) {

+        menu = otherMenu;

+        if (set.SD_CARD_SUPPORT) {

+            menu = menu.concat([{ hash: '#httpshare_guest', path: 'sd_httpshare', level: '', requireLogin: false, checkSIMStatus: false}, 

+						{ hash: '#sdcard', path: 'sd', level: '', requireLogin: true, checkSIMStatus: false}, 

+						{ hash: '#httpshare', path: 'sd_httpshare', level: '', requireLogin: true, checkSIMStatus: false}]);

+        }

+    });

+

+    function initialize() {

+        vmMenu = new Menu_vm();

+    }

+

+    function Menu_vm() {

+        var loginState = getIsLoggedin();

+		var target = this;

+        target.loggedIn = libko.observable(loginState);

+

+        target.showMenu = libko.observable(loginState || displayMenuWhenLogout);

+

+        var menuMain = libus.filter(menu, function (param) {

+            return (param.level == '1' && ((param.requireLogin && target.loggedIn()) || !param.requireLogin) && param.hash != "#entry");

+        });

+

+        target.menuMain = libko.observableArray(menuMain);

+        target.secondMenu = libko.observableArray([]);

+        //target.curThirdMenu; cov_2

+        target.changeMenu = function (data) {

+            var secondMenu = getSubMenu(data);

+            if (secondMenu.length == 0) {

+                libjq("#container").addClass("fixContainerWidth");

+            } else {

+                libjq("#container").removeClass("fixContainerWidth");

+            }

+

+            target.secondMenu(secondMenu);

+            return true;

+        };

+        target.thirdMenu = function () {

+            return target.curThirdMenu;

+        };

+        target.getThirdMenu = function (data) {

+            target.curThirdMenu = getSubMenu(data);

+        };

+        function getSubMenu(data) {

+            return libus.filter(menu, function (param) {

+                return ((param.parent && param.parent == data.hash) && ((param.requireLogin && target.loggedIn()) || !param.requireLogin));

+            });

+        }

+    }

+

+    return {

+        activeSubMenu: menuActSub,

+        checkIsMenuExist: menuExistCheck,

+        findMenu: menuSearch,

+        rebuild: buildNew,

+        refreshMenu: menuRefresh,

+		init: initialize

+    };

+});

+	
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/ext/crypto-js-null.js b/ap/app/zte_webui/js/ext/crypto-js-null.js
new file mode 100755
index 0000000..eb3a541
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/crypto-js-null.js
@@ -0,0 +1,25 @@
+;(function (root, factory) {
+	if (typeof exports === "object") {
+		// CommonJS
+		module.exports = exports = factory();
+	}
+	else if (typeof define === "function" && define.amd) {
+		// AMD
+		define([], factory);
+	}
+	else {
+		// Global (browser)
+		root.CryptoJS = factory();
+	}
+}(this, function () {
+
+	/*globals window, global, require*/
+
+	/**
+	 * CryptoJS core components.
+	 */
+	var CryptoJS = {};
+
+	return CryptoJS;
+
+}));
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/ext/menu.js b/ap/app/zte_webui/js/ext/menu.js
new file mode 100755
index 0000000..6277652
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/menu.js
@@ -0,0 +1,308 @@
+define(function () {

+    var needLogin = true;

+    var menu = [{

+            hash: '#more',

+            path: 'adm_others',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#filter_url',

+            path: 'firewall_url_filter',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin

+        }, {

+            hash: '#demilitarized_zone',

+            path: 'firewall_dmz_set',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#universal_plug_and_play',

+            path: 'firewall_upnp_set',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#map_port',

+            path: 'firewall_port_map',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#foward_port',

+            path: 'firewall_port_forward',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin

+        }, {

+            hash: '#filter_port',

+            path: 'firewall_port_filter',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_sleep',

+            path: 'wifi_sleep_mode',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pin_mode',

+            path: 'adm_pin',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#pwd_mode',

+            path: 'adm_management',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#filter_mac',

+            path: 'wifi_mac_filter',

+            level: '3',

+            parent: '#wlan_basic',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_wps',

+            path: 'wifi_wps',

+            level: '3',

+            parent: '#wlan_basic',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_adv',

+            path: 'wifi_advance',

+            level: '3',

+            parent: '#wlan_basic',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#conn_device',

+            path: 'wifi_station_info',

+            level: '3',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_guset',

+            path: 'wifi_guest',

+            level: '3',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_main',

+            path: 'wifi_main',

+            level: '3',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#fota',

+            path: 'ota_update',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#dynamic_dns',

+            path: 'ddns',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#cgdcont_set',

+            path: 'network_apn_set',

+            level: '3',

+            parent: '#network_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#network_choose',

+            path: 'network_net_select',

+            level: '3',

+            parent: '#network_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#conn_set',

+            path: 'network_dial_set',

+            level: '3',

+            parent: '#network_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        },

+        {

+            hash: '#wlan_station',

+            path: 'wifi_ap_station',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#msg_set',

+            path: 'sms_set',

+            level: '2',

+            parent: '#msg_main',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#msg_sim',

+            path: 'sms_sim_messages',

+            level: '2',

+            parent: '#msg_main',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#msg_list',

+            path: 'sms_list',

+            level: '2',

+            parent: '#msg_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#flow_ctl',

+            path: 'status_traffic_alert',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_work_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_friend_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_family_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_com_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_all_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#usat',

+            path: 'ussd',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#route_set',

+            path: 'adm_lan',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#filter_main',

+            path: 'firewall',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#local_set',

+            path: 'adm_management',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_basic',

+            path: 'wifi_basic',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#network_set',

+            path: 'network_dial_set_cpe',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#fast_set',

+            path: 'adm_quick_set',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        },

+        {

+            hash: '#child_ctl',

+            path: 'firewall_parental_control',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#normal_set',

+            path: 'adm_quick_set',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#pb_main',

+            path: 'phonebook',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#msg_main',

+            path: 'sms_list',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#main',

+            path: 'main',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#entry',

+            path: 'entry',

+            level: '1',

+            requireLogin: false,

+            checkSIMStatus: false

+        },

+    ];

+

+    return menu;

+});

diff --git a/ap/app/zte_webui/js/ext/menu_pppoe.js b/ap/app/zte_webui/js/ext/menu_pppoe.js
new file mode 100755
index 0000000..a1bf328
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/menu_pppoe.js
@@ -0,0 +1,308 @@
+define(function () {

+    var needLogin = true;

+    var menu = [{

+            hash: '#more',

+            path: 'adm_others',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#filter_url',

+            path: 'firewall_url_filter',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin

+        }, {

+            hash: '#demilitarized_zone',

+            path: 'firewall_dmz_set',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#universal_plug_and_play',

+            path: 'firewall_upnp_set',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#map_port',

+            path: 'firewall_port_map',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#foward_port',

+            path: 'firewall_port_forward',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin

+        }, {

+            hash: '#filter_port',

+            path: 'firewall_port_filter',

+            level: '3',

+            parent: '#filter_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_sleep',

+            path: 'wifi_sleep_mode',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pin_mode',

+            path: 'adm_pin',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#pwd_mode',

+            path: 'adm_management',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#filter_mac',

+            path: 'wifi_mac_filter',

+            level: '3',

+            parent: '#wlan_basic',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_wps',

+            path: 'wifi_wps',

+            level: '3',

+            parent: '#wlan_basic',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_adv',

+            path: 'wifi_advance',

+            level: '3',

+            parent: '#wlan_basic',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#conn_device',

+            path: 'wifi_station_info',

+            level: '3',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_guset',

+            path: 'wifi_guest',

+            level: '3',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_main',

+            path: 'wifi_main',

+            level: '3',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#fota',

+            path: 'ota_update',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#dynamic_dns',

+            path: 'ddns',

+            level: '3',

+            parent: '#local_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#cgdcont_set',

+            path: 'network_apn_set',

+            level: '3',

+            parent: '#network_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#network_choose',

+            path: 'network_net_select',

+            level: '3',

+            parent: '#network_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#conn_set',

+            path: 'network_dial_set',

+            level: '3',

+            parent: '#network_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        },

+        {

+            hash: '#wlan_station',

+            path: 'wifi_ap_station',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#msg_set',

+            path: 'sms_set',

+            level: '2',

+            parent: '#msg_main',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#msg_sim',

+            path: 'sms_sim_messages',

+            level: '2',

+            parent: '#msg_main',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#msg_list',

+            path: 'sms_list',

+            level: '2',

+            parent: '#msg_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#flow_ctl',

+            path: 'status_traffic_alert',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_work_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_friend_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_family_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_com_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#pb_all_grp',

+            path: 'phonebook',

+            level: '2',

+            parent: '#pb_main',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#usat',

+            path: 'ussd',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#route_set',

+            path: 'adm_lan',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#filter_main',

+            path: 'firewall',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#local_set',

+            path: 'adm_management',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#wlan_basic',

+            path: 'wifi_basic',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#network_set',

+            path: 'network_dial_set_cpe',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#fast_set',

+            path: 'adm_quick_set',

+            level: '2',

+            parent: '#normal_set',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        },

+        {

+            hash: '#child_ctl',

+            path: 'firewall_parental_control',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#normal_set',

+            path: 'adm_quick_set',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: true

+        }, {

+            hash: '#pb_main',

+            path: 'phonebook',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#msg_main',

+            path: 'sms_list',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#main',

+            path: 'main',

+            level: '1',

+            requireLogin: needLogin,

+            checkSIMStatus: false

+        }, {

+            hash: '#entry',

+            path: 'entry',

+            level: '1',

+            requireLogin: false,

+            checkSIMStatus: false

+        },

+    ];

+

+    return menu;

+});

diff --git a/ap/app/zte_webui/js/ext/set.js b/ap/app/zte_webui/js/ext/set.js
new file mode 100755
index 0000000..4be0732
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/set.js
@@ -0,0 +1,34 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Mobile Hotspot',

+        PRODUCT_TYPE: 'UFI', // ²úÆ·ÀàÐÍUFI¡¢CPE

+        HAS_BLACK_AND_WHITE_FILTER: true, //ÊÇ·ñÖ§³ÖºÚ°×Ãûµ¥

+        AP_STATION_SUPPORT: true,

+        MAX_STATION_NUMBER: 8,

+        STATION_BLOCK_SUPPORT: true, // ÒÑÁ¬½ÓÉ豸ÊÇ·ñÖ§³ÖBlock¹¦ÄÜ

+        HAS_MULTI_SSID: true, //¶àssid¹¦ÄÜ

+        WIFI_BANDWIDTH_SUPPORT_40MHZ: true, //Ƶ´ø¿í¶ÈÊÇ·ñÖ§³Ö40MHZ,reltekоƬ֧³Ö

+        WIFI_BANDWIDTH_SUPPORT: true,

+        WIFI_BAND_SUPPORT: true,

+        SD_CARD_SUPPORT: true, //ÊÇ·ñÖ§³ÖSD¿¨

+        DDNS_SUPPORT: false, //DDNS

+        NETWORK_UNLOCK_SUPPORT: true,

+        HAS_PHONEBOOK: false,

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+                value: 'TD_W'

+            }, {

+                name: '2G Only',

+                value: 'Only_GSM'

+            }

+        ]

+    };

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/ext/set_aic8800.js b/ap/app/zte_webui/js/ext/set_aic8800.js
new file mode 100755
index 0000000..c855342
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/set_aic8800.js
@@ -0,0 +1,59 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Mobile Hotspot',

+        PRODUCT_TYPE: 'UFI', // ²úÆ·ÀàÐÍUFI¡¢CPE

+        HAS_BLACK_AND_WHITE_FILTER: true, //ÊÇ·ñÖ§³ÖºÚ°×Ãûµ¥

+        AP_STATION_SUPPORT: true,

+        MAX_STATION_NUMBER: 8,

+        STATION_BLOCK_SUPPORT: true, // ÒÑÁ¬½ÓÉ豸ÊÇ·ñÖ§³ÖBlock¹¦ÄÜ

+        HAS_MULTI_SSID: true, //¶àssid¹¦ÄÜ

+        WIFI_BANDWIDTH_SUPPORT_40MHZ: true, //Ƶ´ø¿í¶ÈÊÇ·ñÖ§³Ö40MHZ,reltekоƬ֧³Ö

+        WIFI_BANDWIDTH_SUPPORT: true,

+        WIFI_BAND_SUPPORT: true,

+        SD_CARD_SUPPORT: true, //ÊÇ·ñÖ§³ÖSD¿¨

+        DDNS_SUPPORT: false, //DDNS

+        NETWORK_UNLOCK_SUPPORT: true,

+        NETWORK_MODES : [ {

+            name : '802.11 b/g/n/ax',

+            value : '6'

+        } ],

+        HAS_PHONEBOOK: false,

+        //station¼ÓÃÜģʽ

+        AUTH_MODES_ALL: [{

+                name: 'NO ENCRYPTION',

+                value: 'OPEN'

+            }, {

+                name: 'SHARED',

+                value: 'SHARED'

+            }, {

+                name: 'WPA-PSK',

+                value: 'WPAPSK'

+            }, {

+                name: 'WPA2-PSK',

+                value: 'WPA2PSK'

+            }, {

+                name: 'WPA-PSK/WPA2-PSK',

+                value: 'WPAPSKWPA2PSK'

+            }, {

+                name: 'WPA3-Personal',

+                value: 'WPA3Personal'

+            }, {

+                name: 'WPA2(AES)/WPA3-Personal',

+                value: 'WPA2WPA3'

+            }

+        ],

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+                value: 'Only_WCDMA'

+            }

+        ]

+    };

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/ext/set_cpe.js b/ap/app/zte_webui/js/ext/set_cpe.js
new file mode 100755
index 0000000..aa929eb
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/set_cpe.js
@@ -0,0 +1,42 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G CPE',

+        PRODUCT_TYPE: 'CPE', //²úÆ·ÀàÐÍUFI¡¢CPE

+        TURN_OFF_SUPPORT: false, //ÊÇ·ñÖ§³Ö¹Ø»ú

+        RJ45_SUPPORT: true, //ÊÇ·ñÖ§³Örj45

+        HAS_PARENTAL_CONTROL: true, // ÊÇ·ñÖ§³Ö¼Ò³¤¿ØÖƹ¦ÄÜ,

+        TSW_SUPPORT: true, // ÊÇ·ñÖ§³Ö¶¨Ê±ÐÝÃß»½ÐÑ

+        WIFI_SLEEP_SUPPORT: false, // ÊÇ·ñÖ§³ÖwifiÐÝÃß

+        HAS_BATTERY: false, //ÊÇ·ñÓÐµç³Ø

+        FAST_BOOT_SUPPORT: false, //ÊÇ·ñÖ§³Ö¿ìËÙ¿ª»ú

+        HAS_BLACK_AND_WHITE_FILTER: true, //ÊÇ·ñÖ§³ÖºÚ°×Ãûµ¥

+        AP_STATION_SUPPORT: true,

+        MAX_STATION_NUMBER: 8,

+        STATION_BLOCK_SUPPORT: true, // ÒÑÁ¬½ÓÉ豸ÊÇ·ñÖ§³ÖBlock¹¦ÄÜ

+        HAS_MULTI_SSID: true, //¶àssid¹¦ÄÜ

+        WIFI_BANDWIDTH_SUPPORT_40MHZ: true, //Ƶ´ø¿í¶ÈÊÇ·ñÖ§³Ö40MHZ,reltekоƬ֧³Ö

+        WIFI_BANDWIDTH_SUPPORT: true,

+        WIFI_BAND_SUPPORT: true,

+        SD_CARD_SUPPORT: false, //ÊÇ·ñÖ§³ÖSD¿¨

+        DDNS_SUPPORT: false, //DDNS

+        NETWORK_UNLOCK_SUPPORT: true,

+        HAS_PHONEBOOK: true,

+	PASSWORD_ENCODE: false, //false: aes, true: base64

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+                value: 'TD_W'

+            }, {

+                name: '2G Only',

+                value: 'Only_GSM'

+            }

+        ]

+    };

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/ext/set_cpe_sw.js b/ap/app/zte_webui/js/ext/set_cpe_sw.js
new file mode 100755
index 0000000..3e3e4da
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/set_cpe_sw.js
@@ -0,0 +1,42 @@
+define(function() {

+    var config = {

+        WEBUI_TITLE: '4G CPE',

+        PRODUCT_TYPE: 'CPE', //²úÆ·ÀàÐÍUFI¡¢CPE

+        TURN_OFF_SUPPORT: false, //ÊÇ·ñÖ§³Ö¹Ø»ú

+        RJ45_SUPPORT: true, //ÊÇ·ñÖ§³Örj45

+        HAS_PARENTAL_CONTROL: true, // ÊÇ·ñÖ§³Ö¼Ò³¤¿ØÖƹ¦ÄÜ,

+        TSW_SUPPORT: true, // ÊÇ·ñÖ§³Ö¶¨Ê±ÐÝÃß»½ÐÑ

+        WIFI_SLEEP_SUPPORT: false, // ÊÇ·ñÖ§³ÖwifiÐÝÃß

+        HAS_BATTERY: false, //ÊÇ·ñÓÐµç³Ø

+        FAST_BOOT_SUPPORT: false, //ÊÇ·ñÖ§³Ö¿ìËÙ¿ª»ú

+        HAS_BLACK_AND_WHITE_FILTER: true, //ÊÇ·ñÖ§³ÖºÚ°×Ãûµ¥

+        AP_STATION_SUPPORT: true,

+        MAX_STATION_NUMBER: 8,

+        STATION_BLOCK_SUPPORT: true, // ÒÑÁ¬½ÓÉ豸ÊÇ·ñÖ§³ÖBlock¹¦ÄÜ

+        HAS_MULTI_SSID: true, //¶àssid¹¦ÄÜ

+        WIFI_BANDWIDTH_SUPPORT_40MHZ: true, //Ƶ´ø¿í¶ÈÊÇ·ñÖ§³Ö40MHZ,reltekоƬ֧³Ö

+        WIFI_BANDWIDTH_SUPPORT: true,

+        WIFI_BAND_SUPPORT: true,

+        SD_CARD_SUPPORT: false, //ÊÇ·ñÖ§³ÖSD¿¨

+        DDNS_SUPPORT: false, //DDNS

+        NETWORK_UNLOCK_SUPPORT: true,

+        HAS_PHONEBOOK: true,

+	PASSWORD_ENCODE: false, //false: aes, true: base64

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+            value: 'Only_WCDMA'

+            }, {

+                name: '2G Only',

+                value: 'Only_GSM'

+            }

+        ]

+    };

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/ext/set_min.js b/ap/app/zte_webui/js/ext/set_min.js
new file mode 100755
index 0000000..e33eb5f
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/set_min.js
@@ -0,0 +1,45 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Mobile Hotspot',

+        PRODUCT_TYPE: 'UFI', // ²úÆ·ÀàÐÍUFI¡¢CPE

+        HAS_BLACK_AND_WHITE_FILTER: true, //ÊÇ·ñÖ§³ÖºÚ°×Ãûµ¥

+        AP_STATION_SUPPORT: true,

+        MAX_STATION_NUMBER: 8,

+        STATION_BLOCK_SUPPORT: true, // ÒÑÁ¬½ÓÉ豸ÊÇ·ñÖ§³ÖBlock¹¦ÄÜ

+        HAS_MULTI_SSID: true, //¶àssid¹¦ÄÜ

+        WIFI_BANDWIDTH_SUPPORT_40MHZ: true, //Ƶ´ø¿í¶ÈÊÇ·ñÖ§³Ö40MHZ,reltekоƬ֧³Ö

+        WIFI_BANDWIDTH_SUPPORT: true,

+        WIFI_BAND_SUPPORT: true,

+        WIFI_WAP3_SUPPORT: false, 

+        WIFI_WPA2_WAP3_SUPPORT: false, 

+        SD_CARD_SUPPORT: true, //ÊÇ·ñÖ§³ÖSD¿¨

+        DDNS_SUPPORT: false, //DDNS

+        NETWORK_UNLOCK_SUPPORT: true,

+        HAS_PHONEBOOK: false,

+        //wifi¼ÓÃÜģʽ

+        AUTH_MODES: [{

+                name: 'NO ENCRYPTION',

+                value: 'OPEN'

+            }, {

+                name: 'WPA2(AES)-PSK',

+                value: 'WPA2PSK'

+            }, {

+                name: 'WPA-PSK/WPA2-PSK',

+                value: 'WPAPSKWPA2PSK'

+            }

+        ],

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+                value: 'Only_WCDMA'

+            }

+        ]

+    };

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/ext/set_ssv6x5x.js b/ap/app/zte_webui/js/ext/set_ssv6x5x.js
new file mode 100755
index 0000000..43f3f9f
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/set_ssv6x5x.js
@@ -0,0 +1,48 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Mobile Hotspot',

+        PRODUCT_TYPE: 'UFI', // ²úÆ·ÀàÐÍUFI¡¢CPE

+        HAS_BLACK_AND_WHITE_FILTER: true, //ÊÇ·ñÖ§³ÖºÚ°×Ãûµ¥

+        AP_STATION_SUPPORT: true,

+        MAX_STATION_NUMBER: 8,

+        STATION_BLOCK_SUPPORT: true, // ÒÑÁ¬½ÓÉ豸ÊÇ·ñÖ§³ÖBlock¹¦ÄÜ

+        WIFI_BANDWIDTH_SUPPORT_40MHZ: true, //Ƶ´ø¿í¶ÈÊÇ·ñÖ§³Ö40MHZ,reltekоƬ֧³Ö

+        WIFI_BANDWIDTH_SUPPORT: true,

+        WIFI_BAND_SUPPORT: true,

+        WIFI_WAP3_SUPPORT: false, 

+        WIFI_WPA2_WAP3_SUPPORT: false, 

+        SD_CARD_SUPPORT: true, //ÊÇ·ñÖ§³ÖSD¿¨

+        DDNS_SUPPORT: false, //DDNS

+        NETWORK_UNLOCK_SUPPORT: true,

+        NETWORK_MODES : [ {

+            name : '802.11 b/g/n',

+            value : '4'

+        } ],		

+        HAS_PHONEBOOK: false,

+        //wifi¼ÓÃÜģʽ

+        AUTH_MODES: [{

+                name: 'NO ENCRYPTION',

+                value: 'OPEN'

+            }, {

+                name: 'WPA2(AES)-PSK',

+                value: 'WPA2PSK'

+            }, {

+                name: 'WPA-PSK/WPA2-PSK',

+                value: 'WPAPSKWPA2PSK'

+            }

+        ],

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+                value: 'Only_WCDMA'

+            }

+        ]

+    };

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/ext/set_xr819.js b/ap/app/zte_webui/js/ext/set_xr819.js
new file mode 100755
index 0000000..6c8a276
--- /dev/null
+++ b/ap/app/zte_webui/js/ext/set_xr819.js
@@ -0,0 +1,46 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Mobile Hotspot',

+        PRODUCT_TYPE: 'UFI', // ²úÆ·ÀàÐÍUFI¡¢CPE

+        HAS_BLACK_AND_WHITE_FILTER: true, //ÊÇ·ñÖ§³ÖºÚ°×Ãûµ¥

+        MAX_STATION_NUMBER: 8,

+        STATION_BLOCK_SUPPORT: true, // ÒÑÁ¬½ÓÉ豸ÊÇ·ñÖ§³ÖBlock¹¦ÄÜ

+        WIFI_BANDWIDTH_SUPPORT: true,

+        WIFI_BAND_SUPPORT: true,

+        WIFI_WAP3_SUPPORT: false, 

+        WIFI_WPA2_WAP3_SUPPORT: false, 

+        SD_CARD_SUPPORT: true, //ÊÇ·ñÖ§³ÖSD¿¨

+        DDNS_SUPPORT: false, //DDNS

+        NETWORK_UNLOCK_SUPPORT: true,

+        NETWORK_MODES : [ {

+            name : '802.11 b/g/n',

+            value : '4'

+        } ],		

+        HAS_PHONEBOOK: false,

+        //wifi¼ÓÃÜģʽ

+        AUTH_MODES: [{

+                name: 'NO ENCRYPTION',

+                value: 'OPEN'

+            }, {

+                name: 'WPA2(AES)-PSK',

+                value: 'WPA2PSK'

+            }, {

+                name: 'WPA-PSK/WPA2-PSK',

+                value: 'WPAPSKWPA2PSK'

+            }

+        ],

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+                value: 'Only_WCDMA'

+            }

+        ]

+    };

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/lib.js b/ap/app/zte_webui/js/lib.js
new file mode 100755
index 0000000..59354d2
--- /dev/null
+++ b/ap/app/zte_webui/js/lib.js
@@ -0,0 +1,1114 @@
+function restartDevice(service) {

+    showLoading("restarting");

+    service.restart({}, function (data) {

+        if (data && data.result == "success") {

+            successOverlay();

+        } else {

+            errorOverlay();

+        }

+    }, $.noop);

+}

+function signalFormat(signal) {

+    if (signal) {

+        if (signal > 0) {

+            return "-" + signal + " dBm";

+        } else {

+            return signal + " dBm";

+        }

+    } else {

+        return "— —";

+    }

+}

+function convertSignal(data) {

+    var type_2g = ["GSM", "GPRS", "EDGE", "G", "E"];

+    var type_3g = ["UMTS", "HSDPA", "HSUPA", "HSPA", "HSPA+", "DC-HSPA+", "WCDMA", "TD-SCDMA", "TD", "3G", "TD_SCDMA"];

+    var type_4g = ["LTE", "4G", "FDD", "TDD", "TDD-LTE", "FDD-LTE", "TDD_LTE", "FDD_LTE"];

+    var network_type = data.sub_network_type ? data.sub_network_type : (data.network_type ? data.network_type : '');

+    if ($.inArray(network_type, type_2g) != -1) {

+        return data.rssi;

+    } else if ($.inArray(network_type, type_3g) != -1) {

+        return data.rscp;

+    } else if ($.inArray(network_type, type_4g) != -1) {

+        return data.lte_rsrp;

+    }

+}

+

+function verifyDeviceInfo(field) {

+    if (field && field != "" && field != "0.0.0.0") {

+        return field;

+    } else {

+        return "— —";

+    }

+}

+$(document).ready(function () {

+    $("body").click(function (evt) {

+        var $popover = $(".popover");

+        var $target = $(evt.target);

+        if ((evt.target.id != $popover.data('source') && $target.parents('.popover').length == 0) || $target.hasClass("popover-close")) {

+            popover.close();

+        }

+    });

+});

+var popover = {

+    popoverEle: null,

+    _init: function () {

+        if (this.popoverEle == null) {

+            $("body").append('<div class="popover"></div>');

+            this.popoverEle = $(".popover");

+        }

+    },

+    open: function (opt) {

+        this._init();

+        var offset = opt.target.offset();

+        var top = offset.top + opt.target.outerHeight();

+        this.popoverEle.html(opt.html).css({

+            width: opt.width,

+            left: offset.left,

+            top: top

+        }).data({

+            source: opt.target[0].id

+        }).translate();

+        setTimeout(function () {

+            popover.popoverEle.show();

+        }, 100);

+        this.popoverEle.translate();

+        opt.validation && opt.validation.apply();

+    },

+    close: function () {

+        this.popoverEle && this.popoverEle.fadeOut();

+    },

+    show: function () {

+        this.popoverEle && this.popoverEle.show();

+    },

+    hide: function () {

+        this.popoverEle && this.popoverEle.hide();

+    }

+};

+function isWifiConnected(user_ip_addr, station_list) {

+    return !!_.find(station_list, function (station) {

+        return station.ip_addr == user_ip_addr;

+    });

+}

+function trim(stringToTrim) {

+    return stringToTrim.replace(/^\s+|\s+$/g, "");

+}

+

+function renderCustomElement(container) {

+    if (!container) {

+        container = $("#container");

+    }

+    var radios = container.find("input[type='radio']");

+    var checkboxes = container.find("input[type='checkbox']");

+    $.each(radios, function (i, n) {

+        var $el = $(n),

+        ch = 'checked',

+        checkAction = $el.prop('checked') ? true : false;

+        $el.closest('.radio')[checkAction ? 'addClass' : 'removeClass'](ch) && checkAction ? $el.attr(ch, true) : $el.removeAttr(ch);

+    });

+    $.each(checkboxes, function (i, n) {

+        var $el = $(n),

+        ch = 'checked',

+        checkAction = $el.prop('checked') ? true : false;

+        $el.closest('.checkbox')[checkAction ? 'addClass' : 'removeClass'](ch) && checkAction ? $el.attr(ch, true) : $el.removeAttr(ch);

+    });

+}

+

+function getSelectValFromChosen(choices) {

+    var choicesNums = [];

+    $.each(choices, function (i, n) {

+        var arr = $(n).text().split('/');

+        choicesNums.push(arr[arr.length - 1]);

+    });

+    return choicesNums;

+}

+function syncSelectAndChosen(select, choices) {

+    var choicesNums = getSelectValFromChosen(choices);

+    select.val(choicesNums);

+    return choicesNums;

+}

+

+function getPercent(numerator, denominator, accuracy) {

+    if (accuracy) {

+        accuracy = accuracy * 10;

+    } else {

+        accuracy = 100;

+    }

+    return roundToTwoDecimalNumber(numerator / denominator * accuracy) + "%";

+}

+function checkConnectedStatus(modemConnStatus, rj45ConnStatus, apConnStatus) {

+    return modemConnStatus == "ppp_connected" || rj45ConnStatus == "working" || apConnStatus == "connect";

+}

+

+function enableBtn(ele) {

+    ele.removeAttr("disabled").removeClass("disabled");

+}

+function replaceSpaceWithNbsp(str) {

+    return str.replace(/ /g, '&nbsp;');

+}

+function URLEncodeComponent(url) {

+    return encodeURIComponent(url);

+}

+function URLEncode(url) {

+    return encodeURI(url);

+}

+function checkCableMode(currentMode) {

+    return currentMode == "PPPOE" || currentMode == "AUTO_PPPOE";

+}

+function disableBtn(ele) {

+    ele.attr("disabled", "disabled").removeClass("focusIn").addClass("disabled");

+}

+var Escape = {

+    html: function (string) {

+        return (string + '').replace(/[&<>"'\/`]/g, Escape._htmlReplacer);

+    },

+    regex: function (string) {

+        return (string + '').replace(/[\-$\^*()+\[\]{}|\\,.?\s]/g, '\\$&');

+    },

+    _htmlReplacer: function (match) {

+        return Escape.HTML_CHARS[match];

+    },

+    HTML_CHARS: {

+        '&': '&amp;',

+        '<': '&lt;',

+        '>': '&gt;',

+        '"': '&quot;',

+        "'": '&#x27;',

+        '/': '&#x2F;',

+        '`': '&#x60;'

+    }

+};

+function roundToTwoDecimalNumber(num) {

+    return Math.round(num * 100) / 100;

+}

+function HTMLEncode(html) {

+    return Escape.html(html);

+}

+function HTMLDecode(text) {

+    var temp = document.createElement("div");

+    temp.innerHTML = text;

+    var output = temp.innerText || temp.textContent;

+    output = output.replace(new RegExp("&nbsp;", "gm"), " ");

+    temp = null;

+    return output;

+}

+function getDisplayVolume1(volume, isSpeed) {

+    volume = parseInt(volume, 10);

+    if (volume == "" || volume == "0") {

+        return "";

+    }

+    var needReverse = false;

+    if (volume < 0) {

+        needReverse = true;

+        volume = 0 - volume;

+    }

+    var numberOfBytesInOneB = 1;

+    var numberOfBytesInOneKB = numberOfBytesInOneB * 1024;

+    var numberOfBytesInOneMB = numberOfBytesInOneKB * 1024;

+    var numberOfBytesInOneGB = numberOfBytesInOneMB * 1024;

+    var numberOfBytesInOneTB = numberOfBytesInOneGB * 1024;

+    var labelForOneB = isSpeed ? 'b' : 'B';

+    var labelForOneKB = isSpeed ? 'Kb' : 'KB';

+    var labelForOneMB = isSpeed ? 'Mb' : 'MB';

+    var labelForOneGB = isSpeed ? 'Gb' : 'GB';

+    var labelForOneTB = isSpeed ? 'Tb' : 'TB';

+    if (isSpeed) {

+        volume = volume * 8;

+    }

+    var vol = volume / numberOfBytesInOneTB;

+    var displayString = roundToTwoDecimalNumber(vol) + labelForOneTB;

+    if (vol < 0.5) {

+        vol = volume / numberOfBytesInOneGB;

+        displayString = roundToTwoDecimalNumber(vol) + labelForOneGB;

+        if (vol < 0.5) {

+            vol = volume / numberOfBytesInOneMB;

+            displayString = roundToTwoDecimalNumber(vol) + labelForOneMB;

+            if (isSpeed) {

+                if (vol < 0.5) {

+                    vol = volume / numberOfBytesInOneKB;

+                    displayString = roundToTwoDecimalNumber(vol) + labelForOneKB;

+                    if (vol < 0.5) {

+                        vol = volume;

+                        displayString = roundToTwoDecimalNumber(vol) + labelForOneB;

+                    }

+                }

+            }

+        }

+    }

+    if (needReverse) {

+        displayString = "-" + displayString;

+    }

+    return displayString;

+}

+function getDisplayVolume(volume, isSpeed) {

+    volume = parseInt(volume, 10);

+    if (volume == "" || volume == "0") {

+        return "";

+    }

+    var needReverse = false;

+    if (volume < 0) {

+        needReverse = true;

+        volume = 0 - volume;

+    }

+    var numberOfBytesInOneB = 1;

+    var numberOfBytesInOneKB = numberOfBytesInOneB * 1024;

+    var numberOfBytesInOneMB = numberOfBytesInOneKB * 1024;

+    var numberOfBytesInOneGB = numberOfBytesInOneMB * 1024;

+    var numberOfBytesInOneTB = numberOfBytesInOneGB * 1024;

+    var labelForOneB = isSpeed ? 'b' : 'B';

+    var labelForOneKB = isSpeed ? 'Kb' : 'KB';

+    var labelForOneMB = isSpeed ? 'Mb' : 'MB';

+    var labelForOneGB = isSpeed ? 'Gb' : 'GB';

+    var labelForOneTB = isSpeed ? 'Tb' : 'TB';

+    if (isSpeed) {

+        volume = volume * 8;

+    }

+    var vol = volume / numberOfBytesInOneTB;

+    var displayString = roundToTwoDecimalNumber(vol) + labelForOneTB;

+    if (vol < 0.5) {

+        vol = volume / numberOfBytesInOneGB;

+        displayString = roundToTwoDecimalNumber(vol) + labelForOneGB;

+        if (vol < 0.5) {

+            vol = volume / numberOfBytesInOneMB;

+            displayString = roundToTwoDecimalNumber(vol) + labelForOneMB;

+            if (vol < 0.5) {

+                vol = volume / numberOfBytesInOneKB;

+                displayString = roundToTwoDecimalNumber(vol) + labelForOneKB;

+                if (vol < 0.5) {

+                    vol = volume;

+                    displayString = roundToTwoDecimalNumber(vol) + labelForOneB;

+                }

+            }

+        }

+    }

+    if (needReverse) {

+        displayString = "-" + displayString;

+    }

+    return displayString;

+}

+function transUnit(data, isSpeed) {

+    var result = getDisplayVolume1(data, isSpeed);

+    if (result == "") {

+        result = isSpeed ? "0b" : "0MB";

+    }

+    if (isSpeed) {

+        result += "/s";

+    }

+    return result;

+}

+function transTimeUnit(data) {

+    data = parseFloat(data);

+    if (data == "") {

+        return result = "0hour";

+    }

+    var needReverse = false;

+    if (data < 0) {

+        needReverse = true;

+        data = 0 - data;

+    }

+    var labelForOneMinute = 'minute';

+    var labelForOneHour = 'hour';

+    var vol = data / 3600;

+    var result = roundToTwoDecimalNumber(vol) + labelForOneHour;

+    if (vol < 1) {

+        vol = data / 60;

+        result = roundToTwoDecimalNumber(vol) + labelForOneMinute;

+    }

+    if (needReverse) {

+        result = "-" + result;

+    }

+    return result;

+}

+function transSecond2Time(secs) {

+    secs = parseInt(secs, 10);

+    var isNegative = false;

+    if (secs < 0) {

+        isNegative = true;

+        secs = 0 - secs;

+    }

+    var hour = Math.floor(secs / 3600);

+    secs = secs % 3600;

+    var minu = Math.floor(secs / 60);

+    secs = secs % 60;

+    return (isNegative ? '-' : '') + leftInsert(hour, 2, '0') + ":" + leftInsert(minu, 2, '0') + ":" + leftInsert(secs, 2, '0');

+}

+function leftInsert(value, length, placeholder) {

+    var len = value.toString().length;

+    for (; len < length; len++) {

+        value = placeholder + value;

+    }

+    return value;

+}

+

+var _timeoutStack = [];

+var _intervalStack = [];

+function addTimeout(code, delay) {

+    var time = window.setTimeout(code, delay);

+    _timeoutStack.push(time);

+    return time;

+}

+function addInterval(code, delay) {

+    var time = window.setInterval(code, delay);

+    _intervalStack.push(time);

+    return time;

+}

+function clearTimer() {

+    clearTimeoutTimer();

+    clearIntervalTimer();

+}

+function clearTimeoutTimer() {

+    for (var i = 0; i < _timeoutStack.length; i++) {

+        window.clearTimeout(_timeoutStack[i]);

+    }

+    _timeoutStack = [];

+}

+function clearIntervalTimer() {

+    for (var i = 0; i < _intervalStack.length; i++) {

+        window.clearInterval(_intervalStack[i]);

+    }

+    _intervalStack = [];

+}

+$(document).ready(function () {

+    $("[manualControl!=true].checkbox").live("click", function (event) {

+        var $this = $(this);

+        if ($this.hasClass('disable')) {

+            return false;

+        }

+        var checkbox = $this.find("input:checkbox");

+        if (checkbox.attr("checked")) {

+            checkbox.removeAttr("checked");

+        } else {

+            checkbox.attr("checked", "checked");

+        }

+        checkCheckbox(checkbox);

+        event.stopPropagation();

+        return true;

+    });

+    $('input[type="text"][noAction!="true"],input[type="password"][noAction!="true"],select').live("focusin", function (event) {

+        $(this).addClass("focusIn");

+    }).live("focusout", function (event) {

+        $(this).removeClass("focusIn");

+    });

+    $(".form-note .notes-title").live('click', function () {

+        var $this = $(this);

+        $this.siblings("ul.notes-content:first").slideToggle();

+        $this.toggleClass("notes-dot");

+    });

+});

+var GSM7_Table = ["000A", "000C", "000D", "0020", "0021", "0022", "0023", "0024", "0025", "0026", "0027", "0028", "0029", "002A", "002B", "002C", "002D", "002E", "002F", "0030", "0031", "0032", "0033", "0034", "0035", "0036", "0037", "0038", "0039", "003A", "003A", "003B", "003C", "003D", "003E", "003F", "0040", "0041", "0042", "0043", "0044", "0045", "0046", "0047", "0048", "0049", "004A", "004B", "004C", "004D", "004E", "004F", "0050", "0051", "0052", "0053", "0054", "0055", "0056", "0057", "0058", "0059", "005A", "005B", "005C", "005D", "005E", "005F", "0061", "0062", "0063", "0064", "0065", "0066", "0067", "0068", "0069", "006A", "006B", "006C", "006D", "006E", "006F", "0070", "0071", "0072", "0073", "0074", "0075", "0076", "0077", "0078", "0079", "007A", "007B", "007C", "007D", "007E", "00A0", "00A1", "00A3", "00A4", "00A5", "00A7", "00BF", "00C4", "00C5", "00C6", "00C7", "00C9", "00D1", "00D6", "00D8", "00DC", "00DF", "00E0", "00E4", "00E5", "00E6", "00E8", "00E9", "00EC", "00F1", "00F2", "00F6", "00F8", "00F9", "00FC", "0393", "0394", "0398", "039B", "039E", "03A0", "03A3", "03A6", "03A8", "03A9", "20AC"];

+var GSM7_Table_Extend = ["007B", "007D", "005B", "005D", "007E", "005C", "005E", "20AC", "007C"];

+function getEncodeType(strMessage) {

+    var encodeType = "GSM7_default";

+    var gsm7_extend_char_len = 0;

+    if (!strMessage) {

+        return {

+            encodeType: encodeType,

+            extendLen: gsm7_extend_char_len

+        };

+    }

+    for (var i = 0; i < strMessage.length; i++) {

+        var charCode = strMessage.charCodeAt(i).toString(16).toUpperCase();

+        while (charCode.length != 4) {

+            charCode = "0" + charCode;

+        }

+        if ($.inArray(charCode, GSM7_Table_Extend) != -1) {

+            gsm7_extend_char_len++;

+        }

+        if ($.inArray(charCode, GSM7_Table) == -1) {

+            encodeType = "UNICODE";

+            gsm7_extend_char_len = 0;

+            break;

+        }

+    }

+    return {

+        encodeType: encodeType,

+        extendLen: gsm7_extend_char_len

+    };

+}

+function encodeMessage(textString) {

+    var haut = 0;

+    var result = '';

+    if (!textString)

+        return result;

+    for (var i = 0; i < textString.length; i++) {

+        var b = textString.charCodeAt(i);

+        if (haut != 0) {

+            if (0xDC00 <= b && b <= 0xDFFF) {

+                result += dec2hex(0x10000 + ((haut - 0xD800) << 10) + (b - 0xDC00));

+                haut = 0;

+                continue;

+            } else {

+                haut = 0;

+            }

+        }

+        if (0xD800 <= b && b <= 0xDBFF) {

+            haut = b;

+        } else {

+            cp = dec2hex(b);

+            while (cp.length < 4) {

+                cp = '0' + cp;

+            }

+            result += cp;

+        }

+    }

+    return result;

+}

+var specialChars = ['000D', '000A', '0009', '0000'];

+var specialCharsIgnoreWrap = ['0009', '0000'];

+function decodeMessage(str, ignoreWrap) {

+    if (!str)

+        return "";

+    var specials = specialCharsIgnoreWrap;

+    return str.replace(/([A-Fa-f0-9]{1,4})/g, function (matchstr, parens) {

+        if ($.inArray(parens, specials) == -1) {

+            return hex2char(parens);

+        } else {

+            return '';

+        }

+    });

+}

+function dec2hex(textString) {

+    return (textString + 0).toString(16).toUpperCase();

+}

+function hex2char(hex) {

+    var result = '';

+    var n = parseInt(hex, 16);

+    if (n <= 0xFFFF) {

+        result += String.fromCharCode(n);

+    } else if (n <= 0x10FFFF) {

+        n -= 0x10000;

+        result += String.fromCharCode(0xD800 | (n >> 10)) + String.fromCharCode(0xDC00 | (n & 0x3FF));

+    }

+    return result;

+}

+function renderCheckbox() {

+    var checkboxToggle = $(".checkboxToggle");

+    checkboxToggle.each(function () {

+        checkBoxesSize($(this));

+    });

+    var checkboxes = $(".checkbox").not("[class*='checkboxToggle']").find("input:checkbox");

+    if (checkboxes.length == 0) {

+        disableCheckbox(checkboxToggle);

+    } else {

+        enableCheckbox(checkboxToggle);

+    }

+    checkboxes.each(function () {

+        checkCheckbox($(this));

+    });

+}

+function checkBoxesSize(selectAll) {

+    var target = selectAll.attr("target");

+    var boxSize = $("#" + target + " .checkbox input:checkbox").length;

+    var checkedBoxSize = $("#" + target + " .checkbox input:checkbox:checked").length;

+    var checkbox = selectAll.find("input:checkbox");

+    if (boxSize != 0 && boxSize == checkedBoxSize) {

+        checkbox.attr("checked", "checked");

+    } else {

+        checkbox.removeAttr("checked");

+    }

+    checkP(checkbox);

+}

+function checkSelectAll(selectAll, target) {

+    var theCheckbox = $("#" + target + " .checkbox input:checkbox");

+    if (selectAll.attr("checked")) {

+        theCheckbox.attr("checked", "checked");

+    } else {

+        theCheckbox.removeAttr("checked");

+    }

+    theCheckbox.each(function () {

+        checkCheckbox($(this));

+    });

+}

+function checkCheckbox(checkbox) {

+    if (checkbox.closest("p.checkbox").hasClass("checkboxToggle")) {

+        checkSelectAll(checkbox, checkbox.closest("p.checkbox").attr("target"));

+    }

+    checkP(checkbox);

+    checkBoxesSize($("#" + checkbox.attr("target")));

+}

+function checkP(checkbox) {

+    if (checkbox.attr("checked")) {

+        checkbox.closest("p.checkbox").addClass("checkbox_selected");

+    } else {

+        checkbox.closest("p.checkbox").removeClass("checkbox_selected");

+    }

+}

+function removeChecked(id) {

+    $("#" + id).removeClass("checkbox_selected").find("input:checkbox").removeAttr("checked");

+}

+function disableCheckbox(checkbox) {

+    var chk = checkbox.find("input:checkbox");

+    if (chk.attr("checked")) {

+        checkbox.addClass('checked_disable');

+    } else {

+        checkbox.addClass('disable');

+    }

+}

+function enableCheckbox(checkbox) {

+    checkbox.removeClass('disable').removeClass("checked_disable");

+}

+function tryToDisableCheckAll(checkbox, len) {

+    if (len == 0) {

+        disableCheckbox(checkbox);

+    } else {

+        enableCheckbox(checkbox);

+    }

+}

+

+function escapeMessage(msg) {

+    return msg;

+}

+function parseTime(date) {

+    if (date.indexOf("+") > -1) {

+        date = date.substring(0, date.lastIndexOf("+"));

+    }

+    var dateArr;

+    if (date.indexOf(",") > -1) {

+        dateArr = date.split(",");

+    } else {

+        dateArr = date.split(";");

+    }

+    if (dateArr.length == 0) {

+        return "";

+    } else {

+        var time = dateArr[0] + "-" + dateArr[1] + "-" + dateArr[2] + " " + leftInsert(dateArr[3], 2, '0') + ":" + leftInsert(dateArr[4], 2, '0') + ":"

+            +leftInsert(dateArr[5], 2, '0');

+        return time;

+    }

+}

+function transTime(data) {

+    var dateArr = data.split(",");

+    if (dateArr.length == 0 || ("," + data + ",").indexOf(",,") != -1) {

+        return "";

+    } else {

+        var time = dateArr[0] + "/" + dateArr[1] + "/" + dateArr[2] + " " + leftInsert(dateArr[3], 2, '0') + ":" + leftInsert(dateArr[4], 2, '0') + ":"

+            +leftInsert(dateArr[5], 2, '0');

+        return time;

+    }

+}

+function getSmsCount(str) {

+    var encodeType = getEncodeType(str);

+    var len = str.length,

+    gsm7 = encodeType.encodeType != "UNICODE",

+    needChunking = false,

+    chunkSize = 0;

+    if (gsm7) {

+        needChunking = (len + encodeType.extendLen) > 160;

+        chunkSize = 153;

+    } else {

+        needChunking = len > 70;

+        chunkSize = 67;

+    }

+    if (needChunking) {

+        return Math.ceil((len + encodeType.extendLen) / chunkSize);

+    } else {

+        return 1;

+    }

+}

+function getInsertPos(textbox) {

+    var iPos = 0;

+    if (textbox.selectionStart || textbox.selectionStart == "0") {

+        iPos = textbox.selectionStart;

+    } else if (document.selection) {

+        textbox.focus();

+        var range = document.selection.createRange();

+        var rangeCopy = range.duplicate();

+        rangeCopy.moveToElementText(textbox);

+        while (range.compareEndPoints("StartToStart", rangeCopy) > 0) {

+            range.moveStart("character", -1);

+            iPos++;

+        }

+    }

+    return iPos;

+}

+function setInsertPos(textbox, iPos) {

+    textbox.focus();

+    if (textbox.selectionStart || textbox.selectionStart == "0") {

+        textbox.selectionStart = iPos;

+        textbox.selectionEnd = iPos;

+    } else if (document.selection) {

+        var range = textbox.createTextRange();

+        range.moveStart("character", iPos);

+        range.collapse(true);

+        range.select();

+    }

+}

+function isIntNum(input, num) {

+    for (var i = 1; i < 6; i++) {

+        if (input == i * num) {

+            return true;

+        }

+    }

+    return false;

+}

+

+function transUnixTime(millisecond) {

+    var time = new Date(parseInt(millisecond, 10));

+    var year = time.getFullYear();

+    var month = leftPad(time.getMonth() + 1, 2, "0");

+    var date = leftPad(time.getDate(), 2, "0");

+    var hour = leftPad(time.getHours(), 2, "0");

+    var minute = leftPad(time.getMinutes(), 2, "0");

+    var second = leftPad(time.getSeconds(), 2, "0");

+    return year + "-" + month + "-" + date + " " + hour + ":" + minute + ":" + second;

+}

+function leftPad(value, length, placeholder) {

+    var len = value.toString().length;

+    for (; len < length; len++) {

+        value = placeholder + value;

+    }

+    return value;

+};

+function convertNumberToId(number) {

+    return number.replace(/[\+\*#]/g, '_');

+}

+function getLastNumber(number, len) {

+    if (number.length > len) {

+        return convertNumberToId(number.substring(number.length - len, number.length));

+    }

+    return convertNumberToId(number);

+}

+function fixTableHeight() {

+    if ($.browser.msie) {

+        var heightTimer = setInterval(function () {

+            var $table = $(".fixTableScroll")[0];

+            if ($table) {

+                var scrollHeight = $table.scrollHeight;

+                if (scrollHeight != 0) {

+                    $table.style.height = scrollHeight + 20;

+                    window.clearInterval(heightTimer);

+                }

+            } else {

+                window.clearInterval(heightTimer);

+            }

+        }, 300);

+    }

+}

+function refreshTableHeight() {

+    if ($.browser.msie) {

+        $(".fixTableScroll")[0].style.height = $(".fixTableScroll .ko-grid-container")[0].scrollHeight + 35;

+    }

+}

+

+function popup(option) {

+    $.modal.close();

+    var minHeight = option.minHeight || 140;

+    $('#confirm').modal({

+        zIndex: 3000,

+        position: ["30%"],

+        overlayId: 'confirm-overlay',

+        containerId: 'confirm-container',

+        escClose: false,

+        minHeight: minHeight

+    });

+    var $confirmDiv = $('div#confirm');

+    $('#confirmImg', $confirmDiv).attr('src', option.img);

+    $('#popTitle', $confirmDiv).html($.i18n.prop(option.title));

+    if (typeof option.msg != 'string') {

+        var params = [option.msg.msg];

+        params.push(option.msg.params);

+        $('.message', $confirmDiv).html($.i18n.prop.apply(null, _.flatten(params)));      

+    } else {

+		$('.message', $confirmDiv).html($.i18n.prop(option.msg));

+    }

+    var $promptDiv = $("div.promptDiv", $confirmDiv);

+    if (option.showInput === true) {

+        $promptDiv.show();

+        $("input#promptInput", $promptDiv).val(option.defaultValue ? option.defaultValue : "");

+        $(".promptErrorLabel", $promptDiv).empty();

+    } else {

+        $promptDiv.hide();

+    }

+    window.setTimeout(function () {

+        $(':input:enabled:visible:first', '#confirm-container').focus();

+    }, 0);

+}

+function showSettingWindow(title, htmlPath, jsPath, minWidth, minHeight, callback) {

+    var option = {

+        title: title,

+        htmlPath: htmlPath,

+        jsPath: jsPath,

+        minHeight: minHeight,

+        minWidth: minWidth

+    };

+    var callbackIsFunction = $.isFunction(callback);

+    var callbackIsPojo = $.isPlainObject(callback);

+    popupSettingWindow(option);

+}

+function popupSettingWindow(option) {

+    $.modal.close();

+    var minHeight = option.minHeight || 140;

+    var minWidth = option.minWidth || 400;

+    var subContainer = $("#htmlContainer");

+    var tmplPath = 'text!tmpl/' + option.htmlPath + '.html';

+    require([tmplPath, option.jsPath], function (tmpl, viewModel) {

+        subContainer.stop(true, true);

+        subContainer.hide();

+        subContainer.html(tmpl);

+        viewModel.init();

+        $('#htmlContainer').translate();

+        subContainer.show();

+        $('#htmlContainer').css("opacity", 50);

+    });

+    $('#popupSettingWindow').modal({

+        zIndex: 3000,

+        position: ["30%"],

+        escClose: false,

+        minWidth: minWidth,

+        minHeight: minHeight,

+        maxWidth: 400,

+        opacity: 50

+    });

+}

+function hidePopupSettingWindow() {

+    $("#popupSettingWindow").remove();

+    $.modal.close();

+}

+function showInfo(msgObj, minHeight) {

+    var option = {

+        title: 'info',

+        img: 'pic/res_info.png',

+        msg: msgObj,

+        minHeight: minHeight

+    };

+    popup(option);

+    $('#yesbtn, #nobtn').hide();

+    $('#okbtn').unbind('click').click(function () {

+        $.modal.close();

+    }).show();

+}

+function showPrompt(msgObj, callback, minHeight, defaultValue, checkPromptInput, NobtnCallback) {

+    var option = {

+        title: 'prompt',

+        img: 'pic/res_confirm.png',

+        msg: msgObj,

+        minHeight: minHeight,

+        showInput: true,

+        defaultValue: defaultValue

+    };

+    popup(option);

+    $('#yesbtn, #nobtn').unbind('click').show();

+    $('#okbtn').hide();

+    $('#yesbtn').click(function () {

+        if ($.isFunction(checkPromptInput)) {

+            if (!checkPromptInput()) {

+                return false;

+            };

+        }

+        if ($.isFunction(callback)) {

+            if (callback()) {

+                $.modal.close();

+            }

+        }

+    });

+    $('#nobtn').click(function () {

+        if ($.isFunction(NobtnCallback)) {

+            NobtnCallback();

+        }

+        $.modal.close();

+    });

+    if ($.isFunction(checkPromptInput)) {

+        $("#promptInput", "#confirm").unbind('input propertychange').bind('input propertychange', function () {

+            if ($.isFunction(checkPromptInput)) {

+                checkPromptInput();

+            }

+        });

+    }

+    $("#promptInput", "#confirm").unbind('keypress').bind('keypress', function (event) {

+        if (event.keyCode == 13) {

+            $('#yesbtn').trigger("click");

+        }

+    });

+}

+function showConfirm(msgObj, callback, minHeight, yesTrans, noTrans) {

+    if (yesTrans) {

+        $('#yesbtn').attr("data-trans", yesTrans);

+    } else {

+        $('#yesbtn').attr("data-trans", "yes");

+    }

+    if (noTrans) {

+        $('#nobtn').attr("data-trans", noTrans);

+    } else {

+        $('#nobtn').attr("data-trans", "no");

+    }

+    $('#yesbtn, #nobtn').translate();

+    var option = {

+        title: 'confirm',

+        img: 'pic/res_confirm.png',

+        msg: msgObj,

+        minHeight: minHeight

+    };

+    popup(option);

+    $('#yesbtn, #nobtn').show();

+    $('#okbtn').hide();

+    var callbackIsFunction = $.isFunction(callback);

+    var callbackIsPojo = $.isPlainObject(callback);

+    $('#yesbtn').unbind('click').click(function () {

+        $.modal.close();

+        if (callbackIsFunction) {

+            callback();

+        } else if (callbackIsPojo && $.isFunction(callback.ok)) {

+            callback.ok();

+        }

+    });

+    $('#nobtn').unbind('click').click(function () {

+        $.modal.close();

+        if (callbackIsPojo && $.isFunction(callback.no)) {

+            callback.no();

+        }

+    });

+}

+function showAlert(msgObj, callback, minHeight) {

+    var option = {

+        title: 'alert',

+        img: 'pic/res_alert.png',

+        msg: msgObj,

+        minHeight: minHeight

+    };

+    popup(option);

+    $('#yesbtn, #nobtn').hide();

+    $('#okbtn').unbind('click').click(function () {

+        $.modal.close();

+        if ($.isFunction(callback)) {

+            callback();

+        }

+    }).show();

+}

+function loadingMsgChange(msg) {

+    $('#loadMsg').html($.i18n.prop(msg));

+}

+function hideLoading() {

+    $('#confirm-overlay').css("cursor", "default");

+    $.modal.close();

+    $('#loadMsg').html('');

+}

+function getRandomInt(n) {

+    return Math.round(Math.random() * n);

+}

+function getCurrentDatetime() {

+    var d = new Date();

+    return d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + " " + d.getHours() + ":" + d.getMinutes()

+     + ":" + d.getSeconds();

+}

+function getRandomDatetime() {

+    var d = new Date();

+    return d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + " " + getRandomInt(24) + ":" + getRandomInt(60)

+     + ":" + getRandomInt(60);

+}

+function getRandomDatetimeSep() {

+    var d = new Date();

+    return d.getFullYear() + "," + (d.getMonth() + 1) + "," + d.getDate() + "," + getRandomInt(24) + "," + getRandomInt(60)

+     + "," + getRandomInt(60);

+}

+function getCurrentTimeString(theTime) {

+    var time = "";

+    var d = theTime ? theTime : new Date();

+    time += (d.getFullYear() + "").substring(2) + ";";

+    time += getTwoDigit((d.getMonth() + 1)) + ";" + getTwoDigit(d.getDate()) + ";" + getTwoDigit(d.getHours()) + ";"

+    +getTwoDigit(d.getMinutes()) + ";" + getTwoDigit(d.getSeconds()) + ";";

+    if (d.getTimezoneOffset() < 0) {

+        time += "+" + (0 - d.getTimezoneOffset() / 60);

+    } else {

+        time += (0 - d.getTimezoneOffset() / 60);

+    }

+    return time;

+}

+function getTwoDigit(num) {

+    num += "";

+    while (num.length < 2) {

+        num = "0" + num;

+    }

+    return num;

+}

+function showLoading(msg, content, contentAlert) {

+    if (msg) {

+        $('#loadMsg').html($.i18n.prop(msg));

+    } else {

+        $('#loadMsg').html('');

+    }

+    $('#loading').modal({

+        zIndex: 3000,

+        position: ['30%'],

+        overlayId: 'confirm-overlay',

+        containerId: 'confirm-container',

+        minHeight: 140,

+        persist: true,

+        focus: false,

+        escClose: false

+    });

+    var loading = $("#loading #loading_container");

+    var a = "<a href='javascript:void(0)'>&nbsp;</a>";

+    if (content) {

+        loading.html(content + a);

+    } else {

+        loading.html(a);

+    }

+    if (contentAlert) {

+        $('#loading #loading_wording').html($.i18n.prop(contentAlert));

+    } else {

+        $("#loading #loading_wording").html("");

+    }

+    $("a:last", loading).focus().hide();

+}

+function hideProgressBar() {

+    $.modal.close();

+    setProgressBar(0);

+    $('#barMsg').html('');

+}

+function setProgressBar(percents) {

+    jQuery("#bar").width(400 * percents / 100);

+    jQuery("#barValue").text(percents + "%");

+}

+

+function showProgressBar(msg, content) {

+    if (msg) {

+        $('#barMsg').html($.i18n.prop(msg));

+    }

+    $('#progress').modal({

+        zIndex: 3000,

+        position: ['30%'],

+        overlayId: 'confirm-overlay',

+        containerId: 'confirm-container',

+        minHeight: 140,

+        persist: true,

+        focus: false,

+        escClose: false

+    });

+    if (content) {

+        $("#progress #progress_container").html(content);

+    } else {

+        $("#progress #progress_container").html("");

+    }

+}

+

+function showInfoMsg(msg, nameText, tmp) {

+    $.modal.close();

+    if (msg) {

+        $('#result-image', '#result-overlay').removeClass().addClass(nameText);

+        $('#result_wording').html('<h2>' + $.i18n.prop(msg) + '</h2>');

+    }

+    $('#result-overlay').modal({

+        zIndex: 3000,

+        position: ['30%'],

+        overlayId: 'confirm-overlay',

+        containerId: 'confirm-container',

+        minHeight: 140,

+        persist: true,

+        focus: false,

+        escClose: false

+    });

+    var count = 3;

+    var overlayTimer = setInterval(function () {

+        count--;

+        if (count == 0) {

+            clearInterval(overlayTimer);

+            if ($('#result-overlay:visible').length > 0) {

+                $.modal.close();

+            }

+        }

+    }, 1000);

+}

+function errorOverlay(msg, isContinueLoading) {

+    showInfoMsg(msg ? msg : 'error_info', 'overlay-error', !isContinueLoading);

+}

+function successOverlay(msg, isContinueLoading) {

+    showInfoMsg(msg ? msg : 'success_info', 'overlay-success', !isContinueLoading);

+}

+function transOption(transid, isChannel) {

+    if (isChannel) {

+        return function (item) {

+            if (item.value != 0) {

+                var val = item.value.split("_");

+                return val[1] + "MHz " + $.i18n.prop(transid + '_' + val[0]);

+            } else {

+                return $.i18n.prop(transid + '_0');

+            }

+        };

+    }

+    return function (item) {

+        return $.i18n.prop(transid + '_' + item.value);

+    };

+}

+function getFileType(fileName) {

+    var ext = fileName.split('.').pop().toLowerCase();

+    for (type in extMap) {

+        if ($.inArray(ext, extMap[type]) != -1) {

+            return type;

+        }

+    }

+    return "file";

+}

+var extMap = {

+    mp3: ["mp3", "wma", "wav"],

+    film: ["mp4", "avi", "rm", "rmvb", "3gp", "mpeg"],

+    picture: ["jpeg", "jpg", "gif", "bmp", "png"],

+    pdf: ['pdf'],

+    rar: ['rar', '7z', 'zip', 'gzip', 'gz', 'tar'],

+    doc: ['doc', 'docx'],

+    ppt: ['ppt', 'pptx'],

+    xls: ['xls', 'xlsx'],

+    xml: ['xml']

+};

+function checkRange(str, min, max) {

+    var intVal = parseInt(str, 10);

+    return !(intVal > max || intVal < min);

+}

+function transProtocolValue(proto) {

+    switch (proto) {

+    case "TCP":

+    case "UDP":

+    case "ICMP":

+        return proto;

+    case "TCP&UDP":

+        return "TCP+UDP";

+    case "None":

+    default:

+        return "ALL";

+    }

+}

+function transProtocol(proto) {

+    var type = "ALL";

+    if ("1" == proto)

+        type = "TCP";

+    else if ("2" == proto)

+        type = "UDP";

+    else if ("3" == proto)

+        type = "TCP+UDP";

+    else if ("4" == proto)

+        type = "ICMP";

+    else if ("5" == proto)

+        type = "ALL";

+    return type;

+}

+function updateLength(sms_content) {

+    var length = 0;

+    var tmpchr;

+    var index = 0;

+    for (var i = 0; i < sms_content.length; i++) {

+        tmpchr = sms_content.charAt(i);

+        length = length + 1;

+        if ((tmpchr == "[") || (tmpchr == "]") || (tmpchr == "{") || (tmpchr == "}") || (tmpchr == "|") || (tmpchr == "\\") || (tmpchr == "^") || (tmpchr == "~") || (tmpchr == "€")) {

+            length = length + 1;

+        }

+        index = i;

+        if (length == 765) {

+            break;

+        }

+        if (length > 765) {

+            index = i - 1;

+            length = length - 2;

+            break;

+        }

+    }

+    return {

+        index: index,

+        length: length

+    };

+}

+function clearValidateMsg(areaId) {

+    areaId = areaId || '*';

+    $(areaId + ' label.error').remove();

+}

+function isErrorObject(object) {

+    return typeof object.errorType === 'string';

+}

+var manualLogout = false;

diff --git a/ap/app/zte_webui/js/main.js b/ap/app/zte_webui/js/main.js
new file mode 100755
index 0000000..a771f7d
--- /dev/null
+++ b/ap/app/zte_webui/js/main.js
@@ -0,0 +1,121 @@
+require.config({

+    shim: {

+        knockoutbase: ['jq_tmpl'],

+        jq_additional: ['jq_validate'],

+        jq_simplemodal: ['3rd/twbs.bootstrap'],

+        jq_translate: ['jq_i18n'],

+    },

+    paths: {

+        base64: '3rd/webtoolkit.base64',

+        echarts: '3rd/apache.echarts',

+        knockout: '3rd/knockout',

+        knockoutbase: '3rd/knockout.base',

+        jq_additional: '3rd/jquery.additional-methods',

+        jq_chosen: '3rd/jquery.chosen',

+        jq_fileinput: '3rd/jquery.fileinput',

+        jq_i18n: '3rd/jquery.i18n',

+        jq_simplemodal: '3rd/jquery.simplemodal',

+        jq_tmpl: '3rd/jquery.tmpl',

+        jq_translate: '3rd/jquery.translate',

+        jq_validate: '3rd/jquery.validate',

+        jquery: '3rd/require-jquery',

+        jqui: '3rd/jqui',

+        text: '3rd/require-text',

+        tmpl: '../subpg',

+        underscore: '3rd/underscore',

+        service: 'com',

+        

+        CryptoJS: '3rd/crypto-js',

+

+        menu: 'com',

+        adm_lan: 'com',

+        adm_others: 'com',

+        adm_management: 'com',

+        adm_pin: 'com',

+        adm_quick_set: 'com',

+        main: 'com',

+        language: 'com',

+        entry: 'com',

+        logout: 'com',

+        opmode: 'com',

+        opmode_popup: 'com',

+        router: 'com',

+        statusBar: 'com',

+        status_traffic_alert: 'com',

+        tooltip: 'com',

+

+        phonebook: 'sim_device',

+        sim_abnormal: 'sim_device',

+        ota_update: 'sim_device',

+        sd: 'sim_device',

+        sd_httpshare: 'sim_device',

+        sms_set: 'sim_device',

+        sms_sim_messages: 'sim_device',

+        sms_list: 'sim_device',

+        ussd: 'sim_device',

+        network_apn_set: 'net',

+        network_dial_set: 'net',

+        network_dial_set_cpe: 'net',

+        locknet: 'net',

+        network_net_select: 'net',

+        ddns: 'net',

+        firewall: 'net',

+        firewall_dmz_set: 'net',

+        firewall_parental_control: 'net',

+        firewall_port_filter: 'net',

+        firewall_port_forward: 'net',

+        firewall_port_map: 'net',

+        firewall_upnp_set: 'net',

+        firewall_url_filter: 'net',

+        wifi_advance: 'wifi',

+        wifi_ap_station: 'wifi',

+        wifi_guest: 'wifi',

+        wifi_mac_filter: 'wifi',

+        wifi_main: 'wifi',

+        wifi_sleep_mode: 'wifi',

+        wifi_station_info: 'wifi',

+        wifi_wps: 'wifi',

+    },

+

+});

+

+require("set service lib".split(" "),

+    function (set, fnc, util) {

+    function initAndLoad(cfg) {

+        require([cfg.menu, cfg.set], function (params) {

+            require("menu language logout statusBar router entry jq_additional jq_translate jq_simplemodal base64".split(" "),

+                function (menu, language, logout, statusBar, router, entry) {

+                menu.init();

+                language.init();

+                router.init();

+                logout.init();

+                statusBar.init();

+            });

+        });

+    }

+    if (!set.RJ45_SUPPORT) {

+        initAndLoad({

+            set: set.DEVICE + '/set',

+            menu: set.DEVICE + '/menu'

+        });

+    } else {

+        var tmp = "menu";

+        fnc.getOpMode({}, function (mod) {

+            set.blc_wan_mode = mod.blc_wan_mode;

+            switch (mod.blc_wan_mode) {

+            case "AUTO_PPPOE":

+            case "PPPOE":

+                tmp = "menu_pppoe";

+                break;

+            default:

+                tmp = "menu";

+                break;

+            }

+            initAndLoad({

+                set: set.DEVICE + '/set',

+                menu: set.DEVICE + '/' + tmp

+            });

+        });

+    }

+

+});

diff --git a/ap/app/zte_webui/js/net.js b/ap/app/zte_webui/js/net.js
new file mode 100755
index 0000000..22b3ff8
--- /dev/null
+++ b/ap/app/zte_webui/js/net.js
@@ -0,0 +1,4228 @@
+

+define("firewall_url_filter","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    //system url filter setting VM

+     

+    function UrlFilterSettingVM() {

+        var target = this;

+        var urlFltInfo = service.getUrlFilterList();

+        var columnsTmpl = [{

+                columnType: "checkbox",

+                rowText: "index",

+                width: "30%"

+            }, {

+                headerTextTrans: "url",

+                rowText: "url",

+                width: "70%"

+            }

+        ];

+        target.rules = ko.observableArray(urlFltInfo.urlFilterRules);

+

+        target.gridTemplate = new ko.simpleGrid.viewModel({

+            data: target.rules(),

+            idName: "index",

+            columns: columnsTmpl,

+            tmplType: 'list',

+            pageSize: 10

+        });

+

+        target.clear = clearFunc;

+		

+        target.callback = callbackFunc;

+		//删除规则

+         

+        target.deleteRule = deleteRuleFunc;

+		

+        //添加规则

+         

+        target.addRule = addRuleFunc;

+		function callbackFunc(elem) {

+            if (elem.result != "success") {

+                errorOverlay();                

+            } else {

+				target.clear();

+                initialize(target);

+                successOverlay();

+                $("#urlFilters").translate();

+            }

+		}

+		

+		//添加规则

+		function addRuleFunc() {

+            if (target.rules().length >= config.urlFilterMax) {

+                showAlert({

+                    msg: "url_filter_max",

+                    params: config.urlFilterMax

+                });

+                return false;

+            }

+            var tmpArr = [];

+            for (var idx = 0; idx < target.rules().length; idx++) {

+                tmpArr.push(target.rules()[idx].url);

+            }

+            if ($.inArray($("#addURLFilter").val(), tmpArr) != -1) {

+                showAlert("url_repeated");

+                return false;

+            }

+

+            showLoading();

+            var urlFltParams = {

+                goformId: "URL_FILTER_ADD",

+                addURLFilter: $("#addURLFilter").val()

+            };

+            service.addUrlFilterRule(urlFltParams, target.callback);

+        }

+		//删除规则

+		function deleteRuleFunc() {

+            showConfirm('confirm_data_delete', function () {

+                showLoading();

+                var urlFltParams = {

+                    goformId: "URL_FILTER_DELETE",

+                    url_filter_delete_id: target.gridTemplate.selectedIds().join(";") + ";"

+                };

+                service.deleteSelectedRules(urlFltParams, target.callback);

+            });

+        }

+		

+    }

+	

+		function clearFunc() {

+            $("#addURLFilter").val("");

+        }

+		

+    //页面初始化

+     

+    function initialize() {

+       

+        var vm = new UrlFilterSettingVM();

+		bindContainer(vm);

+    }

+	function bindContainer(vm){

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+		ko.applyBindings(vm, container[0]);

+        $('#urlFilterForm').validate({

+            submitHandler: function () {

+                vm.addRule();

+            },

+            rules: {

+                addURLFilter: 'url_filter_check'

+            }

+        });

+

+        $("#urlFilterListForm").validate({

+            submitHandler: function () {

+                vm.deleteRule();

+            }

+        });

+	}

+

+    return {

+        init: initialize

+    };

+});

+

+define("firewall_upnp_set","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    //system upnp setting VM

+     

+    function UpnpSettingVM() {

+        var target = this;

+        var upnpInfo = getUpnpSetting();

+

+        target.upnpSetting = ko.observable(upnpInfo.upnpSetting);

+

+        target.save = saveFunc;

+		function saveFunc() {

+            showLoading();

+            var upnpParams = {};

+            upnpParams.upnpSetting = target.upnpSetting();

+            service.setUpnpSetting(upnpParams, function (rlt) {

+                if (rlt.result == "success") {

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+

+        }

+    }

+	

+		

+    //获取upnp 信息

+     

+    function getUpnpSetting() {

+        return service.getUpnpSetting();

+    }

+

+    //初始化UpnpSettingVM model

+     

+    function initialize() {

+        

+        var vm = new UpnpSettingVM();

+		bindContainer(vm);

+        

+    }

+	function bindContainer(vm) {

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+		ko.applyBindings(vm, container[0]);

+        $('#upnpSettingForm').validate({

+            submitHandler: function () {

+                vm.save();

+            }

+        });

+	}

+

+    return {

+        init: initialize

+    };

+});

+

+define("firewall_upnp_set","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    //system upnp setting VM

+     

+    function UpnpSettingVM() {

+        var target = this;

+        var upnpInfo = getUpnpSetting();

+

+        target.upnpSetting = ko.observable(upnpInfo.upnpSetting);

+

+        target.save = saveFunc;

+		function saveFunc() {

+            showLoading();

+            var upnpParams = {};

+            upnpParams.upnpSetting = target.upnpSetting();

+            service.setUpnpSetting(upnpParams, function (rlt) {

+                if (rlt.result == "success") {

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+

+        }

+    }

+	

+		

+    //获取upnp 信息

+     

+    function getUpnpSetting() {

+        return service.getUpnpSetting();

+    }

+

+    //初始化UpnpSettingVM model

+     

+    function initialize() {

+        

+        var vm = new UpnpSettingVM();

+		bindContainer(vm);

+        

+    }

+	function bindContainer(vm) {

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+		ko.applyBindings(vm, container[0]);

+        $('#upnpSettingForm').validate({

+            submitHandler: function () {

+                vm.save();

+            }

+        });

+	}

+

+    return {

+        init: initialize

+    };

+});

+

+//端口映射

+ 

+define("firewall_port_map","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var protocolModes = _.map(config.MAP_PROTOCOL_MODES, function (ele) {

+        return new Option(ele.name, ele.value);

+    });

+

+    var columnsTmpl = [{

+            columnType: "checkbox",

+            rowText: "index",

+            width: "8%"

+        }, {

+            headerTextTrans: "source_port",

+            rowText: "sourcePort",

+            width: "20%"

+        }, {

+            headerTextTrans: "dest_ip_address",

+            rowText: "destIpAddress",

+            width: "20%"

+        }, {

+            headerTextTrans: "dest_port",

+            rowText: "destPort",

+            width: "20%"

+        }, {

+            headerTextTrans: "protocol",

+            rowText: "protocol",

+            width: "12%"

+        }, {

+            headerTextTrans: "comment",

+            rowText: "comment",

+            width: "20%"

+        }

+    ];

+

+    //prot_map VM

+     

+    function PortMapVM() {

+        var target = this;

+        var mapInfo = getPortMap();

+

+        target.oriPortMapEnable = ko.observable(mapInfo.portMapEnable);

+        target.rules = ko.observableArray(mapInfo.portMapRules);

+        target.portMapEnable = ko.observable(mapInfo.portMapEnable);

+

+		

+        target.comment = ko.observable('');

+        target.selectedMode = ko.observable('TCP&UDP');

+        target.modes = ko.observableArray(protocolModes);

+		

+        target.destPort = ko.observable('');

+        target.destIpAddress = ko.observable('');

+        target.sourcePort = ko.observable('');

+

+

+

+        target.gridTemplate = new ko.simpleGrid.viewModel({

+            data: target.rules(),

+            idName: "index",

+            columns: columnsTmpl,

+            tmplType: 'list',

+            pageSize: 10

+        });

+

+        //设定,新增,删除回调函数

+         

+        target.callback = callbackFunc;

+		

+		//删除规则

+         

+        target.deleteMapRules = deleteMapRulesFunc;

+		

+		//检查新增规则是否已经存在

+         

+        target.checkExist = checkExistFunc;

+		

+        //设定端口映射

+         

+        target.enablePortMap = enablePortMapFunc;

+

+        //保存规则

+         

+        target.save = saveFunc;

+		        

+		//保存规则

+		function saveFunc() {

+            if (target.rules().length >= config.portForwardMax) {

+                showAlert({

+                    msg: "rules_max",

+                    params: config.portForwardMax

+                });

+                return;

+            }

+

+            if (target.checkExist()) {

+                showAlert("rule_exist");

+                return;

+            }

+

+            showLoading();

+            var mapParams = {};

+            mapParams.portMapEnable = target.portMapEnable();

+            mapParams.sourcePort = target.sourcePort();

+            mapParams.destIpAddress = target.destIpAddress();

+            mapParams.destPort = target.destPort();

+            mapParams.protocol = target.selectedMode();

+            mapParams.comment = target.comment();

+            service.setPortMap(mapParams, target.callback);

+        }

+		

+		//检查新增规则是否已经存在

+		function checkExistFunc() {

+            var newMapRule = {

+                sourcePort: target.sourcePort(),

+                destIpAddress: target.destIpAddress(),

+                destPort: target.destPort(),

+                protocol: transProtocolValue(target.selectedMode())

+            };

+

+            var oldMapRule;

+            var mapRules = target.rules();

+            for (var idx = 0; idx < mapRules.length; idx++) {

+                oldMapRule = {

+                    sourcePort: mapRules[idx].sourcePort,

+                    destIpAddress: mapRules[idx].destIpAddress,

+                    destPort: mapRules[idx].destPort,

+                    protocol: mapRules[idx].protocol

+                };

+

+                if (_.isEqual(newMapRule, oldMapRule)) {

+                    return true;

+                }

+            }

+            return false;

+        }

+		

+		//设定端口映射

+		function enablePortMapFunc() {

+            showLoading();

+            var mapParams = {};

+            mapParams.portMapEnable = target.portMapEnable();

+            service.enablePortMap(mapParams, target.callback);

+        }

+		

+		//删除规则

+		function deleteMapRulesFunc() {

+            var ids = target.gridTemplate.selectedIds();

+            if (ids.length == 0) {

+                showAlert("no_data_selected");

+                return;

+            }

+

+            showConfirm("confirm_data_delete", function () {

+                showLoading();

+                var mapParams = {};

+                mapParams.indexs = ids;

+                service.deleteMapRules(mapParams, target.callback);

+            });

+        }

+		

+		//设定,新增,删除回调函数

+		function callbackFunc(ret) {

+            if (ret.result == "success") {

+                clear();

+                initialize(target);

+                successOverlay();

+            } else {

+                errorOverlay();

+            }

+        }

+

+        //情况添加规则输入

+         

+        function clear() {

+            target.sourcePort('');

+            target.destIpAddress('');

+            target.destPort('');

+            target.selectedMode('TCP&UDP');

+            target.comment('');

+        }

+    }

+

+    //获取port map信息

+     

+    function getPortMap() {

+        return service.getPortMap();

+    }

+

+	function bindingContainer(vm){

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(vm, container[0]);

+

+	}

+    //初始化port map view model

+     

+    function initialize(viewModel) {

+        var vm;

+        if (viewModel) {

+            vm = viewModel;

+            var mapInfo = getPortMap();

+            vm.portMapEnable(mapInfo.portMapEnable);

+            vm.oriPortMapEnable(mapInfo.portMapEnable);

+            vm.rules(mapInfo.portMapRules);

+            vm.gridTemplate.clearAllChecked();

+            vm.gridTemplate.data(mapInfo.portMapRules);

+            refreshTableHeight();

+            renderCheckbox();

+            return;

+        }

+

+        vm = new PortMapVM();

+        bindingContainer(vm);

+        fixTableHeight();

+

+        $('#mapBasicForm').validate({

+            submitHandler: function () {

+                vm.enablePortMap();

+            }

+        });

+

+        $('#portMapListForm').validate({

+            submitHandler: function () {

+                vm.deleteMapRules();

+            }

+        });

+

+        $('#portMapForm').validate({

+            submitHandler: function () {

+                vm.save();

+            },

+            rules: {

+                txtDestIpAddress: {

+                    ip_check: true

+                },

+                txtSourcePort: {

+                    digits: true,

+                    range_except: [1, 65000]

+                },

+                txtDestPort: {

+                    digits: true,

+                    range_except: [1, 65000]

+                },

+                txtComment: {

+                    comment_check: true

+                }

+            },

+            errorPlacement: function (error, element) {

+                if (element.attr("name") == "txtDestIpAddress") {

+                    error.appendTo("#txtDestIpAddressErrorDiv");

+                } else if (element.attr("name") == "txtSourcePort") {

+                    error.appendTo("#txtSourcePortErrorDiv");

+                } else if (element.attr("name") == "txtDestPort") {

+                    error.appendTo("#txtDestPortErrorDiv");

+                } else

+                    error.insertAfter(element);

+            }

+        });

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+//端口转发

+ 

+define("firewall_port_forward","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var protocolModes = _.map(config.FORWARD_PROTOCOL_MODES, function (ele) {

+        return new Option(ele.name, ele.value);

+    });

+    //列表模板的columns项

+     

+    var columnsTmpl = [{

+            columnType: "checkbox",

+            rowText: "index",

+            width: "8%"

+        }, {

+            headerTextTrans: "ip_address",

+            rowText: "ipAddress",

+            width: "23%"

+        }, {

+            headerTextTrans: "port_range",

+            rowText: "portRange",

+            width: "23%"

+        }, {

+            headerTextTrans: "protocol",

+            rowText: "protocol",

+            width: "23%"

+        }, {

+            headerTextTrans: "comment",

+            rowText: "comment",

+            width: "23%"

+        }

+    ];

+

+    //prot_forward VM

+     

+    function PortForwardVM() {

+        var target = this;

+        var fwdinfo = getPortForward();

+

+        target.portForwardEnable = ko.observable(fwdinfo.portForwardEnable);

+        target.oriPortForwardEnable = ko.observable(fwdinfo.portForwardEnable);

+		

+        target.portEnd = ko.observable('');

+        target.portStart = ko.observable('');

+        target.ipAddress = ko.observable('');

+		

+        target.comment = ko.observable('');

+        target.selectedMode = ko.observable('3');

+        target.modes = ko.observableArray(protocolModes);

+

+        target.rules = ko.observableArray(fwdinfo.portForwardRules);

+		

+		//设定,新增,删除回调函数

+         

+        target.callback = callbackFunc;

+		

+        //创建列表模板

+         

+        target.gridTemplate = new ko.simpleGrid.viewModel({

+            data: target.rules(),

+            idName: "index",

+            columns: columnsTmpl,

+            tmplType: 'list',

+            pageSize: 10

+        });

+

+        //检查新增规则是否已经存在

+         

+        target.checkExist = checkExistFunc;

+				

+		//保存规则

+         

+        target.save = saveFunc;

+		

+		//删除规则

+         

+        target.deleteForwardRules = deleteForwardRulesFunc;

+		

+        //设定虚拟服务器

+         

+        target.enableVirtualServer = enableVirtualServerFunc;

+		

+		//设定虚拟服务器

+		function enableVirtualServerFunc() {

+            showLoading();

+            var fwdParams = {};

+            fwdParams.portForwardEnable = target.portForwardEnable();

+            service.enableVirtualServer(fwdParams, target.callback);

+        }

+		

+		//删除规则

+		function deleteForwardRulesFunc() {

+            var ids = target.gridTemplate.selectedIds();

+            if (ids.length == 0) {

+                showAlert("no_data_selected");

+                return;

+            }

+

+            showConfirm("confirm_data_delete", function () {

+                showLoading('deleting');

+                var fwdParams = {};

+                fwdParams.indexs = ids;

+                service.deleteForwardRules(fwdParams, target.callback);

+            });

+        }

+		

+		//保存规则

+		function saveFunc() {

+            if (target.rules().length >= config.portForwardMax) {

+                showAlert({

+                    msg: "rules_max",

+                    params: config.portForwardMax

+                });

+                return;

+            }

+

+            if (target.checkExist()) {

+                showAlert("rule_exist");

+                return;

+            }

+

+            showLoading();

+            var fwdParams = {};

+            fwdParams.comment = target.comment();

+            fwdParams.protocol = target.selectedMode();

+            fwdParams.portEnd = target.portEnd();

+            fwdParams.portStart = target.portStart();

+            fwdParams.ipAddress = target.ipAddress();

+            service.setPortForward(fwdParams, target.callback);

+        }

+         //情况添加规则输入

+        function clear() {

+            target.ipAddress('');

+            target.portStart('');

+            target.portEnd('');

+            target.selectedMode('TCP&UDP');

+            target.comment('');

+        }

+		

+		//设定,新增,删除回调函数

+		function callbackFunc(ret) {

+            if (ret.result == "success") {

+                clear();

+                initialize(target);

+                successOverlay();

+            } else {

+                errorOverlay();

+            }

+        }

+

+		//检查新增规则是否已经存在

+		function checkExistFunc() {

+            var newRule = {

+                ipAddress: target.ipAddress(),

+                portRange: target.portStart() + ' - ' + target.portEnd(),

+                protocol: transProtocolValue(target.selectedMode())

+            };

+

+            var oldRule;

+            var fwdrules = target.rules();

+            for (var ki = 0; ki < fwdrules.length; ki++) {

+                oldRule = {

+                    ipAddress: fwdrules[ki].ipAddress,

+                    portRange: fwdrules[ki].portRange,

+                    protocol: fwdrules[ki].protocol

+                };

+

+                if (_.isEqual(newRule, oldRule)) {

+                    return true;

+                }

+            }

+            return false;

+        }

+    }

+

+    //获取port forward信息

+     

+    function getPortForward() {

+        return service.getPortForward();

+    }

+

+    //初始化port forward view model

+     

+    function initialize(viewModel) {

+        var vm;

+        if (viewModel) {

+            vm = viewModel;

+            var fwdinfo = getPortForward();

+            vm.gridTemplate.clearAllChecked();

+            vm.gridTemplate.data(fwdinfo.portForwardRules);

+            vm.rules(fwdinfo.portForwardRules);

+            vm.portForwardEnable(fwdinfo.portForwardEnable);

+            vm.oriPortForwardEnable(fwdinfo.portForwardEnable);

+            refreshTableHeight();

+            return;

+        }

+

+        vm = new PortForwardVM();

+        bindContainer(vm);

+		

+        fixTableHeight();

+        renderCheckbox();

+

+        $('#virtualServerForm').validate({

+            submitHandler: function () {

+                vm.enableVirtualServer();

+            }

+        });

+

+        $('#portForwardListForm').validate({

+            submitHandler: function () {

+                vm.deleteForwardRules();

+            }

+        });

+

+        $('#portForwardForm').validate({

+            submitHandler: function () {

+                vm.save();

+            },

+            rules: {

+                txtIpAddress: {

+                    ip_check: true

+                },

+                txtPortStart: {

+                    digits: true,

+                    range: [1, 65535],

+                    portCompare: "#txtPortEnd"

+                },

+                txtPortEnd: {

+                    digits: true,

+                    range: [1, 65535],

+                    portCompare: "#txtPortStart"

+                },

+                txtComment: {

+                    comment_check: true

+                }

+            },

+            groups: {

+                range: "txtPortStart txtPortEnd"

+            },

+            errorPlacement: function (error, element) {

+                if (element.attr("name") == "txtIpAddress") {

+                    error.appendTo("#ipErrorDiv");

+                } else if (element.attr("name") == "txtPortStart" || element.attr("name") == "txtPortEnd") {

+                    error.appendTo("#portRangeErrorDiv");

+                } else

+                    error.insertAfter(element);

+            }

+        });

+    }

+	

+	function bindContainer(vm){

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(vm, container[0]);

+

+	}

+	

+

+    return {

+        init: initialize

+    };

+});

+

+define("firewall_port_filter","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var PROTOCOLS = {

+        ICMP: 'ICMP',

+        NONE: 'None'

+    };

+

+    var columnsTmpl = [{

+            columnType: "checkbox",

+            rowText: "index",

+            width: "4%"

+        }, {

+            headerTextTrans: "mac_address",

+            rowText: "macAddress",

+            width: "12%"

+        }, {

+            headerTextTrans: "ip_type",

+            rowText: "ipType",

+            width: "5%",

+            display: config.IPV6_SUPPORT

+        }, {

+            headerTextTrans: "source_ip_address",

+            rowText: "sourceIpAddress",

+            width: "12%"

+        }, {

+            headerTextTrans: "dest_ip_address",

+            rowText: "destIpAddress",

+            width: "12%"

+        }, {

+            headerTextTrans: "protocol",

+            rowText: "protocol",

+            width: "12%",

+            needTrans: true

+        }, {

+            headerTextTrans: "source_port_range",

+            rowText: "sourcePortRange",

+            width: "12%"

+        }, {

+            headerTextTrans: "dest_port_range",

+            rowText: "destPortRange",

+            width: "12%"

+        }, {

+            headerTextTrans: "port_filter_action",

+            rowText: "action",

+            width: "12%",

+            needTrans: true

+        }, {

+            headerTextTrans: "comment",

+            rowText: "comment",

+            width: "12%"

+        }

+    ];

+

+    var protocolModes = _.map(config.FILTER_PROTOCOL_MODES, function (elem) {

+        return new Option(elem.name, elem.value);

+    });

+    //prot_filter VM

+     

+    function PortFilterVM() {

+        var target = this;

+        var info = getPortFilter();

+		

+        target.oriDefaultPolicy = ko.observable(info.defaultPolicy);

+        target.defaultPolicy = ko.observable(info.defaultPolicy);

+        target.oriPortFilterEnable = ko.observable(info.portFilterEnable);

+        target.portFilterEnable = ko.observable(info.portFilterEnable);

+        target.rules = ko.observableArray(info.portFilterRules);

+		

+        target.ipv6Support = ko.observable(config.IPV6_SUPPORT);

+        target.comment = ko.observable('');

+        target.selectedMode = ko.observable('5');

+        target.modes = ko.observableArray(protocolModes);

+        target.sourcePortEnd = ko.observable('');

+        target.sourcePortStart = ko.observable('');

+        target.destPortEnd = ko.observable('');

+        target.destPortStart = ko.observable('');

+        target.destIpv6Address = ko.observable('');

+        target.sourceIpv6Address = ko.observable('');

+        target.sourceIpAddress = ko.observable('');

+        target.destIpAddress = ko.observable('');

+        target.macAddress = ko.observable('');

+        target.portFilterAction = ko.observable('');

+

+        target.ipType = ko.observable('ipv4');

+

+        //设定,新增,删除回调函数

+         

+        target.callback = callbackFunc;

+		

+        //创建列表模板

+         

+        target.gridTemplate = new ko.simpleGrid.viewModel({

+            data: target.rules(),

+            idName: "index",

+            columns: columnsTmpl,

+            tmplType: 'list',

+            pageSize: 20

+        });

+        //default policy change handler

+         

+        target.policyChangeHandler = policyChangeHandlerFunc;

+

+        //保存规则

+         

+        target.save = saveFunc;

+	

+        //设定过滤基本信息

+         

+        target.setPortFilterBasic = setPortFilterBasicFunc;

+		

+		//清空添加规则输入

+         

+        target.clear = clearFunc;

+

+        //检查新增规则是否已经存在

+         

+        target.checkExist = checkExistFunc;

+

+		//ip类型变化事件监听

+         

+        target.ipTypeChangeHandler = ipTypeChangeHandlerFunc;

+		

+        //协议变化事件监听

+         

+        target.protocolChangeHandler = protocolChangeHandlerFunc;

+

+        //删除规则

+         

+        target.deleteFilterRules = deleteFilterRulesFunc;

+

+        //init to call

+        target.policyChangeHandler();

+		

+		//设定,新增,删除回调函数

+		function callbackFunc(ret) {

+            if (ret.result != "success") {

+                errorOverlay();

+            } else {

+                target.clear();

+                initialize(target);

+                successOverlay();

+            }

+        }

+		//default policy change handler

+		function policyChangeHandlerFunc() {

+            var action = target.defaultPolicy() != "1" ? "Drop" : "Accept";

+            target.portFilterAction(action);

+            return true;

+        }

+		

+		//保存规则

+		function saveFunc() {

+            target.sourceIpAddress(target.sourceIpAddress().replace(/\s+/g, ''));

+            target.destIpAddress(target.destIpAddress().replace(/\s+/g, ''));

+            target.sourceIpv6Address(target.sourceIpv6Address().replace(/\s+/g, ''));

+            target.destIpv6Address(target.destIpv6Address().replace(/\s+/g, ''));

+            target.macAddress(target.macAddress().replace(/\s+/g, ''));

+            if (target.ipv6Support() == false) {

+                if (target.rules().length >= config.portForwardMax) {

+                    showAlert({

+                        msg: "rules_max",

+                        params: config.portForwardMax

+                    });

+                    return;

+                }

+

+                if (target.checkExist()) {

+                    showAlert("rule_exist");

+                    return;

+                }

+

+            } else {

+				var type = target.ipType() == "ipv4" ? "IPv4" : "IPv6";

+                var oldRules = _.filter(target.rules(), function (item) {

+                    return item.ipType == type;

+                });

+

+                if (oldRules.length >= config.portForwardMax) {

+                    showAlert({

+                        msg: "rules_max_v4v6",

+                        params: [type, config.portForwardMax]

+                    });

+                    return;

+                }

+

+                if (target.checkExist()) {

+                    showAlert({

+                        msg: "rule_exist_v4v6",

+                        params: type

+                    });

+                    return;

+                }

+            }

+            showConfirm("confirm_data_effect", function () {

+                showLoading();

+                var fltParams = {};

+                fltParams.macAddress = target.macAddress();

+

+                if (target.ipv6Support() && target.ipType() != 'ipv6') {

+                    fltParams.destIpAddress = target.destIpAddress();

+                    fltParams.sourceIpAddress = target.sourceIpAddress();

+                } else {

+                    fltParams.destIpAddress = target.destIpv6Address();

+                    fltParams.sourceIpAddress = target.sourceIpv6Address();

+                }

+				

+                fltParams.ipType = target.ipType();

+                fltParams.comment = target.comment();

+                fltParams.protocol = target.selectedMode();

+                fltParams.action = target.portFilterAction();

+                fltParams.sourcePortEnd = target.sourcePortEnd();

+                fltParams.sourcePortStart = target.sourcePortStart();

+                fltParams.destPortEnd = target.destPortEnd();

+                fltParams.destPortStart = target.destPortStart();

+                service.setPortFilter(fltParams, target.callback);

+            });

+        }

+		

+		//设定过滤基本信息

+		function setPortFilterBasicFunc() {

+            showLoading();

+            var elems = {};

+            elems.defaultPolicy = target.defaultPolicy();

+            elems.portFilterEnable = target.portFilterEnable();

+            service.setPortFilterBasic(elems, target.callback);

+        }

+		//清空添加规则输入

+		function clearFunc() {

+            target.comment('');

+            target.selectedMode('None');

+            target.sourcePortEnd('0');

+            target.sourcePortStart('0');

+            target.destPortEnd('0');

+            target.destPortStart('0');

+            target.sourceIpv6Address('');

+            target.sourceIpAddress('');

+            target.destIpv6Address('');

+            target.destIpAddress('');

+            target.macAddress('');

+            clearValidateMsg();

+        }

+		

+		//检查新增规则是否已经存在

+		function checkExistFunc() {

+            target.macAddress(target.macAddress().toUpperCase());

+            var currIpType = target.ipType().toUpperCase();

+            var newRule = {

+                macAddress: target.macAddress(),

+                destIpAddress: currIpType == "IPV4" ? target.destIpAddress() : target.destIpv6Address(),

+                sourceIpAddress: currIpType == "IPV4" ? target.sourceIpAddress() : target.sourceIpv6Address(),

+                destPortRange: target.destPortStart() == '0' ? '' : target.destPortStart() + ' - ' + target.destPortEnd(),

+                sourcePortRange: target.sourcePortStart() == '0' ? '' : target.sourcePortStart() + ' - ' + target.sourcePortEnd(),

+                action: target.portFilterAction() == "Drop" ? "filter_drop" : "filter_accept",

+                protocol: transProtocolValue(target.selectedMode()),

+                ipType: currIpType

+            };

+

+            var oldRule;

+            var rules = target.rules();

+            for (var ki = 0; ki < rules.length; ki++) {

+                oldRule = {

+                    macAddress: rules[ki].macAddress,

+                    destIpAddress: rules[ki].destIpAddress,

+                    sourceIpAddress: rules[ki].sourceIpAddress,

+                    destPortRange: rules[ki].destPortRange,

+                    sourcePortRange: rules[ki].sourcePortRange,

+                    action: rules[ki].action,

+                    protocol: rules[ki].protocol,

+                    ipType: rules[ki].ipType.toUpperCase()

+                };

+

+                if (_.isEqual(newRule, oldRule)) {

+                    return true;

+                }

+            }

+            return false;

+        }

+		

+		//协议变化事件监听

+		function protocolChangeHandlerFunc() {

+            if (target.selectedMode() == PROTOCOLS.ICMP || target.selectedMode() == PROTOCOLS.NONE) {

+                target.sourcePortEnd('0');

+                target.sourcePortStart('0');

+                target.destPortEnd('0');

+                target.destPortStart('0');

+                clearValidateMsg('#portRangeArea');

+            } else {

+                target.sourcePortEnd('65535');

+                target.sourcePortStart('1');

+                target.destPortEnd('65535');

+                target.destPortStart('1');

+            }

+            return true;

+        }

+		

+		//删除规则

+		function deleteFilterRulesFunc() {

+            var ids = target.gridTemplate.selectedIds();

+            if (ids.length == 0) {

+                showAlert("no_data_selected");

+                return;

+            }

+

+            showConfirm("confirm_data_effect", function () {

+                showLoading('deleting');

+                var rules = {};

+                rules.indexs = ids;

+                service.deleteFilterRules(rules, target.callback);

+            });

+        }

+		

+    }

+

+    //获取port filter信息

+     

+    function getPortFilter() {

+        return service.getPortFilter();

+    }

+		

+	//ip类型变化事件监听

+	function ipTypeChangeHandlerFunc() {

+        clearValidateMsg();

+        return true;

+    }

+	

+    //初始化port filter view model

+     

+    function initialize(viewModel) {

+        var vm;

+        if (viewModel) {

+            vm = viewModel;

+            var fltinfo = getPortFilter();

+            vm.gridTemplate.clearAllChecked();

+            vm.gridTemplate.data(fltinfo.portFilterRules);

+			vm.defaultPolicy(fltinfo.defaultPolicy);

+            vm.oriDefaultPolicy(fltinfo.defaultPolicy);

+            vm.portFilterEnable(fltinfo.portFilterEnable);

+            vm.oriPortFilterEnable(fltinfo.portFilterEnable);

+            vm.rules(fltinfo.portFilterRules);

+            refreshTableHeight();

+            $('#portFilters').find('tbody').translate();

+            renderCheckbox();

+            $('.notes-content').translate();

+            return;

+        }

+

+        vm = new PortFilterVM();

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(vm, container[0]);

+

+        fixTableHeight();

+

+        $('#filterBasicForm').validate({

+            submitHandler: function () {

+                showConfirm("confirm_data_effect", function () {

+                    vm.setPortFilterBasic();

+                });

+            }

+        });

+

+        $('#portFilterListForm').validate({

+            submitHandler: function () {

+                vm.deleteFilterRules();

+            }

+        });

+

+        $('#portFilterForm').validate({

+            submitHandler: function () {

+                vm.save();

+            },

+            rules: {

+                txtMacAddress: {

+                    filter_optional: true,

+                    mac_check: true

+                },

+                txtDestIpAddress: {

+                    ip_check: true

+                },

+                txtSourceIpAddress: {

+                    ip_check: true

+                },

+                txtSourceIpv6Address: {

+                    ipv6: true

+                },

+                txtDestIpv6Address: {

+                    ipv6: true

+                },

+                txtDestPortStart: {

+                    digits: true,

+                    range: [1, 65535],

+                    portCompare: "#txtDestPortEnd"

+                },

+                txtDestPortEnd: {

+                    digits: true,

+                    range: [1, 65535],

+                    portCompare: "#txtDestPortStart"

+                },

+                txtSourcePortStart: {

+                    digits: true,

+                    range: [1, 65535],

+                    portCompare: "#txtSourcePortEnd"

+                },

+                txtSourcePortEnd: {

+                    digits: true,

+                    range: [1, 65535],

+                    portCompare: "#txtSourcePortStart"

+                },

+

+                txtComment: {

+                    comment_check: true

+                }

+            },

+            groups: {

+                destPort: "txtDestPortStart txtDestPortEnd",

+                sourcePort: "txtSourcePortStart txtSourcePortEnd"

+            },

+            errorPlacement: function (error, element) {

+                if (element.attr("name") == "txtMacAddress") {

+                    error.appendTo("#macErrorDiv");

+                } else if (element.attr("name") == "txtDestPortStart" || element.attr("name") == "txtDestPortEnd") {

+                    error.appendTo("#destPortErrorDiv");

+                } else if (element.attr("name") == "txtSourcePortStart" || element.attr("name") == "txtSourcePortEnd") {

+                    error.appendTo("#sourcePortErrorDiv");

+                } else

+                    error.insertAfter(element);

+            }

+        });

+    }

+

+    $.validator.addMethod("filter_optional", function (value, element, param) {

+        var result = _.any(['#txtMacAddress', '#txtDestIpAddress', '#txtSourceIpAddress', '#txtSourceIpv6Address', '#txtDestIpv6Address'],

+                function (item) {

+            var tmp = $(item).val().replace(/\s+/g, '');

+            return $(item + ':visible').length > 0 && tmp != '';

+        });

+

+        var portResult = _.any(['#txtDestPortStart', '#txtDestPortEnd', '#txtSourcePortStart', '#txtSourcePortEnd'],

+                function (item) {

+            return $(item).val() != '0';

+        });

+

+        return result || portResult;

+    });

+

+    return {

+        init: initialize

+    };

+});

+

+//家长控制

+ 

+define("firewall_parental_control","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var maxItem = 10;

+    var pcVm = null;

+    var PAGES = {

+        MAIN: 0,

+        MANAGE: 1,

+        RULE: 2

+    };

+	

+	

+    function ParentalControlVM() {

+        var target = this;

+        var hostNameList = service.getHostNameList({}).devices;

+        target.currentPage = ko.observable(PAGES.MAIN);

+        target.pages = PAGES;

+

+

+        target.childGroupList = ko.observable([]);

+        target.childGroupMac = ko.computed(function () {

+            return _.map(target.childGroupList(), function (data) {

+                return data.mac;

+            });

+        });

+		

+        target.currentUserInChildGroup = ko.observable(true);

+        //获取儿童组设备列表

+         

+        target.fetchChildGroupList = fetchChildGroupListFunc;

+		

+        target.fetchChildGroupList();

+

+        target.manageHandler = manageHandlerFunc;

+		function manageHandlerFunc() {

+            target.currentPage(PAGES.MANAGE);

+            target.fetchAttachedDevices();

+        }

+        target.attachedDevices = ko.observable([]);

+        //获取已连接设备列表

+         

+        target.fetchAttachedDevices = fetchAttachedDevicesFunc;

+		

+

+		//儿童组设备 标签按钮事件

+         

+        target.backToMainHandler = backToMainHandlerFunc;

+		

+		

+        ko.computed(function () {

+            target.attachedDevices();

+            target.childGroupList();

+            $("#pc_children_group_form").translate();

+        }).extend({

+            notify: 'always',

+            throttle: 300

+        });

+        

+        //添加至儿童组

+         

+        function addChildGroupFun(flag, eleData) {

+            showLoading();

+            service.addChildGroup(eleData, function (data) {

+                target.fetchChildGroupList(function () {

+                    target.fetchAttachedDevices(function () {

+                        hideLoading();

+                        if (flag) {

+                            service.logout({}, function () {

+                                window.location = 'index.html';

+                            });

+                        }

+                    });

+                });

+            }, function (data) {

+                errorOverlay();

+            });

+        }

+		

+        //移除按钮事件

+         

+        target.removeChildGroupHandler = removeChildGroupHandlerFunc;

+		

+		

+        //添加按钮事件

+         

+        target.addChildGroupHandler = addChildGroupHandlerFunc;

+		

+

+        target.dealElement = dealElementFunc;

+		

+		

+		

+        //取消编辑主机名按钮事件

+         

+        target.cancelEditHostNameHandler = cancelEditHostNameHandlerFunc;

+		

+        //主机名编辑保存按钮事件

+         

+        target.saveHostNameHandler = saveHostNameHandlerFunc;

+		

+        //主机名编辑按钮事件

+         

+        target.editHostNameHandler = editHostNameHandlerFunc;

+		

+		

+        target.selectedIds = ko.observableArray([]);

+        target.siteList = ko.observable([]);

+        /////////////////////////////////////////////////////////////////

+        target.disableAdd = ko.computed(function () {

+            return target.siteList().length == maxItem;

+        });

+        

+        ko.computed(function () {

+            target.siteList();

+            target.selectedIds();

+            setTimeout(function () {

+                renderCheckbox();

+            }, 100);

+            $("#pc_site_white_list_form").translate();

+        });

+		

+        //网站白名单添加按钮事件

+         

+        target.openAddSitePopoverHandler = openAddSitePopoverHandlerFunc;

+		

+        //网站白名单列表选择框点击事件

+         

+        target.checkboxClickHandler = checkboxClickHandlerFunc;

+		

+		//获取网站白名单列表

+         

+        target.fetchSiteWhiteList = fetchSiteWhiteListFunc;

+		

+		//网站白名单删除函数

+         

+        function removeSiteWhiteItem(ids) {

+            showConfirm('confirm_data_delete', function () {

+                showLoading();

+                service.removeSiteWhite({

+                    ids: ids

+                }, function (data) {

+                    target.fetchSiteWhiteList(function () {

+                        successOverlay();

+                    });

+                }, function (data) {

+                    target.fetchSiteWhiteList(function () {

+                        errorOverlay();

+                    });

+                });

+            });

+        }

+		//网站白名单删除所有按钮事件

+         

+        target.removeAllWhiteSite = removeAllWhiteSiteFunc;

+		

+        //网站白名单删除按钮事件

+         

+        target.removeSelectedWhiteSite = removeSelectedWhiteSiteFunc;

+		

+        //网站白名单移除按钮事件

+         

+        target.removeWhiteSite = removeWhiteSiteFunc;

+		

+        

+        

+        //网站白名单添加框保存按钮事件

+         

+        target.saveSiteWhite = saveSiteWhiteFunc;

+		

+        //////////////////////////////////////////////////////////////////

+        target.notSave = ko.observable(false);

+        //获取时间限制信息

+         

+        target.fetchTimeLimited = fetchTimeLimitedFunc;

+		

+        

+        //上网时间设置时间表格事件绑定

+         

+        target.bindEvent = bindEventFunc;

+		

+		//上网时间设置保存按钮事件

+         

+        target.saveTimeLimitedHandler = saveTimeLimitedHandlerFunc;

+		

+        //////////////////////////////////////////////////////////////////

+        var isBinded = false;

+        //上网规则标签点击事件

+         

+        target.openRulePage = openRulePageFunc;

+		function openRulePageFunc() {

+            if (target.currentPage() == PAGES.RULE) {

+                return;

+            }

+            target.currentPage(PAGES.RULE);

+            target.currentUserInChildGroup(service.checkCurrentUserInChildGroup().result);

+            initTableData();

+            if (!isBinded) {

+                if (!target.currentUserInChildGroup()) {

+                    target.bindEvent();

+                }

+                isBinded = true;

+            }

+            showLoading();

+            target.fetchTimeLimited();

+            target.fetchSiteWhiteList(function () {

+                hideLoading();

+            });

+        }

+		

+		//获取儿童组设备列表

+		function fetchChildGroupListFunc(cb) {

+            service.childGroupList({}, function (data) {

+                target.currentUserInChildGroup(service.checkCurrentUserInChildGroup(data.devices).result);

+                target.childGroupList([]);

+                _.map(data.devices, function (elem, idx) {

+                    elem.idx = idx;

+                    elem.hostname = pcUtil.getHostName(elem.hostname, elem.mac, hostNameList);

+                });

+                target.childGroupList(data.devices);

+                if (_.isFunction(cb)) {

+                    cb.apply(this);

+                }

+            });

+		}

+		

+		//获取已连接设备列表

+		function fetchAttachedDevicesFunc(cb) {

+            target.attachedDevices([]);

+            var counter = 0;

+            var currDevices = [];

+            //RJ45 已连接设备

+            service.getAttachedCableDevices({}, function (data) {

+                counter++;

+                var devs = _.map(data.attachedDevices, function (elem) {

+                    elem.idx = _.uniqueId('wireless_');

+                    elem.hostName = pcUtil.getHostName(elem.hostName, elem.macAddress, hostNameList);

+                    elem.inChildGroup = _.contains(target.childGroupMac(), elem.macAddress);

+                    return elem;

+                });

+                if (counter != 1) {

+                    target.attachedDevices(_.flatten([currDevices, devs]));

+                    if (_.isFunction(cb)) {

+                        cb.apply(this);

+                    }

+                } else {

+                    currDevices = devs;

+                }

+            });

+			

+            //wifi 已连接设备

+            service.getCurrentlyAttachedDevicesInfo({}, function (data) {

+                counter++;

+                var devs = _.map(data.attachedDevices, function (elem) {

+                    elem.idx = _.uniqueId('wireless_');

+                    elem.hostName = pcUtil.getHostName(elem.hostName, elem.macAddress, hostNameList);

+                    elem.inChildGroup = _.contains(target.childGroupMac(), elem.macAddress);

+                    return elem;

+                });

+                if (counter != 1) {

+                    target.attachedDevices(_.flatten([currDevices, devs]));

+                    if (_.isFunction(cb)) {

+                        cb.apply(this);

+                    }

+                } else {

+                    currDevices = devs;

+                }

+            });

+		}

+		//儿童组设备 标签按钮事件

+		function backToMainHandlerFunc() {

+			target.currentPage(PAGES.MAIN);

+		}

+		

+		//移除按钮事件

+		function removeChildGroupHandlerFunc(ele) {

+            showLoading();

+            service.removeChildGroup(ele, function (data) {

+                target.fetchChildGroupList(function () {

+                    target.fetchAttachedDevices(function () {

+                        hideLoading();

+                    });

+                });

+            }, function (data) {

+                errorOverlay();

+            });

+        }

+		

+		//添加按钮事件

+		function addChildGroupHandlerFunc(data) {

+            var uMacAddr = service.getCurretnMAC();

+            if (uMacAddr != data.macAddress) {

+                addChildGroupFun(false, data);

+            } else {

+                showConfirm("parental_add_self", function () {

+                    addChildGroupFun(true, data);

+                })

+            }

+        }

+		

+		//取消编辑主机名按钮事件

+		function cancelEditHostNameHandlerFunc(eleData) {

+            target.dealElement(false, eleData.idx);

+        }

+		

+		//主机名编辑保存按钮事件

+		function saveHostNameHandlerFunc(ele) {

+            var $hostInput = $("#hostname_input_" + ele.idx);

+            var hostname = $.trim($hostInput.val());

+			if (hostname.indexOf(" ") == 0 || hostname.lastIndexOf(" ") == (hostname.length - 1) || /[\*\+\$\[&:,;<>'"\\`\]¥]{1,32}/.test(hostname)) {

+                showAlert('modify_hostname_invalid');

+                return false;

+            }else if (hostname == '') {

+                $(".promptErrorLabel", "#confirm-message-container").text($.i18n.prop("required"));

+                var $closestTD = $hostInput.closest('td').addClass('has-error');

+                addTimeout(function () {

+                    $closestTD.removeClass('has-error');

+                }, 5000);

+                showAlert('required');

+                return false;

+            }  

+            showLoading();

+            ele.hostname = hostname;

+            service.editHostName(ele, function () {

+                service.getHostNameList({}, function (hostNameData) {

+                    hostNameList = hostNameData.devices;

+                    target.fetchChildGroupList(function () {

+                        hideLoading();

+                    });

+                    target.fetchAttachedDevices();

+                });

+            }, function () {

+                errorOverlay();

+            });

+        }

+		

+		//主机名编辑按钮事件

+		function editHostNameHandlerFunc(ele) {

+            $("#hostname_input_" + ele.idx).val(ele.hostname);

+            target.dealElement(true, ele.idx);

+            return false;

+        }

+		//网站白名单添加按钮事件

+		function openAddSitePopoverHandlerFunc() {

+            var addNewSiteTmpl = $("#addNewSiteTmpl").html();

+            popover.open({

+                target: $("#openAddSiteBtn"),

+                html: addNewSiteTmpl,

+                width: "300px",

+                validation: addValidation

+            });

+        }

+		

+		//网站白名单列表选择框点击事件

+		function checkboxClickHandlerFunc(eleData, evt) {

+            addTimeout(function () {

+                target.selectedIds(getSelectedValues());

+            }, 100);

+        }

+		//获取网站白名单列表

+		function fetchSiteWhiteListFunc(cb) {

+            service.getSiteWhiteList({}, function (eledata) {

+                target.selectedIds([]);

+                target.siteList(eledata.siteList);

+                _.isFunction(cb) && cb.apply(this);

+            }, function () {

+                target.siteList([]);

+                _.isFunction(cb) && cb.apply(this);

+            });

+        }

+		

+		//网站白名单删除所有按钮事件

+		function removeAllWhiteSiteFunc() {

+            removeSiteWhiteItem(getAllCheckboxValues());

+        }

+		//网站白名单删除按钮事件

+		function removeSelectedWhiteSiteFunc() {

+            removeSiteWhiteItem(getSelectedValues());

+        }

+		//网站白名单移除按钮事件

+		function removeWhiteSiteFunc(ele, evt) {

+            removeSiteWhiteItem([ele.id]);

+        }

+		

+		//网站白名单添加框保存按钮事件

+		function saveSiteWhiteFunc(name, site) {

+            popover.hide();

+            var matched = _.find(target.siteList(), function (one) {

+                return one.site == site;

+            });

+            if (matched) {

+                showAlert("pc_link_exist", function () {

+                    setTimeout(function () {

+                        popover.show();

+                    }, 200);

+                });

+                return false;

+            }

+

+            showLoading();

+            service.saveSiteWhite({

+                name: name,

+                site: site

+            }, function () {

+                target.fetchSiteWhiteList(function () {

+                    popover.close();

+                    successOverlay();

+                });

+            }, function () {

+                target.fetchSiteWhiteList(function () {

+                    errorOverlay();

+                    popover.show();

+                });

+            });

+        }

+		

+		//上网时间设置时间表格事件绑定

+		function bindEventFunc() {

+            $("td:not('.col-head')", "#pc_time_limited_tbody").addClass('cursorhand').die().click(function () {

+                target.notSave(true);

+                $(this).toggleClass('active');

+            }).hover(function () {

+                var $this = $(this);

+                var w = $this.data('week');

+                var h = $this.data('hour');

+                $("tr:nth-child(" + (w + 1) + ") td:first-child", "#pc_time_limited_tbody").addClass('time_td_hover');

+                $("#col_" + h).addClass('time_td_hover');

+                if ($this.not('.active')) {

+                    $this.addClass('time_td_hover');

+                }

+            }, function () {

+                var $this = $(this);

+                var w = $this.data('week');

+                var h = $this.data('hour');

+                $("tr:nth-child(" + (w + 1) + ") td:first-child", "#pc_time_limited_tbody").removeClass('time_td_hover');

+                $("#col_" + h).removeClass('time_td_hover');

+                $this.removeClass('time_td_hover');

+            });

+        }

+		

+		//上网时间设置保存按钮事件

+		function saveTimeLimitedHandlerFunc() {

+            showLoading();

+            var tds = getSelectedTds();

+            var timeStr = getSavedData(tds);

+            service.saveTimeLimited({

+                time: timeStr

+            }, function () {

+                target.notSave(false);

+                successOverlay();

+            }, function () {

+                errorOverlay();

+            });

+        }

+		

+    }

+	

+		function dealElementFunc(flag, idx) {

+            if (flag == false) {

+                $("#edit_btn_" + idx + ",#hostname_txt_" + idx).show();

+                $("#save_btn_" + idx + ",#cancel_btn_" + idx + ",#hostname_input_" + idx).hide();

+            } else {

+                $("#edit_btn_" + idx + ",#hostname_txt_" + idx).hide();

+                $("#save_btn_" + idx + ",#cancel_btn_" + idx + ",#hostname_input_" + idx).show();

+            }

+        }

+

+		//获取时间限制信息

+		function fetchTimeLimitedFunc() {

+            service.getTimeLimited({}, function (ele) {

+                for (var ki in ele) {

+                    for (var idx = 0; idx < ele[ki].length; idx++) {

+                        var id = 'td_' + ki + '_' + ele[ki][idx];

+                        $("#" + id).addClass('active');

+                    }

+                }

+            }, function () {});

+        }

+

+    var pcUtil = {

+        getHostName: function (hostName, mac, hostNameList) {

+            var ele = _.find(hostNameList, function (ele) {

+                return ele.mac == mac;

+            });

+            return ele ? ele.hostname : hostName;

+        }

+    };

+	function getCheckboxValues(flag) {

+        var selectedValues = [];

+        $(":checkbox" + (flag ? ":checked" : ""), "#pb_white_list").each(function (i, n) {

+            selectedValues.push(n.value)

+        });

+        return selectedValues;

+    }

+    //获取列表中被选中项的value值

+     

+    function getSelectedValues() {

+        return getCheckboxValues(true);

+    }

+    function getAllCheckboxValues() {

+        return getCheckboxValues(false);

+    }

+    

+    //增加网站白名单表单提交函数绑定和校验规则设置

+     

+    function addValidation() {

+        $('#whiteSiteAddForm').validate({

+            submitHandler: function () {

+                var name = $("#siteName").val();

+                var site = $("#siteLink").val();

+                pcVm.saveSiteWhite(name, site);

+            },

+            rules: {

+                siteName: 'siteName_check',

+                siteLink: 'siteLink_check'

+            }

+        });

+    }

+	

+    function getSavedData(timeDatas) {

+        var ret = '';

+        for (var ki in timeDatas) {

+            var hours = _.sortBy(timeDatas[ki], function (n) {

+                return n;

+            });

+            if (timeDatas[ki].length) {

+                ret += ki + '+';

+                ret += hours.join(',');

+                ret += ';'

+            }

+        }

+        return ret.substring(0, ret.length - 1);

+    }

+    //获取时间表格选中的时间

+     

+    function getSelectedTds() {

+        var defaultValue = {

+            '0': [],

+            '1': [],

+            '2': [],

+            '3': [],

+            '4': [],

+            '5': [],

+            '6': []

+        };

+        $("td.active", "#pc_time_limited_tbody").each(function (i, n) {

+            var $this = $(n);

+            var week = $this.data('week');

+            var hour = $this.data('hour');

+            defaultValue[week].push(hour);

+        });

+        return defaultValue;

+    }

+

+	function convertHour(hour) {

+        if (hour <= 16) {

+            return hour + 7;

+        } else {

+            return hour - 17;

+        }

+    }

+    //初始化时间表格

+     

+    function initTableData() {

+        $("tr", "#pc_time_limited_tbody").each(function (idx, n) {

+            var $tr = $(n);

+            $("td:not(:first)", $tr).each(function (j, m) {

+                var $td = $(m);

+                var hour = convertHour(j);

+                $td.attr({

+                    id: 'td_' + idx + '_' + hour

+                }).data({

+                    week: idx,

+                    hour: hour

+                });

+            });

+        });

+        $("td.active", "#pc_time_limited_tbody").removeClass("active");

+        $("thead td:not(:first)", "#pc_time_limited_form").each(function (idx, n) {

+            var hour = convertHour(idx);

+            $(n).attr({

+                id: 'col_' + hour

+            });

+        });

+        pcVm.notSave(false);

+    }

+

+    

+    //页面初始化

+     

+    function initialize() {

+       

+        pcVm = new ParentalControlVM();

+		bindContainer(pcVm);

+    }

+	function bindContainer(pcVm)

+	{

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(pcVm, container[0]);

+	}

+

+    return {

+        init: initialize

+    };

+});

+

+define("firewall_dmz_set","underscore jquery knockout set service".split(" "),

+    function ( _, $, ko, config, service) {

+

+    //system dmz setting VM

+     

+    function DmzSettingVM() {

+        var target = this;

+        var dmzInfo = getDmzSetting();

+        target.dmzSetting = ko.observable(dmzInfo.dmzSetting);

+        target.ipAddress = ko.observable(dmzInfo.ipAddress);

+        target.isDataCard = config.PRODUCT_TYPE == 'DATACARD';

+

+        target.clear = clearFunc;

+        //应用按钮事件

+         

+        target.save = saveFunc;

+		

+		function saveFunc() {

+			showLoading();

+			var params = {};

+			params.dmzSetting = target.dmzSetting();

+			params.ipAddress = target.ipAddress();

+			service.setDmzSetting(params, function (result) {

+				if (result.result != "success") {

+					errorOverlay();

+				} else {

+					target.clear();

+					successOverlay();

+				}

+			});

+		}

+		

+    }

+	

+	function clearFunc() {

+		initialize();

+    }

+	

+	

+    //获取dmz 信息

+     

+    function getDmzSetting() {

+        return service.getDmzSetting();

+    }

+

+    //初始化DmzSettingVM model

+     

+    function initialize() {

+        

+        var dmzVm = new DmzSettingVM();

+        bindContainer(dmzVm);

+    }

+	function bindContainer(dmzVm){

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+		ko.applyBindings(dmzVm, container[0]);

+        $('#dmzSettingForm').validate({

+            submitHandler: function () {

+                dmzVm.save();

+            },

+            rules: {

+                txtIpAddress: 'dmz_ip_check'

+            }

+        });

+	}

+

+    return {

+        init: initialize

+    };

+});

+

+define("firewall","underscore jquery knockout set service".split(" "),

+

+function(_, $, ko, config, service) {

+

+    function FirewallVM() {

+        var target = this;

+		target.hasDdns = config.DDNS_SUPPORT;

+		target.hasUpdateCheck = config.HAS_UPDATE_CHECK;

+		target.hasUrlFilter = config.HAS_URL;

+		target.hasUssd = config.HAS_USSD;

+    }

+

+	function initialize() {        

+        var fwVm = new FirewallVM();

+		bindingContainer(fwVm);

+    }

+	function bindingContainer(fwVm)

+	{

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(fwVm, container[0]);

+	}

+	return {

+		init : initialize

+	};

+});

+

+define("ddns","underscore jquery knockout set service".split(" "), function (_, $, ko, config, service) {

+    var ddnsSetModes = _.map(config.DDNSSetMode, newOption);

+    var ddnsProviderList = _.map(config.DDNSDDP, newOption);

+    var ddns_mode_select = _.map(config.ddns_Modeselect, newOption);

+    function newOption(optItem) {

+        return new Option(optItem.name, optItem.value);

+    }

+    function DdnsViewModel() {

+        var target = this;

+        target.hasUssd = config.HAS_USSD;

+        target.hasUpdateCheck = config.HAS_UPDATE_CHECK;

+        var data = service.getDdnsParams();

+        target.ddnsSetModes = ko.observableArray(ddnsSetModes);

+        target.ddnsProviderList = ko.observableArray(ddnsProviderList);

+        target.ddns_mode_select = ko.observableArray(ddns_mode_select);

+        target.currentMode = ko.observable(data.DDNS_Enable);

+        target.currentModeselect = ko.observable(data.DDNS_Mode);

+        target.currentProviderList = ko.observable("dyndns.org");

+        $.each(config.DDNSDDP, function (i, n) {

+            if (data.DDNSProvider == n.value) {

+                target.currentProviderList(data.DDNSProvider);

+            }

+        });

+        target.DDNSaccount = ko.observable(data.DDNSAccount);

+        target.DDNSpasswd = ko.observable(data.DDNSPassword);

+        target.DDNSname = ko.observable(data.DDNS);

+        target.DDNS_HashValue = ko.observable(data.DDNS_Hash_Value);

+        target.isddnsStatusTrans = ko.observable();

+        target.isEnableSet = ko.observable();

+        target.isHashValue = ko.observable();

+        target.isddnsaccount = ko.observable();

+        target.isddnspasswd = ko.observable();

+        target.isDDNSStatus = ko.observable();

+        target.isddnsdomainName = ko.observable();

+        target.isNone = ko.observable();

+        target.onStates = ko.observable();

+        target.showPassword_ddns = ko.observable(false);

+        target.showPasswordHandler_ddns = showPasswordHandler_ddns;

+        changeddnsProviderList();

+        target.changeDdnsProvider = changeDdnsProviderFunc;

+        changeSetDdnsMode();

+        target.changeSetDdnsMode = changeSetDdnsModeFunc;

+        updateScanDdnsStatus();

+        target.apply = applyFunc;

+        function updateScanDdnsStatus() {

+            var trans = "";

+            $.getJSON("/reqproc/proc_get", {

+                cmd: "getddns_status",

+                "_": new Date().getTime()

+            }, function (data) {

+                if (data.getddns_status == "0") {

+                    trans = "register successful";

+                    target.onStates(true);

+                } else if (data.getddns_status == "1") {

+                    trans = "login error";

+                    target.onStates(true);

+                } else if (data.getddns_status == "2") {

+                    trans = "network error";

+                    target.onStates(true);

+                } else if (data.getddns_status == "3") {

+                    trans = "registering";

+                    target.onStates(true);

+                } else if (data.getddns_status == "4") {

+                    trans = "not registered";

+                    target.onStates(true);

+                } else if (data.getddns_status == "5") {

+                    trans = "error registering";

+                    target.onStates(true);

+                } else if (data.getddns_status == "-1") {

+                    trans = "";

+                    target.onStates(true);

+                }

+                target.isddnsStatusTrans($.i18n.prop(trans));

+                addTimeout(updateScanDdnsStatus, 2000);

+            });

+        }

+        function changeSetDdnsMode() {

+            if (target.currentMode() != "1") {

+                target.isEnableSet(false);

+            } else {

+                target.isEnableSet(true);

+            }

+            return true;

+        }

+        function changeSetDdnsModeFunc() {

+            changeSetDdnsMode();

+        }

+        function showPasswordHandler_ddns() {

+            $("#ddns_secretcode_input").parent().find(".error").hide();

+            var checkbox = $("#showPassword_ddns:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showPassword_ddns(true);

+            } else {

+                target.showPassword_ddns(false);

+            }

+        }

+        function changeDdnsProviderFunc() {

+            if (data.DDNSProvider != target.currentProviderList()) {

+                target.DDNSaccount("");

+                target.DDNSpasswd("");

+                target.DDNSname("");

+            } else {

+                target.DDNSaccount(data.DDNSAccount);

+                target.DDNSpasswd(data.DDNSPassword);

+                target.DDNSname(data.DDNS);

+            }

+            changeddnsProviderList();

+        }

+        function changeddnsProviderList() {

+            if (target.currentProviderList() != "none") {

+                target.isddnsaccount(true);

+                target.isddnspasswd(true);

+                target.isddnsdomainName(true);

+                target.isHashValue(true);

+                target.isDDNSStatus(true);

+            } else {

+                target.isddnsaccount(false);

+                target.isddnspasswd(false);

+                target.isddnsdomainName(false);

+                target.isHashValue(false);

+                target.isDDNSStatus(false);

+            }

+            if (target.currentProviderList() != "freedns.afraid.org") {

+                target.isHashValue(false);

+            } else {

+                target.isHashValue(true);

+            }

+            return true;

+        }

+        function applyFunc() {

+            showLoading();

+            var params = {};

+            params.goformId = "DDNS";

+            params.DDNS_Enable = target.currentMode();

+            if (target.currentMode() == "1") {

+                params.DDNS_Mode = target.currentModeselect();

+                params.DDNSProvider = target.currentProviderList();

+                if (target.currentProviderList() != "none") {

+                    params.DDNS = target.DDNSname();

+                    params.DDNSPassword = target.DDNSpasswd();

+                    params.DDNSAccount = target.DDNSaccount();

+                }

+                if (target.currentProviderList() == "freedns.afraid.org") {

+                    params.DDNS_Hash_Value = target.DDNS_HashValue();

+                }

+            }

+            service.setDDNSForward(params, function (result) {

+                if (result.result == "success") {

+                    successOverlay();

+                    data = service.getDdnsParams();

+                } else {

+                    errorOverlay();

+                }

+            });

+        }

+    }

+    function initialize() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var vm = new DdnsViewModel();

+        ko.applyBindings(vm, container[0]);

+        $("#ddnsForm").validate({

+            submitHandler: function () {

+                vm.apply();

+            },

+            rules: {

+                ddns_secretcode_input: "secretcode_check",

+                DDNS_Hash_Value: "ddns_hashvalue_check",

+                ddns_secretcode_inputshow: "secretcode_check"

+            },

+            errorPlacement: function (error, element) {

+                var id = element.attr("id");

+                if (id == "ddns_secretcode_input" || id == "ddns_secretcode_inputshow") {

+                    error.insertAfter("#lblShowPassword");

+                } else {

+                    error.insertAfter(element);

+                }

+            }

+        });

+    }

+    return {

+        init: initialize

+    };

+});

+

+

+//选网模块

+ 

+define("network_net_select","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var selectModes = _.map(config.AUTO_MODES, function (item) {

+        return new Option(item.name, item.value);

+    });

+

+    //选网功能view model

+     

+    function NetSelectVM() {

+        var target = this;

+

+        target.networkList = ko.observableArray([]);

+        target.selectNetwork = ko.observable('');

+        target.enableFlag = ko.observable(true);

+        target.types = ko.observableArray(selectModes);

+        target.selectedType = ko.observable();

+        target.selectMode = ko.observable();

+

+		target.networkText = networkTextFunc;

+		

+		target.networkStatusId = networkStatusIdFunc;

+		

+        target.networkStatus = networkStatusFunc;

+

+        target.subnetworkType = subnetworkTypeFunc;

+

+		target.networkType = networkTypeFunc;

+

+        target.operatorName = operatorNameFunc;

+

+        target.networkValue = networkValueFunc;

+

+        target.networkTypeId = networkTypeIdFunc;

+

+        target.subnetTypeId = subnetTypeIdFunc;

+       //手动搜网.

+         

+        target.search = searchFunc;

+

+        //自动选网时设置网络模式.

+         

+        target.save = saveFunc;

+

+        target.checkEnable = checkEnableFunc;

+

+        //注册选择的网络.

+         

+        target.register = registerFunc;

+

+        //init data

+        target.checkEnable();

+        var info = getNetSelectInfo();

+        if ("manual_select" == info.net_select_mode || "manual_select" == info.m_netselect_save) {

+            target.selectMode("manual_select");

+        } else {

+            target.selectMode("auto_select");

+        }

+

+        target.selectedType(info.net_select);

+		

+		//注册选择的网络.

+		function registerFunc() {

+            showLoading('registering_net');

+            var networkToSet = target.selectNetwork().split(',');

+            service.setNetwork(networkToSet[0], parseInt(networkToSet[1]), parseInt(networkToSet[2]), function (result) {

+                if (result) {

+                    target.networkList([]);

+                    var autoType = getNetSelectInfo();

+                    target.selectedType(autoType.net_select);

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+        }

+		

+		function checkEnableFunc() {

+            var status = service.getStatusInfo();

+            if (status.connectStatus == "ppp_connected" || status.connectStatus == "ppp_connecting") {

+                target.enableFlag(false);

+            } else {

+                target.enableFlag(true);

+            }

+        }

+		

+		//自动选网时设置网络模式.

+		function saveFunc() {

+            showLoading();

+

+            //AutoSelect call SetBearerPreference

+            var params = {};

+            params.strBearerPreference = target.selectedType();

+            service.setBearerPreference(params, function (result) {

+                if (result.result == "success") {

+                    target.networkList([]);

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+        }

+		

+		//手动搜网.

+		function searchFunc() {

+            showLoading('searching_net');

+            service.scanForNetwork(function (result, networkList) {

+                hideLoading();

+                if (result) {

+                    target.networkList(networkList);

+                    for (var i = 0; i < networkList.length; i++) {

+                        var n = networkList[i];

+                        if (n.nState == '2') {

+                            target.selectNetwork(n.strNumeric + ',' + n.nRat + ',' + n.SubAct);

+                            return;

+                        }

+                    }

+                } else {

+                    target.networkList([]);

+                }

+            });

+        }

+		

+		function subnetTypeIdFunc(data) {

+            return getSubNetworkTypeTog(data.nRat, data.SubAct);

+        }

+		

+		function networkTypeIdFunc(data) {

+            return getNetworkType(data.nRat);

+        }

+		

+		function networkValueFunc(data) {

+            var result = [];

+            result.push(data.strNumeric); //strNumeric

+            result.push(data.nRat); //nRat

+            result.push(data.SubAct);

+            return result.join(',');

+        }

+		

+		function operatorNameFunc(data) {

+            return data.strShortName;

+        }

+		

+		function networkTypeFunc(data) {

+            var result = getNetworkType(data.nRat);

+            if (result == "auto")

+                result = $.i18n.prop("auto");

+            return result;

+        }

+		

+		function subnetworkTypeFunc(data) {

+            var result = getSubNetworkTypeTog(data.nRat, data.SubAct);

+            return result;

+        }

+		

+		function networkStatusFunc(data) {

+            return $.i18n.prop(getNetworkStatusTog(data.nState));

+        }

+		

+		function networkStatusIdFunc(data) {

+            return getNetworkStatusTog(data.nState);

+        }

+		

+		function networkTextFunc(data) {

+            return data.strNumeric;

+        }

+

+    }

+

+    //获取网络选择信息.

+     

+    function getNetSelectInfo() {

+        return service.getNetSelectInfo();

+    }

+

+    //搜网结果中的状态转换为对应的语言项.

+     

+    function getNetworkStatusTog(status) {

+        if ("3" == status) {

+            return "forbidden";

+        } else if ("2" == status) {

+            return "current";

+        } else if ("1" == status) {

+            return "available";

+        }else if ("0" == status) {

+            return "unknown";

+        }

+    }

+	//子网络类型转换.

+     

+    function getSubNetworkTypeTog(type, subtype) {

+        var type_3g = [2, 4, 5, 6, 8];

+        if ("1" == subtype) {

+            if ("7" == type) {

+                subtype = "FDD-LTE";

+            } else if ($.inArray(type, type_3g) != -1) {

+                subtype = "WCDMA";

+            }else {

+                subtype = "GSM";

+            }

+        } else if ("0" == subtype) {

+            if ("7" == type) {

+                subtype = "TD-LTE";

+            } else if ($.inArray(type, type_3g) != -1) {

+                subtype = "TD-SCDMA";

+            } else {

+                subtype = "GSM";

+            }

+        } else {

+            subtype = "";

+        }

+        return subtype;

+    }

+    //网络类型转换.

+     

+    function getNetworkType(type) {

+        if ("7" == type) {

+            return "4G";

+        } else if ("2" == type) {

+            return "3G";

+        } else if ("0" == type) {

+            return "2G";

+        } else {

+            return "auto";

+        }

+    }

+

+    function bindContainer(vm){

+	

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(vm, container[0]);

+	}

+

+    //初始化选网功能view model.

+     

+    function initialize() {

+        var vm = new NetSelectVM();

+		bindContainer(vm);

+        addInterval(vm.checkEnable, 1000);

+    }

+

+    return {

+        init: initialize

+    };

+});

+define("locknet","jquery knockout service jquery set main".split(" "),

+    function ($, ko, service, config, home) {

+

+    function initialize() {

+        var container = $('#container')[0];

+        ko.cleanNode(container);

+        var vm = new locknetViewMode();

+        ko.applyBindings(vm, container);

+

+        $("#frmNetworkLock").validate({

+            submitHandler: function () {

+                vm.unlock();

+            },

+            rules: {

+                txtLockNumber: "unlock_code_check"

+            }

+        });

+    }

+

+    function locknetViewMode() {

+        var target = this;

+        var curCableMode = false;

+        target.isCPE = config.PRODUCT_TYPE == 'CPE';

+        target.hasRj45 = config.RJ45_SUPPORT;

+        target.hasSms = config.HAS_SMS;

+        target.hasPhonebook = config.HAS_PHONEBOOK;

+        target.isSupportSD = config.SD_CARD_SUPPORT;

+        if (config.WIFI_SUPPORT_QR_SWITCH == false) {

+            target.showQRCode = config.WIFI_SUPPORT_QR_CODE;

+        } else {

+            var wifiInfo = service.getWifiBasic();

+            target.showQRCode = config.WIFI_SUPPORT_QR_CODE && wifiInfo.show_qrcode_flag;

+        }

+        target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + $.now();

+        target.hasParentalControl = ko.observable(config.HAS_PARENTAL_CONTROL && curCableMode);

+        target.deviceInfo = ko.observable([]);

+        target.isHomePage = ko.observable(false);

+        if (window.location.hash == "#main") {

+            target.isHomePage(true);

+        }

+

+        target.supportUnlock = config.NETWORK_UNLOCK_SUPPORT;

+        target.unlockCode = ko.observable();

+

+        var info = service.getNetworkUnlockTimes();

+        target.times = ko.observable(info.unlock_nck_time);

+

+        //显示工作模式设置窗口

+        target.showOpModeWindow = showOpModeWindowFunc;

+		

+        target.isLoggedIn = ko.observable(false);

+        target.enableFlag = ko.observable(false);

+        //解锁

+        target.unlock = unlockFunc;

+

+        //更新工作模式状态

+        target.refreshOpmodeInfo = refreshOpmodeInfoFunc;

+		

+        //定时检查工作模式状态

+        if (target.hasRj45) {

+            target.refreshOpmodeInfo();

+            addInterval(function () {

+                target.refreshOpmodeInfo();

+            }, 1000);

+        }

+		

+		//更新工作模式状态

+		function refreshOpmodeInfoFunc() {

+            var obj = service.getStatusInfo();

+            target.isLoggedIn(obj.isLoggedIn);

+

+            if (!curCableMode && checkCableMode(obj.blc_wan_mode)) { //如果有线,则重新加载

+                window.location.reload();

+                return;

+            }

+

+            curCableMode = checkCableMode(obj.blc_wan_mode);

+            target.hasParentalControl(config.HAS_PARENTAL_CONTROL && curCableMode);

+            if (curCableMode && obj.ethWanMode.toUpperCase() == "DHCP") {

+                target.enableFlag(true);

+            } else if ((!curCableMode && obj.connectStatus != "ppp_disconnected") || (curCableMode && obj.rj45ConnectStatus != "idle" && obj.rj45ConnectStatus != "dead")) {

+                target.enableFlag(false);

+            } else {

+                target.enableFlag(true);

+            }

+            var getMode = (obj.blc_wan_mode == "AUTO_PPP" || obj.blc_wan_mode == "AUTO_PPPOE") ? "AUTO" : obj.blc_wan_mode;

+            var currMode = "";

+            switch (getMode) {

+			case "PPP":

+                currMode = "opmode_gateway";

+                break;

+			case "PPPOE":

+                currMode = "opmode_cable";

+                break;

+            case "AUTO":

+                currMode = "opmode_auto";

+                break;

+            default:

+                break;

+            }

+            $("#opmode").attr("data-trans", currMode).text($.i18n.prop(currMode));

+        }

+		

+		//解锁

+		function unlockFunc() {

+            showLoading();

+            service.unlockNetwork({

+                unlock_network_code: target.unlockCode()

+            }, function (data) {

+                target.unlockCode("");

+                if (data && data.result == "success") {

+                    successOverlay();

+                    if (window.location.hash == "#main") {

+                        setTimeout(function () {

+                            window.location.reload();

+                        }, 500);

+                    } else {

+                        window.location.hash = "#main";

+                    }

+                } else {

+                    var info = service.getNetworkUnlockTimes();

+                    target.times(info.unlock_nck_time);

+                    errorOverlay();

+                }

+            })

+        }

+		

+		//显示工作模式设置窗口

+		function showOpModeWindowFunc() {

+            showSettingWindow("change_mode", "opmode_popup", "opmode_popup", 400, 300, function () {});

+        }

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+// RJ45联网设置模块

+ 

+define("network_dial_set_cpe","underscore jquery knockout set service".split(" "),

+function(_, $, ko, config, service) {

+	var dialActions = _.map(config.dialActions, function(elem){

+		return new Option(elem.name, elem.value);

+	});

+	

+	var dialModes = _.map(config.pppoeModes, function(elem) {

+		return new Option(elem.name, elem.value);

+	});

+		

+    var checkStatusTimer = 0;

+    var checkConCounter = 0;

+    var timeoutTipShowed = false;

+

+    // 联网设置view model.

+     

+	function PPPoEViewModel() {

+		var pppObj = service.getPppoeParams();

+        var ethParams = pppObj;

+		var target = this;

+		

+		target.staticNoticeShow = ko.observable();

+		target.dhcpNoticeShow = ko.observable();

+		target.pppoeNoticeShow = ko.observable();

+		target.autoNoticeShow = ko.observable();

+		target.staticNotice = ko.observable();

+		target.dhcpNotice = ko.observable();

+		target.pppoeNotice = ko.observable();

+		target.autoNotice = ko.observable();

+		target.dhcpNoticeText = ko.observable();

+		target.staticNoticeText = ko.observable();

+		target.pppoeNoticeText = ko.observable();

+        target.autoNoticeText = ko.observable();		

+		target.currentMode = ko.observable(pppObj.ethwan_mode);//auto dhcp pppoe static

+		target.showPassword = ko.observable(false);

+		target.modes = ko.observableArray(dialModes);

+		target.isPppoeMode = ko.observable(false);

+		target.isStaticMode = ko.observable(false);

+		target.isAutoMode = ko.observable(false);

+		target.action = ko.observable();

+		target.btnTrans = ko.observable();

+		target.enableFlag = ko.observable();

+		target.isShowDisbtn = ko.observable();

+		target.isShowCancelbtn = ko.observable();

+		

+		if(pppObj.rj45_state == "dead"){

+			checkRj45DeadTip();

+		} else if(pppObj.rj45_state == "connect"){

+			timeoutTipShowed = true;

+			setRj45CheckTimer("connect");

+		} else if(pppObj.rj45_state == "working"){

+			setRj45WorkingTip();

+		}

+		

+		target.user = ko.observable(pppObj.pppoe_username);

+		target.password = ko.observable(pppObj.pppoe_cc);

+		target.autoUser = ko.observable(pppObj.pppoe_username);

+		target.autoPassword = ko.observable(pppObj.pppoe_cc);

+		target.pppMode = ko.observable(pppObj.ethwan_dialmode);

+		initContronler();

+		

+

+		//下拉框选择改变下面DIV模块

+		target.changeModeDiv = changeModeDivFunc;

+				

+		target.radioHandler = radioHandlerFunc;

+				

+		target.primaryDNS = ko.observable(pppObj.static_wan_primary_dns);

+		target.secondaryDNS = ko.observable(pppObj.static_wan_secondary_dns);

+		target.ipAddress = ko.observable(pppObj.static_wan_ipaddr);

+		target.subnetMask = ko.observable(pppObj.static_wan_netmask);

+		target.defaultGateway = ko.observable(pppObj.static_wan_gateway);

+		

+		addInterval(function(){

+			ethParams = service.getPppoeParams();

+			pppObj.rj45_state = ethParams.rj45_state;

+			initContronler();

+		}, 1000);

+		

+        // 取消连接按钮事件.

+         					

+		target.cancelConnect = cancelConnectFunc;

+		

+        // 应用按钮事件.

+         		

+		target.save = saveFunc;

+		

+		 //密码显示事件

+        target.showPasswordHandler = function () {

+            var checkbox = $("#showPassword:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showPassword(true);

+            } else {

+                target.showPassword(false);

+            }

+        };

+		

+        // 更新当前界面状态、按钮、提示语等.

+         			

+		function initContronler() {	

+            checkRj45DeadTip();		

+			if(target.currentMode() == "PPPOE"){

+				target.isPppoeMode(true);

+				target.isStaticMode(false);

+				target.isAutoMode(false);

+				target.staticNoticeShow(false);

+				target.dhcpNoticeShow(false);	

+				target.autoNoticeShow(false);	

+			} else if(target.currentMode() == "AUTO"){

+				target.isStaticMode(false);

+				target.isPppoeMode(false);

+				target.isAutoMode(true);

+				target.dhcpNoticeShow(false);

+				target.pppoeNoticeShow(false);

+				target.staticNoticeShow(false);

+			} else if(target.currentMode() == "STATIC"){

+				target.isStaticMode(true);

+				target.isPppoeMode(false);

+				target.isAutoMode(false);

+				target.dhcpNoticeShow(false);

+				target.pppoeNoticeShow(false);

+				target.autoNoticeShow(false);

+			} else{

+				target.isStaticMode(false);

+				target.isPppoeMode(false);

+				target.isAutoMode(false);

+				target.staticNoticeShow(false);

+				target.pppoeNoticeShow(false);

+                target.autoNoticeShow(false);					

+			}

+			if(ethParams.ethwan_dialmode != "auto_dial" && (pppObj.rj45_state == "working" || pppObj.rj45_state =="connect") ){

+				target.enableFlag(false);

+			} else {

+				target.enableFlag(true);

+			}

+			if(pppObj.rj45_state == "connect"){

+				if(target.pppMode() == "auto_dial"){

+					target.action("connect");

+				}else{

+					target.action("disconnect");

+				}					

+			} else if(pppObj.rj45_state == "working"){

+				target.action("disconnect");

+			}else{

+				target.action("connect");

+			}

+			//应用/连接按钮

+			if(target.pppMode() != "auto_dial" && target.currentMode() == ethParams.ethwan_mode){

+				target.btnTrans("connect");

+			} else{

+				target.btnTrans("apply");

+			}

+			if(pppObj.rj45_state != "idle"){

+				$("#pppoeApply").attr("disabled", true);

+		    }else {

+				$("#pppoeApply").attr("disabled", false);

+            }

+			

+			//取消/断开按钮

+			target.isShowDisbtn(target.pppMode() != "auto_dial" && pppObj.rj45_state == "working");

+			target.isShowCancelbtn(target.pppMode() != "auto_dial" && pppObj.rj45_state == "connect");

+			

+			$("#pppoeApply").translate();

+		}

+        // 设置后通过定时检查rj45_state状态,判断连接或断开操作结果.

+         		

+	    function setRj45CheckTimer(action){

+            checkStatusTimer && window.clearInterval(checkStatusTimer);

+            if("connect" != action){				

+                checkStatusTimer = addInterval(function () {

+                    checkDisconnectStatus();

+                }, 2000);

+            }else{

+                if(target.currentMode() == "PPPOE"){

+                    target.pppoeNoticeShow(true);

+                    target.pppoeNotice("pppoe_processing");

+                    target.pppoeNoticeText($.i18n.prop("pppoe_processing"));

+                } else if(target.currentMode() == "STATIC"){

+                    target.staticNoticeShow(true);

+                    target.staticNotice("static_processing");

+                    target.staticNoticeText($.i18n.prop("static_processing"));

+                } else if(target.currentMode() == "DHCP"){

+                    target.dhcpNoticeShow(true);

+                    target.dhcpNotice("dyn_processing");

+                    target.dhcpNoticeText($.i18n.prop("dyn_processing"));

+                }else{

+                    target.autoNoticeShow(true);

+                    target.autoNotice("auto_processing");

+                    target.autoNoticeText($.i18n.prop("auto_processing"));

+                }

+                checkStatusTimer = addInterval(function () {

+                    checkConnectionStatus();

+                }, 2000);

+            }			

+        }

+        // 设置后通过定时检查rj45_state状态,判断连接操作结果.

+         			

+        function checkConnectionStatus(){

+            if(checkConCounter < 1){

+				checkConCounter++;

+				return;

+            }

+            if(pppObj.rj45_state == "connect"){

+                if(target.currentMode() != ethParams.ethwan_mode){

+                    if(target.currentMode() == "AUTO"){

+                        target.autoNoticeShow(true);

+                    }else if(target.currentMode() == "PPPOE"){

+                        target.pppoeNoticeShow(true);

+                    }else if(target.currentMode() == "STATIC"){

+                        target.staticNoticeShow(true);

+                    }else if(target.currentMode() == "DHCP"){

+                        target.dhcpNoticeShow(true);

+                    }

+                }

+                if(checkConCounter > 6){

+                    if(timeoutTipShowed == false){

+                        timeoutTipShowed = true;

+                        showAlert("ussd_operation_timeout");

+                    }

+                }

+                checkConCounter++;

+            } else if (pppObj.rj45_state == "working") {

+                hideLoading();

+                setRj45WorkingTip();

+                window.clearInterval(checkStatusTimer);						

+            } else if (pppObj.rj45_state == "dead") {

+				hideLoading();

+				checkRj45DeadTip();

+                window.clearInterval(checkStatusTimer);

+            } else if(pppObj.rj45_state == "idle"){

+                hideLoading();

+                if(target.currentMode() == "DHCP" && ethParams.ethwan_mode == "DHCP") {

+                    timeoutTipShowed == false && target.dhcpNoticeShow(true);

+                    target.dhcpNotice("dyn_fail");

+                    target.dhcpNoticeText($.i18n.prop("dyn_fail"));

+                }

+                if(target.currentMode() == "STATIC" && ethParams.ethwan_mode == "STATIC") {

+                    timeoutTipShowed == false && target.staticNoticeShow(true);

+                    target.staticNotice("static_fail");

+                    target.staticNoticeText($.i18n.prop("static_fail"));

+                }

+                if(target.currentMode() == "PPPOE" && ethParams.ethwan_mode == "PPPOE") {

+                    timeoutTipShowed == false && target.pppoeNoticeShow(true);

+                    target.pppoeNotice("pppoe_fail");

+                    target.pppoeNoticeText($.i18n.prop("pppoe_fail"));

+                }

+                if(target.currentMode() == "AUTO" && ethParams.ethwan_mode == "AUTO") {

+                    timeoutTipShowed == false && target.autoNoticeShow(true);

+                    target.autoNotice("auto_fail");

+                    target.autoNoticeText($.i18n.prop("auto_fail"));

+                }

+                window.clearInterval(checkStatusTimer);

+            }   else{

+                hideLoading();

+				window.clearInterval(checkStatusTimer);

+			}

+        }

+		// 设置连接成功时提示语状态.

+         		

+        function setRj45WorkingTip(){

+            if(target.currentMode() == ethParams.ethwan_mode){

+                if(target.currentMode() == "AUTO") {

+                    target.autoNoticeShow(true);

+                    target.autoNotice("auto_success");

+                    target.autoNoticeText($.i18n.prop("auto_success"));

+                }else if(target.currentMode() == "PPPOE") {

+                    target.pppoeNoticeShow(true);

+                    target.pppoeNotice("pppoe_success");

+                    target.pppoeNoticeText($.i18n.prop("pppoe_success"));

+                }else if(target.currentMode() == "STATIC") {

+                    target.staticNoticeShow(true);

+                    target.staticNotice("static_success");

+                    target.staticNoticeText($.i18n.prop("static_success"));

+                }else if(target.currentMode() == "DHCP" ) {

+                    target.dhcpNoticeShow(true);

+                    target.dhcpNotice("dyn_success");

+                    target.dhcpNoticeText($.i18n.prop("dyn_success"));

+                }

+            }

+        }

+		

+		// 设置网线断开提示语状态.

+         		

+        function checkRj45DeadTip(){

+            if(pppObj.rj45_state != "dead"){

+                if(target.currentMode() == "AUTO"  && target.autoNotice() == "pppoe_msg") {

+                    target.autoNoticeShow(false);

+                }else if(target.currentMode() == "PPPOE"  && target.pppoeNotice() == "pppoe_msg") {

+                    target.pppoeNoticeShow(false);

+                }else if(target.currentMode() == "STATIC"  && target.staticNotice() == "pppoe_msg") {

+                    target.staticNoticeShow(false);

+                }else if(target.currentMode() == "DHCP" && target.dhcpNotice() == "pppoe_msg") {

+                    target.dhcpNoticeShow(false);

+                }				

+                

+            } else{

+				target.dhcpNotice("pppoe_msg");

+                target.dhcpNoticeText($.i18n.prop("pppoe_msg"));

+                target.staticNotice("pppoe_msg");

+                target.staticNoticeText($.i18n.prop("pppoe_msg"));

+                target.pppoeNotice("pppoe_msg");

+                target.pppoeNoticeText($.i18n.prop("pppoe_msg"));

+                target.autoNotice("pppoe_msg");

+                target.autoNoticeText($.i18n.prop("pppoe_msg"));

+                if(target.currentMode() == "AUTO") {

+                    target.autoNoticeShow(true);

+                }else if(target.currentMode() == "PPPOE") {

+                    target.pppoeNoticeShow(true);

+                }else if(target.currentMode() == "STATIC") {

+                    target.staticNoticeShow(true);

+                }else if(target.currentMode() == "DHCP") {

+                    target.dhcpNoticeShow(true);

+                }

+            }            

+		}

+        // 设置后通过定时检查rj45_state状态,判断断开操作结果.

+         		

+        function checkDisconnectStatus(){

+            if(checkConCounter < 1){

+                checkConCounter++;

+            } else if (pppObj.rj45_state != "working" && pppObj.rj45_state != "connect") {

+                target.dhcpNoticeShow(false);

+                target.staticNoticeShow(false);

+                target.pppoeNoticeShow(false);

+                target.autoNoticeShow(false);

+                window.clearInterval(checkStatusTimer);

+                successOverlay();

+            } else if(checkConCounter > 6){

+                if(timeoutTipShowed == false){

+                    timeoutTipShowed = true;

+                    showAlert("ussd_operation_timeout");

+                }

+                window.clearInterval(checkStatusTimer);

+            } else if(checkConCounter < 7) {

+                checkConCounter++;

+            } else {

+                hideLoading();

+                window.clearInterval(checkStatusTimer);

+            }				

+        }

+        

+		//应用按钮事件.

+		function saveFunc(){

+			target.dhcpNoticeShow(false);

+			target.staticNoticeShow(false);

+			target.pppoeNoticeShow(false);

+			target.autoNoticeShow(false);

+			if(pppObj.rj45_state == "dead"){

+				showAlert("pppoe_msg");

+				return;

+			}

+			var requestParams = {};

+			if($("#pppoe_mode").val() == "PPPOE") {

+				requestParams = $.extend({}, {

+					goformId: "WAN_GATEWAYMODE_PPPOE",

+					pppoe_username: target.user(),

+					pppoe_cc: target.password()

+				});

+			} else if($("#pppoe_mode").val() == "AUTO") {

+				requestParams = $.extend({}, {

+					goformId: "WAN_GATEWAYMODE_AUTO",

+					pppoe_username: target.autoUser(),

+					pppoe_cc: target.autoPassword()

+				});

+			} else if($("#pppoe_mode").val() == "STATIC") {

+				if(target.ipAddress() == target.defaultGateway()){

+					showAlert("ip_gate_not_same");

+					return;

+				}

+				if(isStaticIPValid(target.ipAddress(), pppObj.lan_ipaddr, pppObj.lan_netmask)){

+					showAlert("ip_innergate_not_same");

+					return;

+				}

+				requestParams = $.extend({}, {

+					goformId: "WAN_GATEWAYMODE_STATIC",

+					static_wan_ipaddr: target.ipAddress(),

+					static_wan_netmask: target.subnetMask(),

+					static_wan_gateway: target.defaultGateway(),

+					static_wan_primary_dns: target.primaryDNS(),

+					static_wan_secondary_dns: target.secondaryDNS(),

+					WAN_MODE: "STATIC"

+				});

+			} else {

+				requestParams = $.extend({}, {

+					goformId: "WAN_GATEWAYMODE_DHCP"

+				});

+			}

+			requestParams.action_link = "connect";

+			requestParams.dial_mode = target.pppMode();

+			showLoading("waiting");

+			

+			service.setPppoeDialMode(requestParams, function(data){

+				if(data.result){

+					target.currentMode($("#pppoe_mode").val());

+					pppObj = service.getPppoeParams();

+					checkConCounter = 0;

+					timeoutTipShowed = false;

+					setRj45CheckTimer("connect");					

+					$("#pppoeApply").translate();

+                } else {

+					errorOverlay("pppoe_message_send_fail");

+                }

+			});

+			

+		}

+		

+		//取消连接按钮事件.

+		function cancelConnectFunc(){

+			target.dhcpNoticeShow(false);

+			target.staticNoticeShow(false);

+			target.pppoeNoticeShow(false);

+			target.autoNoticeShow(false);

+			if(pppObj.rj45_state == "dead"){

+				showAlert("pppoe_msg");

+				return;

+			}

+			var requestParams = {

+				dial_mode: target.pppMode(),

+				action_link: "disconnect"

+			};

+			if(pppObj.ethwan_mode == "PPPOE") {

+				requestParams = $.extend(requestParams, {

+					goformId: "WAN_GATEWAYMODE_PPPOE",

+					pppoe_username: pppObj.pppoe_username,

+					pppoe_cc: pppObj.pppoe_cc					

+				});

+			}else if(pppObj.ethwan_mode == "AUTO") {

+				requestParams = $.extend(requestParams, {

+					goformId: "WAN_GATEWAYMODE_AUTO",

+					pppoe_username: pppObj.pppoe_username,

+					pppoe_cc: pppObj.pppoe_cc					

+				});

+			}else if(pppObj.ethwan_mode == "STATIC") {

+				requestParams = $.extend(requestParams, {

+					goformId: "WAN_GATEWAYMODE_STATIC",

+					static_wan_ipaddr: pppObj.static_wan_ipaddr,

+					static_wan_netmask: pppObj.static_wan_netmask,

+					static_wan_gateway: pppObj.static_wan_gateway,

+					static_wan_primary_dns: pppObj.static_wan_primary_dns,

+					static_wan_secondary_dns: pppObj.static_wan_secondary_dns,

+					WAN_MODE: "STATIC"

+				});

+			}else {

+				requestParams = $.extend(requestParams, {

+					goformId: "WAN_GATEWAYMODE_DHCP"

+				});

+			}

+			showLoading("waiting");

+			service.setPppoeDialMode(requestParams, function(data){

+				if(data.result){

+                    checkConCounter = 0;

+					timeoutTipShowed = false;

+					setRj45CheckTimer("disconnect");

+					$("#pppoeApply").translate();

+                } else {

+					errorOverlay("pppoe_message_send_fail");

+                }

+			});

+			

+		}

+		

+		function radioHandlerFunc(){

+			initContronler();

+			return true;

+		}

+		

+		function changeModeDivFunc(){

+			initContronler();

+		}

+        

+    }

+

+	function bindContainer(vm){

+		var container = $('#container');

+		ko.cleanNode(container[0]);

+		ko.applyBindings(vm, container[0]);

+	

+	}

+    // 联网设置初始化.

+     

+	function initialize() {

+		var vm = new PPPoEViewModel();

+		bindContainer(vm);

+		

+		$("#pppoeApply").translate();

+		

+		$('#pppoeForm').validate({

+			submitHandler : function() {

+				vm.save();

+			},

+            rules: {

+                txtPin: "wps_pin_check",

+				txtIpAddress: "dmz_ip_check",

+				txtSubnetMask: {

+					ipv4: true,

+                    subnetmask_check: true

+				},

+				txtDefaultGateway: {

+					ipv4: true,

+					gateway_check: true

+				},

+				txtPrimaryDNS: {

+					ipv4: true,

+					dns_check:true

+				},

+				txtSecondaryDNS: {

+					ipv4: true,

+					dns_check:true

+				}

+            }

+		});

+	}

+	

+	

+//from 4.0

+    // 有效DNS检查.

+     

+function validateDns(dns){

+	if ( "0.0.0.0" == dns || "255.255.255.255" == dns) {

+		return false;

+	}

+	return true;

+}

+    // 联网设置初始化.

+     

+function isStaticIPValid(ip, lanip, lanmask){

+	if(!ip || !lanip || !lanmask){//各参数不能为空

+        return false;

+    }

+	if(ip == lanip){// 与内网IP相等

+		return true;

+	}

+    var  res1 = [], res2 = [], mask = [];

+    addr1 = ip.split(".");

+    addr2 = lanip.split(".");

+    mask  = lanmask.split(".");

+    for(var i = 0; i < addr1.length; i += 1){

+        res1.push(parseInt(addr1[i]) & parseInt(mask[i]));

+        res2.push(parseInt(addr2[i]) & parseInt(mask[i]));

+    }

+    if(res1.join(".") == res2.join(".")){//在同一个网段

+        return true;

+    }else{//不在同一个网段

+        return false;

+    }

+}

+

+// 有效子网掩码验证.

+     

+function isNetmaskIPValid(ip) {

+	if (ip == 255 || ip == 254 || ip == 252 || ip == 248

+		|| ip == 240 || ip == 224 || ip == 192 || ip == 128 || ip == 0)

+	{

+		return true;

+	}

+	else

+	{

+		return false;

+	}

+}

+    // 有效子网掩码检查.

+     

+function validateNetmask(netmask) {

+	var array = new Array();

+	array = netmask.split(".");

+

+	if (array.length != 4) {

+		return false;

+	}

+

+	array[0] = parseInt(array[0]);

+	array[1] = parseInt(array[1]);

+	array[2] = parseInt(array[2]);

+	array[3] = parseInt(array[3]);

+

+	if (array[3] != 0) {

+		if (array[2] != 255 || array[1] != 255 || array[0] != 255) {

+			return false;

+		} else {

+			if (!isNetmaskIPValid(array[3])) {

+				return false;

+			}

+		}

+	}

+

+	if (array[2] != 0) {

+		if (array[1] != 255 || array[0] != 255) {

+			return false;

+		} else {

+			if (!isNetmaskIPValid(array[2])) {

+				return false;

+			}

+		}

+	}

+

+	if (array[1] != 0) {

+		if (array[0] != 255) {

+			return false;

+		} else{

+			if (!isNetmaskIPValid(array[1])) {

+				return false;

+			}

+		}

+	}

+	if(array[0]!=255) {

+		return false;

+	}

+	if ( "0.0.0.0" == netmask || "255.255.255.255" == netmask) {

+		return false;

+	}

+	return true;

+}

+    

+    // subnetmask_check校验规则

+     

+jQuery.validator.addMethod("subnetmask_check", function (value, element, param) {

+	var result = validateNetmask(value);

+    return this.optional(element) || result;

+});

+    // dns_check校验规则

+     

+jQuery.validator.addMethod("dns_check", function (value, element, param) {

+	var result = validateDns(value);

+    return this.optional(element) || result;

+});

+    // 有效网关检查.

+     

+function validateGateway(wanIp, netmaskIp, gatewayIp) {

+	if(myConcat(wanIp,netmaskIp) == myConcat(netmaskIp, gatewayIp)) {

+		return true;

+	} else {

+		return false;

+	}

+}

+    // IP和子网掩码转换成数组形式并相与,返回相与后的IP.

+     

+function myConcat(ip1,ip2){

+	var result = [];

+	var iplArr = ip1.split(".");

+	var ip2Arr = ip2.split(".");

+	for(var i = 0; i < iplArr.length;i++){

+		result[i] = (iplArr[i] & ip2Arr[i]);

+	}

+	return result.join(".");

+}

+    // gateway_check校验规则

+     

+jQuery.validator.addMethod("gateway_check", function (value, element, param) {

+	var result = validateGateway($('#txtIpAddress').val(), $('#txtSubnetMask').val(), $("#txtDefaultGateway").val());

+    return this.optional(element) || result;

+});

+	

+	return {

+		init: initialize

+	};

+});

+//联网设置模块

+define("network_dial_set","underscore jquery knockout set service".split(" "),

+function(_, $, ko, config, service) {

+

+    //联网设置view model

+	function DialVM() {

+		var dialMode = service.getConnectionMode();

+		var target = this;

+

+		target.selectMode = ko.observable(dialMode.connectionMode);

+        target.enableFlag = ko.observable(true);

+        target.isAllowedRoaming = ko.observable(dialMode.isAllowedRoaming);

+        var originalRoaming = dialMode.isAllowedRoaming;

+

+        target.setAllowedRoaming = setAllowedRoamingFunc;

+		

+		var checkboxFlag = $(".checkboxToggle");

+        target.checkEnable = checkEnableFunc;

+		

+        //修改联网模式

+        target.save = saveFunc;

+		

+		function saveFunc() {

+            showLoading();

+            var connMode = target.selectMode();

+            //当选择自动时,下发原先的勾选状态

+            if (connMode == 'auto_dial') {

+                originalRoaming = target.isAllowedRoaming();

+            } else {

+                target.isAllowedRoaming(originalRoaming);

+            }

+            service.setConnectionMode({

+                connectionMode: connMode,

+                isAllowedRoaming: target.isAllowedRoaming()

+            }, function (result) {

+                if (result.result == "success") {

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+        }

+		

+		function setAllowedRoamingFunc() {

+            if(!$("#roamBtn").hasClass("disable")){

+                var checkbox = $("#isAllowedRoaming:checked");

+                if(checkbox && checkbox.length == 0 ){

+                    target.isAllowedRoaming("on");

+                }else{

+                    target.isAllowedRoaming("off");

+                }

+            }

+        }

+		

+		function checkEnableFunc() {

+            var status = service.getStatusInfo();

+

+            if (status.connectStatus == "ppp_connected" || status.connectStatus == "ppp_connecting") {

+                target.enableFlag(false);

+                disableCheckbox(checkboxFlag);

+            }

+            else {

+                target.enableFlag(true);

+                enableCheckbox(checkboxFlag);

+            }

+        }

+

+	}

+

+    //联网设置初始化.

+	function initialize() {

+		var vm = new DialVM();

+		bindContainer(vm);

+		

+        vm.checkEnable();

+        addInterval( vm.checkEnable, 1000);

+	}

+	

+	function bindContainer(vm){

+		var container = $('#container');

+		ko.cleanNode(container[0]);

+		ko.applyBindings(vm, container[0]);

+	

+	}

+	

+	return {

+		init: initialize

+	};

+});

+// APN Setting 模块

+define("network_apn_set","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    //获取鉴权方式

+     

+    function getAuthModes() {

+        return _.map(config.APN_AUTH_MODES, function (item) {

+            return new Option(item.name, item.value);

+        });

+    }

+

+    function getApnPdpTypes() {

+        var pdpTypesArray = [new Option('IPv4', 'IP')];

+        if (config.IPV6_SUPPORT) {

+            pdpTypesArray.push(new Option('IPv6', 'IPv6'));

+            if (config.IPV4V6_SUPPORT) {

+                pdpTypesArray.push(new Option('IPv4v6', 'IPv4v6'));

+            }

+            if (config.IPV4_AND_V6_SUPPORT) {

+                pdpTypesArray.push(new Option('IPv4 & IPv6', 'IPv4v6'));

+            }

+        }

+        return pdpTypesArray;

+    }

+

+    //获取apn相关信息

+     

+    function getApnSet() {

+        var apnInfo = service.getApnSettings();

+        apnInfo.ipv6ApnConfigs = getApnConfigs(apnInfo.ipv6APNs, true);

+        apnInfo.apnConfigs = getApnConfigs(apnInfo.APNs, false);

+        apnInfo.autoApnConfigs = getAutoApnsConfig(apnInfo.autoApns, apnInfo.autoApnsV6);

+        return apnInfo;

+    }

+    var apnConfigs = {};

+    var ipv6ApnConfigs = {};

+    var autoApnConfigs = {};

+

+    //解析自动apn信息

+     

+    function getAutoApnsConfig(autoApnV4, autoApnV6) {

+        var autoApnsV4 = [];

+        var autoApnsV6 = [];

+

+        if (autoApnV4 && autoApnV4.length > 5) {

+            var apnArr = autoApnV4.split("||");

+            for (var ki = 0; ki < apnArr.length; ki++) {

+                if (apnArr[ki] != "") {

+                    var apnItem = parseApnItem(apnArr[ki], false);

+                    autoApnsV4.push(apnItem);

+                }

+            }

+        }

+        if (autoApnV6 && autoApnV6.length > 5) {

+            var apnArr = autoApnV6.split("||");

+            for (var ki = 0; ki < apnArr.length; ki++) {

+                if (apnArr[ki] != "") {

+                    var apnItem = parseApnItem(apnArr[ki], false);

+                    autoApnsV6.push(apnItem);

+                }

+            }

+        }

+        return dealAutoApnsV4V6(autoApnsV4, autoApnsV6);

+    }

+    //解析apn信息

+     

+    function getApnConfigs(apnsStr, isIpv6) {

+        var apnCfgs = [];

+        var theApnConfigs = {};

+        if (apnsStr && apnsStr.length > 10) {

+            var apnArr = apnsStr.split("||");

+            for (var ki = 0; ki < apnArr.length; ki++) {

+                if (apnArr[ki] != "") {

+                    var apnItem = parseApnItem(apnArr[ki], isIpv6);

+                    apnCfgs.push(apnItem);

+                    theApnConfigs[apnItem.profileName] = apnItem;

+                }

+            }

+        }

+        if (isIpv6 == false) {

+            apnConfigs = theApnConfigs;

+        } else {

+            ipv6ApnConfigs = theApnConfigs;

+        }

+        return apnCfgs;

+    }

+

+	//解析单条apn信息

+     

+    function parseApnItem(apnStr, isIpv6) {

+        var apnItem = {};

+        var items = apnStr.split("($)");

+        for (var ki = 0; ki < items.length; ki++) {

+            apnItem.profileName = items[0];

+            apnItem.pdpType = items[7];

+            if (isIpv6 == false) {	

+                apnItem.dnsMode = items[10];

+                apnItem.dns1 = items[11];

+                apnItem.dns2 = items[12];

+                apnItem.wanApn = items[1];

+                apnItem.authMode = items[4].toLowerCase();

+                apnItem.username = items[5];

+                apnItem.password = items[6];

+            } else {		

+                apnItem.dnsModeV6 = items[10];

+                apnItem.dns1V6 = items[11];

+                apnItem.dns2V6 = items[12];

+                apnItem.wanApnV6 = items[1];

+                apnItem.authModeV6 = items[4].toLowerCase();

+                apnItem.usernameV6 = items[5];

+                apnItem.passwordV6 = items[6];

+            }

+        }

+        return apnItem;

+    }

+    //合并V4\V6自动apn信息

+     

+    function dealAutoApnsV4V6(v4, v6) {

+        autoApnConfigs = {};

+        var autoApns = [];

+        for (var ki = 0; ki < v4.length; ki++) {

+            var apnElem = v4[ki];

+            var itemsV6 = v6[ki];

+            if (itemsV6 && (itemsV6.pdpType == 'IPv6' || itemsV6.pdpType == 'IPv4v6')) {

+                apnElem.usernameV6 = itemsV6.username;

+                apnElem.passwordV6 = itemsV6.password;

+                apnElem.dns1V6 = itemsV6.dns1;

+                apnElem.dns2V6 = itemsV6.dns2;

+                apnElem.wanApnV6 = itemsV6.wanApn;

+                apnElem.authModeV6 = itemsV6.authMode;

+                apnElem.dnsModeV6 = itemsV6.dnsMode;

+            }

+            autoApns.push(apnElem);

+            autoApnConfigs[apnElem.profileName] = apnElem;

+        }

+        return autoApns;

+    }

+

+    function getProfileOptions(apns) {

+        return _.map(apns, function (item) {

+            return new Option(item.profileName, item.profileName);

+        });

+    }

+

+    //APNViewModel

+     

+    function APNViewModel() {

+        var target = this;

+        var apnSettings = getApnSet();

+        if (apnSettings.apnNumPreset) {

+            config.maxApnNumber = apnSettings.apnNumPreset;

+        }

+

+        target.defApn = ko.observable(apnSettings.profileName); //当前默认APN

+        target.apnMode = ko.observable(apnSettings.apnMode);

+        target.autoProfiles = ko.observableArray(getProfileOptions(apnSettings.autoApnConfigs));

+        target.profiles = ko.observableArray(getProfileOptions(apnSettings.apnConfigs));

+        target.wanDial = ko.observable(apnSettings.wanDial);

+		

+        target.showApnDns = ko.observable(config.SHOW_APN_DNS);

+        target.index = ko.observable(apnSettings.currIndex);

+        target.supportIPv6 = ko.observable(config.IPV6_SUPPORT);

+        target.supportIpv4AndIpv6 = ko.observable(config.IPV4_AND_V6_SUPPORT);

+

+        target.apn = ko.observable(apnSettings.wanApn);

+        target.dnsMode = ko.observable(apnSettings.dnsMode == 'manual' ? 'manual' : 'auto');

+        target.dns1 = ko.observable(apnSettings.dns1);

+        target.dns2 = ko.observable(apnSettings.dns2);

+        target.authModes = ko.observableArray(getAuthModes());

+        target.username = ko.observable(apnSettings.username);

+        target.password = ko.observable(apnSettings.password);

+		

+        target.pdpTypes = ko.observableArray(getApnPdpTypes());

+        target.selectedPdpType = ko.observable(apnSettings.pdpType);

+        target.selectedPdpTypeTmp = ko.observable(apnSettings.pdpType); //the PdpType select's value before chang

+        target.profileName = ko.observable(apnSettings.profileName); //当前编辑框中的

+        target.selectedProfile = ko.observable(apnSettings.profileName); //当前下拉框选择的APN

+

+        target.showPassword = ko.observable(false);

+

+        target.apnV6 = ko.observable(apnSettings.wanApnV6);

+        target.dnsModeV6 = ko.observable(apnSettings.dnsModeV6 == 'manual' ? 'manual' : 'auto');

+        target.dns1V6 = ko.observable(apnSettings.dns1V6);

+        target.dns2V6 = ko.observable(apnSettings.dns2V6);

+        target.authModesV6 = ko.observableArray(getAuthModes());

+        target.usernameV6 = ko.observable(apnSettings.usernameV6);

+        target.passwordV6 = ko.observable(apnSettings.passwordV6);

+        target.pdpTypeNote = ko.observable(true);

+        if (apnSettings.autoApnConfigs && apnSettings.autoApnConfigs.length > 0) {

+            target.selectedAutoProfile = ko.observable(apnSettings.autoApnConfigs[0].profileName);

+        } else {

+            target.selectedAutoProfile = ko.observable();

+        }

+

+        if (config.EMPTY_APN_SUPPORT == false) {

+            $("#apn_ipv4_apn").addClass("required");

+            $("#apn_ipv6_apn").addClass("required");

+        } else {

+            $("#apn_ipv4_apn").removeClass("required");

+            $("#apn_ipv6_apn").removeClass("required");

+        }

+		

+        target.disableProfile = ko.observable(false); //表示处于新增页面

+        target.addApnHide = ko.observable(true);

+        target.defaultCfg = ko.observable(true); //当前选中的是默认APN

+        target.predeterminedCfg = ko.observable(true); //当前选中的是预置的APN

+		

+        target.selectedAuthentication = ko.observable(apnSettings.authMode);

+        target.selectedAuthenticationV6 = ko.observable(apnSettings.authModeV6);

+

+

+        target.transApnV6 = ko.observable('apn');

+        target.transDnsModeV6 = ko.observable('apn_dns_mode');

+        target.transDns1V6 = ko.observable('apn_dns1');

+        target.transDns2V6 = ko.observable('apn_dns2');

+        target.transAuthV6 = ko.observable('apn_authentication');

+        target.transUserNameV6 = ko.observable('apn_user_name');

+        target.transPasswordV6 = ko.observable('apn_password');

+		

+        target.transApn = ko.observable(config.IPV4_AND_V6_SUPPORT ? 'apn_ipv4_apn' : 'apn');

+        target.transDnsMode = ko.observable(config.IPV4_AND_V6_SUPPORT ? 'apn_dns_mode_ipv4' : 'apn_dns_mode');

+        target.transDns1 = ko.observable(config.IPV4_AND_V6_SUPPORT ? 'apn_dns1_ipv4' : 'apn_dns1');

+        target.transDns2 = ko.observable(config.IPV4_AND_V6_SUPPORT ? 'apn_dns2_ipv4' : 'apn_dns2');

+        target.transAuth = ko.observable(config.IPV4_AND_V6_SUPPORT ? 'apn_authentication_ipv4' : 'apn_authentication');

+        target.transUserName = ko.observable(config.IPV4_AND_V6_SUPPORT ? 'apn_user_name_ipv4' : 'apn_user_name');

+        target.transPassword = ko.observable(config.IPV4_AND_V6_SUPPORT ? 'apn_password_ipv4' : 'apn_password');

+

+        target.setDefaultVisible = ko.observable(!isConnectedNetWork());

+

+        target.tmp1 = ko.computed(function () {

+             if (target.selectedPdpType() == "IPv6") {

+                target.transApnV6('apn');

+                target.transDnsModeV6('apn_dns_mode');

+                target.transDns1V6('apn_dns1');

+                target.transDns2V6('apn_dns2');

+                target.transAuthV6('apn_authentication');

+                target.transUserNameV6('apn_user_name');

+                target.transPasswordV6('apn_password');

+            } else if (config.IPV4_AND_V6_SUPPORT && target.selectedPdpType() == 'IPv4v6') {

+                target.transApn('apn_ipv4_apn');

+                target.transDnsMode('apn_dns_mode_ipv4');

+                target.transDns1('apn_dns1_ipv4');

+                target.transDns2('apn_dns2_ipv4');

+                target.transAuth('apn_authentication_ipv4');

+                target.transUserName('apn_user_name_ipv4');

+                target.transPassword('apn_password_ipv4');

+

+                target.transApnV6('apn_ipv6_apn');

+                target.transDnsModeV6('apn_dns_mode_ipv6');

+                target.transDns1V6('apn_dns1_ipv6');

+                target.transDns2V6('apn_dns2_ipv6');

+                target.transAuthV6('apn_authentication_ipv6');

+                target.transUserNameV6('apn_user_name_ipv6');

+                target.transPasswordV6('apn_password_ipv6');

+            } else if (target.selectedPdpType() == "IP" || target.selectedPdpType() == "IPv4") {

+                target.transApn('apn');

+                target.transDnsMode('apn_dns_mode');

+                target.transDns1('apn_dns1');

+                target.transDns2('apn_dns2');

+                target.transAuth('apn_authentication');

+                target.transUserName('apn_user_name');

+                target.transPassword('apn_password');

+            } else { //config.IPV4V6_SUPPORT && target.selectedPdpType() == 'IPv4v6'

+                target.transApn('apn');

+                target.transDnsMode('apn_dns_mode');

+                target.transDns1('apn_dns1');

+                target.transDns2('apn_dns2');

+                target.transAuth('apn_authentication');

+                target.transUserName('apn_user_name');

+                target.transPassword('apn_password');

+            }

+            $("#apn_setting_form").translate();

+        });

+

+        target.autoApnChecked = ko.computed(function () {

+            return target.apnMode() == "auto";

+        });

+		

+        target.hasCapacity = ko.computed(function () {

+            if (target.profiles().length < config.maxApnNumber) {

+                return true;

+            } else {

+                return false;

+            }

+        });

+

+        target.showDnsV6 = ko.computed(function () {

+            return target.dnsModeV6() == "manual";

+        });

+		

+        target.showDns = ko.computed(function () {

+            return target.dnsMode() == "manual";

+        });

+

+

+        checkDefaultProfileStatus();

+        target.checkInputDisable = ko.computed(function () {

+            if (target.apnMode() != "auto"  && (target.predeterminedCfg() == false && target.defaultCfg() == true) && !isConnectedNetWork()) {

+                return false;

+            }

+            if (((target.apnMode() != "auto" && (target.predeterminedCfg() || target.defaultCfg()) && !target.disableProfile())) || target.apnMode() == "auto") {

+                return true;

+            }

+            if ((!target.disableProfile() || !(target.predeterminedCfg() || target.defaultCfg())) && target.apnMode() != "auto") {

+                return false;

+            }

+            return false;

+        });

+

+        var data = service.getDeviceInfo();

+        target.pdpTypeChangeAlert = pdpTypeChangeAlertFunc;

+		

+

+        target.showAutoApnDetail = ko.computed(function () {

+            if (target.apnMode() != "auto") {

+                return true;

+            } else {

+                return target.autoProfiles().length > 0;

+            }

+        });

+		//密码显示事件

+        target.showPasswordHandler = function () {

+            var checkbox = $("#showPassword:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showPassword(true);

+            } else {

+                target.showPassword(false);

+            }

+        };

+		//auto apn profile change 事件处理

+         

+        target.autoProfileChangeHandler = autoProfileChangeHandlerFunc;

+		

+		

+        //profile change 事件处理

+         

+        target.profileChangeHandler = profileChangeHandlerFunc;

+		

+        

+        //切换profile时重置下面的显示项

+        target.setUIData = setUIDataFunc;

+		

+

+        //设置默认apn状态

+         

+        function checkDefaultProfileStatus() {

+            var index = getApnIndex();

+            //默认apn不允许编辑

+            if (target.apnMode() != "auto") { //当前选中与实际不一致的话

+                if (target.selectedProfile() != target.defApn()) {

+                    target.defaultCfg(false);

+                } else {

+                    target.defaultCfg(true); //默认APN

+                }

+            } else {

+                if (target.selectedAutoProfile() != target.defApn()) {

+                    target.defaultCfg(false);

+                } else {

+                    target.defaultCfg(true); //默认APN

+                }

+            }

+

+            if (index >= config.defaultApnSize) {

+                target.predeterminedCfg(false);

+            } else {

+                target.predeterminedCfg(true); //预置APN

+            }

+        }

+

+

+        //设置为默认apn

+         

+        target.setDefaultAct = setDefaultActFunc;

+		

+

+		

+        //APN mode change 事件处理

+         

+        target.apnModeChangeHandler = apnModeChangeHandlerFunc;

+		

+		

+        function doSetDefaultAct() {

+            var index = 0;

+            if (target.apnMode() != 'auto') {

+                index = getApnIndex();

+                target.selectedProfile($("#profile").val());

+            } else {

+                index = getAutoApnIndex();

+                target.selectedAutoProfile($("#autoProfile").val());

+            }

+            var selectedProfileDetail = target.getSelectedManualProfile();

+            service.setDefaultApn({

+                index: index,

+                apnMode: target.apnMode(),

+                pdpType: selectedProfileDetail.pdpType,

+

+                profileName: selectedProfileDetail.profileName,

+                wanApn: selectedProfileDetail.wanApn,

+                authMode: selectedProfileDetail.authMode,

+                username: selectedProfileDetail.username,

+                password: selectedProfileDetail.password,

+                dnsMode: config.SHOW_APN_DNS ? selectedProfileDetail.dnsMode : 'auto',

+                dns1: config.SHOW_APN_DNS ? selectedProfileDetail.dns1 : '',

+                dns2: config.SHOW_APN_DNS ? selectedProfileDetail.dns2 : ''

+            }, function (data) {

+                if (data.result) {

+                    //showLoading("apn_alert_restart");

+                    //restartDevice(service);

+                    addTimeout(function () {

+                        initialize(true);

+                        target.apnModeChangeHandler();

+                        successOverlay();

+                    }, 500);

+                } else {

+                    errorOverlay();

+                }

+            }, function (data) {

+                errorOverlay();

+            });

+        }

+

+        target.getSelectedManualProfile = getSelectedManualProfileFunc;

+		

+

+        //获取自动apn索引

+         

+        function getAutoApnIndex() {

+            var configs = $("#autoProfile option");

+            for (var ki = 0; ki < configs.length; ki++) {

+                if (configs[ki].value == target.selectedAutoProfile()) {

+                    return ki;

+                }

+            }

+            return configs.length - 1;

+        }

+		

+		//获取apn索引

+         

+        function getApnIndex() {

+            var configs = $("#profile option");

+            if (configs.length == 0) {

+                configs = target.profiles();

+            }

+            var ki = 0;

+            for (; ki < configs.length; ki++) {

+                if (configs[ki].value == target.selectedProfile()) {

+                    break;

+                }

+            }

+            return ki;

+        }

+

+        //保存APN设置信息

+         

+        target.saveAct = saveActFunc;

+		

+		//编辑APN信息

+         

+        function editApnSetting(preAct) { //默认设置按钮触发为TRUE

+            showLoading();

+            var apnIndex = getApnIndex();

+            var sameInfo = false;

+            if (config.IPV4V6_SUPPORT && target.selectedPdpType() == 'IPv4v6') {

+                sameInfo = true;

+            }

+            var needDoDefault = false;

+            if (preAct || (target.predeterminedCfg() || target.defaultCfg())) {

+                needDoDefault = true;

+            }

+            service.addOrEditApn({

+                profileName: target.profileName(),

+                pdpType: target.selectedPdpType(),

+                index: apnIndex,

+

+                wanApn: target.apn(),

+                authMode: target.selectedAuthentication(),

+                username: target.username(),

+                password: target.password(),

+                dnsMode: config.SHOW_APN_DNS ? target.dnsMode() : 'auto',

+                dns1: config.SHOW_APN_DNS ? target.dns1() : '',

+                dns2: config.SHOW_APN_DNS ? target.dns2() : '',

+

+                wanApnV6: sameInfo ? target.apn() : target.apnV6(),

+                authModeV6: sameInfo ? target.selectedAuthentication() : target.selectedAuthenticationV6(),

+                usernameV6: sameInfo ? target.username() : target.usernameV6(),

+                passwordV6: sameInfo ? target.password() : target.passwordV6(),

+                dnsModeV6: config.SHOW_APN_DNS ? (sameInfo ? target.dnsMode() : target.dnsModeV6()) : 'auto',

+                dns1V6: config.SHOW_APN_DNS ? (sameInfo ? target.dns1() : target.dns1V6()) : '',

+                dns2V6: config.SHOW_APN_DNS ? (sameInfo ? target.dns2() : target.dns2V6()) : ''

+            }, function (data) {

+                if (data.result) {

+                    apnSettings = getApnSet();

+                    if (target.profileName() != target.selectedProfile()) {

+                        var newProfileName = target.profileName();

+                        target.profiles(getProfileOptions(apnSettings.apnConfigs));

+                        $('#profile').val(newProfileName).trigger('change');

+                    }

+                    if (needDoDefault == false) {

+                        successOverlay();

+                    } else {

+                        doSetDefaultAct();

+                    }

+                } else {

+                    errorOverlay();

+                }

+            }, function (data) {

+                errorOverlay();

+            });

+        }

+		

+        //新增APN信息

+         

+        function addNewApnSetting() {

+            showLoading("waiting");

+            var optionLen = $("option", "#profile").length;

+            if (optionLen < config.defaultApnSize) {

+                errorOverlay();

+                return;

+            }

+            // 支持IPv4v6,并且选择IPv4v6时,IPv4 与 IPv6下发相同的信息

+            // 支持IPv4 & v6,并且选择IPv4v6时,IPv4 与 IPv6下发各自的信息

+            var sameInfo = false;

+            if (config.IPV4V6_SUPPORT && target.selectedPdpType() == 'IPv4v6') {

+                sameInfo = true;

+            }

+

+            service.addOrEditApn({

+                profileName: target.profileName(),

+                pdpType: target.selectedPdpType(),

+                index: optionLen,

+

+                wanApn: target.apn(),

+                authMode: target.selectedAuthentication(),

+                username: target.username(),

+                password: target.password(),

+                dnsMode: config.SHOW_APN_DNS ? target.dnsMode() : 'auto',

+                dns1: config.SHOW_APN_DNS ? target.dns1() : '',

+                dns2: config.SHOW_APN_DNS ? target.dns2() : '',

+

+                wanApnV6: sameInfo ? target.apn() : target.apnV6(),

+                authModeV6: sameInfo ? target.selectedAuthentication() : target.selectedAuthenticationV6(),

+                usernameV6: sameInfo ? target.username() : target.usernameV6(),

+                passwordV6: sameInfo ? target.password() : target.passwordV6(),

+                dnsModeV6: config.SHOW_APN_DNS ? (sameInfo ? target.dnsMode() : target.dnsModeV6()) : 'auto',

+                dns1V6: config.SHOW_APN_DNS ? (sameInfo ? target.dns1() : target.dns1V6()) : '',

+                dns2V6: config.SHOW_APN_DNS ? (sameInfo ? target.dns2() : target.dns2V6()) : ''

+            }, function (data) {

+                if (data.result) {

+                    apnSettings = getApnSet();

+                    if (target.profileName() != target.selectedProfile()) {

+                        var newProfileName = target.profileName();

+                        target.profiles(getProfileOptions(apnSettings.apnConfigs));

+                        $('#profile').val(newProfileName).trigger('change');

+                    }

+                    doSetDefaultAct();

+                } else {

+                    errorOverlay();

+                }

+            }, function (data) {

+                errorOverlay();

+            });

+        }

+

+        

+

+        var tempApn = {};

+		//删除APN

+         

+        target.deleteAct = deleteActFunc;

+		

+		//取消新增APN

+         

+        target.cancelAddAct = cancelAddActFunc;

+		

+        //进入新增APN页面

+         

+        target.addAct = addActFunc;

+		//进入新增APN页面

+		function addActFunc() {

+            clearValidateMsg('#apn_setting_form');

+            target.pdpTypeNote(true);

+            target.disableProfile(true);

+            target.addApnHide(true);

+            tempApn = {

+                profileName: target.profileName(),

+                selectedPdpType: target.selectedPdpType(),

+

+                wanApnV6: target.apnV6(),

+                dnsModeV6: config.SHOW_APN_DNS ? target.dnsModeV6() : 'auto',

+                dns1V6: config.SHOW_APN_DNS ? target.dns1V6() : '',

+                dns2V6: config.SHOW_APN_DNS ? target.dns2V6() : '',

+                authModeV6: target.selectedAuthenticationV6(),

+                usernameV6: target.usernameV6(),

+                passwordV6: target.passwordV6(),

+				

+                wanApn: target.apn(),

+                dnsMode: config.SHOW_APN_DNS ? target.dnsMode() : 'auto',

+                dns1: config.SHOW_APN_DNS ? target.dns1() : '',

+                dns2: config.SHOW_APN_DNS ? target.dns2() : '',

+                authMode: target.selectedAuthentication(),

+                username: target.username(),

+                password: target.password(),

+

+            };

+            target.profileName("");

+            target.selectedPdpType("IP");

+            target.selectedPdpTypeTmp("IP");

+

+            target.apnV6("");

+            target.dnsModeV6("auto");

+            target.dns1V6("");

+            target.dns2V6("");

+            target.selectedAuthenticationV6("none");

+            target.usernameV6("");

+            target.passwordV6("");

+			

+            target.apn("");

+            target.dnsMode("auto");

+            target.dns1("");

+            target.dns2("");

+            target.selectedAuthentication("none");

+            target.username("");

+            target.password("");

+

+        }

+		

+		//取消新增APN

+		function cancelAddActFunc() {

+            clearValidateMsg('#apn_setting_form');

+            target.pdpTypeNote(false);

+            target.disableProfile(false);

+            target.addApnHide(false);

+            target.profileName(tempApn.profileName);

+            target.selectedPdpType(tempApn.selectedPdpType);

+            target.selectedPdpTypeTmp(tempApn.selectedPdpType);

+

+            target.apnV6(tempApn.wanApnV6);

+            target.dnsModeV6(tempApn.dnsModeV6);

+            target.dns1V6(tempApn.dns1V6);

+            target.dns2V6(tempApn.dns2V6);

+            target.selectedAuthenticationV6(tempApn.authModeV6);

+            target.usernameV6(tempApn.usernameV6);

+            target.passwordV6(tempApn.passwordV6);

+			

+            target.apn(tempApn.wanApn);

+            target.dnsMode(tempApn.dnsMode);

+            target.dns1(tempApn.dns1);

+            target.dns2(tempApn.dns2);

+            target.selectedAuthentication(tempApn.authMode);

+            target.username(tempApn.username);

+            target.password(tempApn.password);

+

+        }

+		

+		//删除APN

+		function deleteActFunc() {

+            if (!target.selectedProfile()) {

+                showAlert("apn_no_select_alert");

+                return false;

+            }

+            if (target.predeterminedCfg()) { //预置的apn不允许删除

+                errorOverlay("apn_delete_cant_delete_default");

+                return false;

+            }

+            if (getApnSet().profileName == target.profileName()) {

+                errorOverlay("apn_cant_delete_current");

+                return false;

+            }

+

+            showConfirm("apn_delete_confirm", function () {

+                showLoading('deleting');

+                service.deleteApn({

+                    index: getApnIndex()

+                }, function (data) {

+                    if (data.result) {

+                        target.profiles(getProfileOptions(getApnSet().apnConfigs));

+                        target.selectedProfile(target.defApn());

+                        target.profileChangeHandler();

+                        successOverlay();

+                    } else {

+                        errorOverlay();

+                    }

+                }, function (data) {

+                    errorOverlay();

+                });

+            });

+        }

+		

+		//保存APN设置信息

+		function saveActFunc() {

+            if (!$('#apn_setting_form').valid()) {

+                return false;

+            }

+            if (!target.selectedProfile() && !target.disableProfile()) { //不是增加时的设置需要判断是否选择了Profile

+                showAlert("apn_no_select_alert");

+                return false;

+            }

+            var exist = false;

+            $.each(target.profiles(), function (i, e) {

+                if (e.value == target.profileName()) {

+                    exist = true;

+                }

+            });

+

+            if (target.disableProfile() == false) {

+                if (exist && target.selectedProfile() != target.profileName()) {

+                    showInfo("apn_save_profile_exist");

+                    return false;

+                }

+                if (target.predeterminedCfg()) { //预置的APN不可以修改

+                    errorOverlay();

+                    return false;

+                }

+                if (target.predeterminedCfg() || target.defaultCfg()) {

+                    //showConfirm("apn_alert", function () {

+                    editApnSetting(false);

+                    //});

+                } else {

+                    editApnSetting(false);

+                }

+            } else {

+				

+                if ($("#profile option").length >= config.maxApnNumber) {

+                    showInfo({

+                        msg: "apn_profile_full",

+                        params: [config.maxApnNumber]

+                    });

+                    return false;

+                }

+                if (exist) {

+                    showInfo("apn_save_profile_exist");

+                    return false;

+                }

+                var info = service.getStatusInfo();

+                if (info.connectStatus != "ppp_connected") {

+                    //showConfirm("apn_alert", function () {

+                    addNewApnSetting();

+                    //});

+                    

+                } else {

+					showConfirm("apn_diconneted_network_confirm", function () {

+                        showLoading('disconnecting');

+                        service.disconnect({}, function (data) {

+                            if (data.result) {

+                                config.connect_flag = true;

+                                addNewApnSetting();

+                            } else {

+                                errorOverlay();

+                            }

+                        });

+                    });

+                }

+            }

+        }

+		

+		function getSelectedManualProfileFunc() {

+            var cfg = {};

+            var profileVal = $("#profile").val();

+            if (typeof target.selectedProfile() == 'undefined') {

+                target.selectedProfile(profileVal);

+            }

+            var cfgV4 = apnConfigs[profileVal];

+            var cfgV6 = ipv6ApnConfigs[profileVal];

+            if (cfgV4 && !cfgV6) {

+                $.extend(cfg, cfgV4);

+            } else if (cfgV4 && cfgV6) {

+                if (!!cfgV4.pdpType) {

+                    $.extend(cfg, cfgV6);

+                    $.extend(cfg, cfgV4);

+                } else {

+                    $.extend(cfg, cfgV4);

+                    $.extend(cfg, cfgV6);

+                }

+            }

+            return cfg;

+        }

+		

+		//APN mode change 事件处理

+		function apnModeChangeHandlerFunc(data, event) {

+            if (target.apnMode() != 'auto') {

+                target.profileChangeHandler();

+            } else {

+                if (target.showAutoApnDetail()) {

+                    target.autoProfileChangeHandler();

+                }

+            }

+            return true;

+        }

+		

+		//设置为默认apn

+		function setDefaultActFunc() {

+            if (!target.selectedProfile()) {

+                showAlert("apn_no_select_alert");

+                return false;

+            }

+            var connectStatus = service.getConnectionInfo().connectStatus;

+             if (connectStatus == "ppp_connecting") {

+                showAlert({

+                    msg: "apn_cant_modify_status",

+                    params: [$.i18n.prop("connecting").toLowerCase()]

+                });

+                return false;

+            } else if (connectStatus == "ppp_disconnecting") {

+                showAlert({

+                    msg: "apn_cant_modify_status",

+                    params: [$.i18n.prop("disconnecting").toLowerCase()]

+                });

+                return false;

+            } else if (connectStatus == "ppp_connected") {

+                showAlert({

+                    msg: "apn_cant_modify_status",

+                    params: [$.i18n.prop("connected").toLowerCase()]

+                });

+                return false;

+            }

+            if (target.apnMode() == 'auto' || target.predeterminedCfg()) {

+                //showConfirm("apn_alert", function () {

+                showLoading("waiting");

+                doSetDefaultAct();

+                //});

+            } else {

+                if ($('#apn_setting_form').valid() == false) {

+                    $(".error:first", "#apn_setting_form").focus();                    

+                } else {

+					var exist = false;

+                    $.each(target.profiles(), function (i, e) {

+                        if (e.value == target.profileName()) {

+                            exist = true;

+                        }

+                    });

+                    if (exist && target.selectedProfile() != target.profileName()) {

+                        showInfo("apn_save_profile_exist");

+                        return false;

+                    }

+                    //showLoading("waiting");

+                    //showConfirm("apn_alert", function () {

+                    editApnSetting(true);

+                    //});

+                }

+            }

+        }

+		

+		//切换profile时重置下面的显示项

+		function setUIDataFunc(data) {

+            clearValidateMsg('#apn_setting_form');

+            if (!data) {

+                return;

+            }

+            target.selectedPdpType(data.pdpType || 'IP');

+            target.selectedPdpTypeTmp(data.pdpType || 'IP');

+            target.profileName(data.profileName);

+

+            target.apn(data.wanApn);

+            target.dnsMode(data.dnsMode != 'manual' ? 'auto' : 'manual');

+            target.dns1(data.dns1);

+            target.dns2(data.dns2);

+            target.username(data.username);

+            target.password(data.password);

+            target.selectedAuthentication(data.authMode || 'none');

+

+            target.apnV6(data.wanApnV6);

+            target.dnsModeV6(data.dnsModeV6 != 'manual' ? 'auto' : 'manual');

+            target.dns1V6(data.dns1V6);

+            target.dns2V6(data.dns2V6);

+            target.usernameV6(data.usernameV6);

+            target.passwordV6(data.passwordV6);

+            target.selectedAuthenticationV6(data.authModeV6 || 'none');

+        }

+		

+		//profile change 事件处理

+		function profileChangeHandlerFunc(data, event) {

+            target.pdpTypeNote(true);

+            if (target.apnMode() != 'manual') {

+                return true;

+            }

+            var cfg = target.getSelectedManualProfile();

+            target.setUIData(cfg);

+            checkDefaultProfileStatus();

+            return true;

+        }

+		

+		//auto apn profile change 事件处理

+		function autoProfileChangeHandlerFunc(data, event) {

+            if (target.apnMode() != 'auto') {

+                return true;

+            }

+            var cfg = autoApnConfigs[target.selectedAutoProfile()];

+            target.setUIData(cfg);

+            checkDefaultProfileStatus();

+            return true;

+        }

+		

+		function pdpTypeChangeAlertFunc() {

+            if (target.pdpTypeNote()) {

+                showAlert({

+                    msg: "apn_pdptype_change_note",

+                    params: [data.lanDomain, data.ipAddress]

+                });

+            }

+            if (target.apnMode() != "auto" && !target.disableProfile()) { //如果是手动非ADD状态,切换PDP类型时,不改变界面显示的各项值

+                if ((config.IPV4_AND_V6_SUPPORT && target.selectedPdpTypeTmp() != 'IPv4v6' && target.selectedPdpType() != 'IPv4v6') || !config.IPV4_AND_V6_SUPPORT) { //

+                    if (target.selectedPdpTypeTmp() == 'IPv6') { //V6 -> V4 / V4V6

+                        target.apn(target.apnV6());

+                        target.dnsMode(target.dnsModeV6());

+                        target.dns1(target.dns1V6());

+                        target.dns2(target.dns2V6());

+                        target.username(target.usernameV6());

+                        target.password(target.passwordV6());

+                        target.selectedAuthentication(target.selectedAuthenticationV6());

+                    } else if (target.selectedPdpType() == 'IPv6') { //V4 / V4V6 -> V6

+                        target.apnV6(target.apn());

+                        target.dnsModeV6(target.dnsMode());

+                        target.dns1V6(target.dns1());

+                        target.dns2V6(target.dns2());

+                        target.usernameV6(target.username());

+                        target.passwordV6(target.password());

+                        target.selectedAuthenticationV6(target.selectedAuthentication());

+                    }

+                }

+            }

+            target.selectedPdpTypeTmp(target.selectedPdpType());

+        }

+       

+

+    }

+

+    //是否已联网

+     

+    function isConnectedNetWork() {

+        var info = service.getConnectionInfo();

+        return info.connectStatus == "ppp_connected";

+    }

+

+    function initVar() {

+        apnConfigs = {};

+        ipv6ApnConfigs = {};

+        autoApnConfigs = {};

+    }

+	function bindContainer(vm){

+		var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(vm, container[0]);

+	}

+    //初始化ViewModel

+     

+    function initialize(formInit) {

+        initVar();

+        

+        var vm = new APNViewModel();

+		bindContainer(vm);

+

+        if (!formInit) {

+            addInterval(function () {

+                vm.setDefaultVisible(!isConnectedNetWork());

+            }, 1000);

+        }

+        $('#apn_setting_form').validate({

+            submitHandler: function () {

+                vm.saveAct();

+            },

+            rules: {

+                profile_name: 'apn_profile_name_check',

+                apn_ipv4_apn: 'apn_check',

+                apn_dns1_ipv4: "ipv4",

+                apn_dns2_ipv4: "ipv4",

+                apn_ipv6_apn: 'apn_check',

+                apn_dns1_ipv6: "ipv6",

+                apn_dns2_ipv6: "ipv6",

+                apn_user_name_ipv4: 'ppp_username_check',

+                apn_secretcode_ipv4: 'ppp_secretcode_check',

+                apn_user_name_ipv6: 'ppp_username_check',

+                apn_secretcode_ipv6: 'ppp_secretcode_check'

+            }

+        });

+    }

+

+    return {

+        init: initialize

+    };

+});
\ No newline at end of file
diff --git a/ap/app/zte_webui/js/set.js b/ap/app/zte_webui/js/set.js
new file mode 100755
index 0000000..e284074
--- /dev/null
+++ b/ap/app/zte_webui/js/set.js
@@ -0,0 +1,958 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Hostless Modem', //title配置, 具体参考各设备下的配置

+        ALREADY_NOTICE: false, //是否已经提醒,有在线升级信息

+        ALREADY_OTA_NOTICE: false, //是否OTA升级提醒过

+        dbMsgs: [], //数据库中全部的短消息

+        listMsgs: [], //经解析关联后的所有短消息

+        currentChatObject: null, //当前聊天对象的手机号

+        smsMaxId: 0, //短消息最大编号

+        phonebook: [], //电话本记录

+        smsIsReady: false, //缓存短信初始化状态

+        portForwardMax: 10, //端口转发最大规则数

+        urlFilterMax: 10, //URL filter最大规则数

+        defaultApnSize: 1, //出厂设置默认APN的个数

+        maxApnNumber: 10, //最大APN个数

+        RJ45_SUPPORT: false, //是否支持rj45

+        TSW_SUPPORT: false, // 是否支持定时休眠唤醒

+        WIFI_SLEEP_SUPPORT: true, // 是否支持wifi休眠

+        HAS_BATTERY: true, //是否有电池

+        FAST_BOOT_SUPPORT: true, //是否支持快速开机

+        TURN_OFF_SUPPORT: true, //是否支持关机

+        PRODUCT_TYPE: 'UFI', // 产品类型UFI、CPE

+        IS_TEST: false, //配置是否是模拟数据

+        NATIVE_UPDATE_FILE_SIZE: 64, //支持的本地升级文件大小上限,单位为M

+        DDNS_SUPPORT: false, //DDNS

+        MAX_LOGIN_COUNT: 5, //最大登录次数,密码输入错误次数到了以后会账户冻结一定时间

+        LOGIN_SECURITY_SUPPORT: true, //是否支持登录安全

+        LOGIN_THEN_CHECK_PIN: true, //是否先登录后验证PIN,PUK

+        GUEST_HASH: ['#httpshare_guest'],

+        DEVICE: 'ext', //各个型号机配置文件路径

+        connect_flag: false,

+        defaultRoute: '#entry',

+        IPV4_AND_V6_SUPPORT: false, //是否支持IPv4 & v6。 双PDP双栈

+        IPV4V6_SUPPORT: true, //是否支持ipv4v6。 IPV4V6_SUPPORT和IPV4_AND_V6_SUPPORT不可同时为true.单PDP双栈

+        IPV6_SUPPORT: true, //是否支持ipv6

+        EMPTY_APN_SUPPORT: false, //是否支持空apn

+        SHOW_APN_DNS: false, //APN设置页面是否显示DNS,不显示则dnsMode默认设置为auto

+        TRAFFIC_SUPPORT: true, //是否支持流量功能

+        CLEAR_DATA_SUPPORT: false, //是否支持流量和时间清空功能

+        NETWORK_UNLOCK_SUPPORT: false, //是否支持解锁

+        SHOW_MAC_ADDRESS: false, //是否显示mac地址

+        PASSWORD_ENCODE: true, //登录密码和WIFI密码是否加密

+        AP_STATION_SUPPORT: false, //是否支持AP Station功能

+        AP_STATION_LIST_LENGTH: 10,

+        WIFI_WEP_SUPPORT: false, //是否支持wifi WEP加密

+        WIFI_WAP3_SUPPORT: true, //是否支持wifi WAP3加密

+        WIFI_WPA2_WAP3_SUPPORT: true, //是否支持wifi WPA2/WAP3兼容模式

+        WIFI_HAS_5G: false,

+        WIFI_BAND_SUPPORT: false, //是否支持wifi频段设置

+        WIFI_BANDWIDTH_SUPPORT: false, //是否支持频带宽度

+        WIFI_BANDWIDTH_SUPPORT_40MHZ: false, //频带宽度是否支持40MHZ,reltek芯片支持

+        WIFI_SUPPORT_QR_CODE: true, //是否支持wifi二维码显示

+        WIFI_SUPPORT_QR_SWITCH: false, //是否支持wifi二维码显示控制

+        WIFI_SWITCH_SUPPORT: true, //是否支持wifi开关

+        MAX_STATION_NUMBER: 32, //CPE WIFI最大连接数为32

+        SHOW_WIFI_AP_ISOLATED: false, // 是否显示AP隔离

+        STATION_BLOCK_SUPPORT: false, // 已连接设备是否支持Block功能

+        UPGRADE_TYPE: "FOTA", //取值有"NONE","OTA","FOTA","TWO_PORTION"

+        SMS_UNREAD_NUM_INCLUDE_SIM: false, //未读短息数量是否包含SIM侧

+        SMS_DATABASE_SORT_SUPPORT: true, //短信是否支持DB排序

+        SMS_MATCH_LENGTH: 11, //短信联系人号码匹配位数,11国内项目,8国际项目

+        SHOW_UN_COMPLETE_CONCAT_SMS: true, //级联短信未接收完是否显示相关级联短信

+        SMS_SET_READ_WHEN_COMPLETE: false, //聊天过程中,级联短信只有接受完成后才能自动设置为已读

+        SD_CARD_SUPPORT: false, //是否支持SD卡

+        SD_BASE_PATH: '/mmc2', //SD 卡根目录

+        //modem_main_state的临时状态,一般需要界面轮询等待

+        TEMPORARY_MODEM_MAIN_STATE: ["modem_undetected", "modem_detected", "modem_sim_state", "modem_handover", "modem_imsi_lock", "modem_online", "modem_offline"],

+        ISNOW_NOTICE: false, //FOTA是否正在提示有新版本

+        INCLUDE_MOBILE: true,

+        HAS_USSD: false, // 是否支持USSD功能,

+        HAS_URL: false, // 是否支持URL过滤,

+        HAS_CASCADE_SMS: true, //是否支持级联短信

+        HAS_FOTA: true, //是否支持FOTA

+        HAS_UPDATE_CHECK: true, //是否支持升级检测设置

+        HAS_PHONEBOOK: true, //是否有电话本功能

+        HAS_SMS: true, //是否有短信功能

+        HAS_PARENTAL_CONTROL: false, // 是否支持家长控制功能

+        HAS_MULTI_SSID: false, //多ssid功能

+        HAS_WIFI: true, //是否包含wifi功能

+        HAS_QUICK_SETTING: true, //是否支持快速设置

+        HAS_SNTP: true, //是否支持时间管理

+        HAS_BLACK_AND_WHITE_FILTER: false, //是否支持黑白名单

+        HAS_LOGIN: true, //是否有登录页面

+        BAUD_RATES: [{

+                name: '9600',

+                value: '9600'

+            }, {

+                name: '19200',

+                value: '19200'

+            }, {

+                name: '38400',

+                value: '38400'

+            }, {

+                name: '57600',

+                value: '57600'

+            }, {

+                name: '115200',

+                value: '115200'

+            }, {

+                name: '230400',

+                value: '230400'

+            }, {

+                name: '460800',

+                value: '460800'

+            }, {

+                name: '921600',

+                value: '921600'

+            }

+        ],

+        FORWARDING_MODES: [{

+                name: 'Unconditional forwarding',

+                value: '1'

+            }, {

+                name: 'When busy',

+                value: '2'

+            }, {

+                name: 'When no answer',

+                value: '3'

+            }, {

+                name: 'Cancel all forwarding',

+                value: '0'

+            }

+        ],

+        wdsModes: [{

+                name: "Disable",

+                value: "0"

+            }, {

+                name: "RootAP Mode",

+                value: "1"

+            }, {

+                name: "Bridge Mode",

+                value: "2"

+            }, {

+                name: "Repeater Mode",

+                value: "3"

+            }

+        ],

+        daylightSave: [{

+                name: "Disable",

+                value: "0"

+            }, {

+                name: "Enable",

+                value: "1"

+            }

+        ],

+        sntpTimeSetMode: [{

+                name: 'manual',

+                value: 'manual'

+            }, {

+                name: 'auto',

+                value: 'auto'

+            }

+        ],

+        //时区

+        timeZone: [{

+                name: "(GMT-12:00) Dateline West",

+                value: "<-12>12_0"

+            }, {

+                name: "(GMT-11:00) Midway Islands, Samoa",

+                value: "SST11_0"

+            }, {

+                name: "(GMT-10:00) Hawaii",

+                value: "<-10>10_0"

+            }, {

+                name: "(GMT-09:00) Alaska",

+                value: "<-09>9_0"

+            }, {

+                name: "(GMT-08:00) Pacific time (USA and Canada), Tijuana",

+                value: "PST8PDT,M3.2.0,M11.1.0_0"

+            }, {

+                name: "(GMT-07:00) Mountain time (USA and Canada)",

+                value: "<-07>7_0"

+            }, {

+                name: "(GMT-07:00) Arizona",

+                value: "<-07>7_1"

+            }, {

+                name: "(GMT-07:00) Chihuahua, La Paz, Mazza Tran",

+                value: "MST7MDT,M4.1.0,M10.5.0_2"

+            }, {

+                name: "(GMT-06:00) Saskatchewan",

+                value: "<-06>6_0"

+            }, {

+                name: "(GMT-06:00) Central time (USA and Canada)",

+                value: "<-06>6_1"

+            }, {

+                name: "(GMT-06:00) Central America",

+                value: "<-06>6_2"

+            }, {

+                name: "(GMT-06:00) Guadalajara City, Mexico City, Monterey",

+                value: "<-06>6_3"

+            }, {

+                name: "(GMT-05:00) Bogota, Lima, Quito",

+                value: "<-05>5_0"

+            }, {

+                name: "(GMT-05:00) Eastern time (USA and Canada)",

+                value: "<-05>5_1"

+            }, {

+                name: "(GMT-05:00) Indiana (East)",

+                value: "EST5EDT,M3.2.0,M11.1.0_2"

+            }, {

+                name: "(GMT-04:00) Atlantic time (Canada)",

+                value: "AST4ADT,M3.2.0,M11.1.0_0"

+            }, {

+                name: "(GMT-04:00) Caracas, La Paz",

+                value: "<-04>4_1"

+            }, {

+                name: "(GMT-04:00) Santiago",

+                value: "<-04>4<-03>,M8.2.6/24,M5.2.6/24_2"

+            }, {

+                name: "(GMT-03:30) Newfoundland",

+                value: "NST3:30NDT,M3.2.0,M11.1.0_0"

+            }, {

+                name: "(GMT-03:00) Brasilia",

+                value: "<-03>3_0"

+            }, {

+                name: "(GMT-03:00) Buenos Aires, Georgetown",

+                value: "<-03>3_1"

+            }, {

+                name: "(GMT-03:00) Greenland",

+                value: "<-03>3_2"

+            }, {

+                name: "(GMT-02:00) Mid-Atlantic",

+                value: "<-02>2_0"

+            }, {

+                name: "(GMT-01:00) Cape Verde Islands",

+                value: "<-01>1_0"

+            }, {

+                name: "(GMT-01:00) Azores",

+                value: "<-01>1<+00>,M3.5.0/0,M10.5.0/1_1"

+            }, {

+                name: "(GMT) GMT: Dublin, Edinburgh, London, Lisbon",

+                value: "GMT0IST,M3.5.0/1,M10.5.0_0"

+            }, {

+                name: "(GMT) Casablanca, Monrovia",

+                value: "WET0WEST,M3.5.0,M10.5.0/3_1"

+            }, {

+                name: "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna",

+                value: "CET-1CEST,M3.5.0,M10.5.0/3_0"

+            }, {

+                name: "(GMT+01:00) Belgrad, Bratislava, Budapest, Ljubljana, Prague",

+                value: "CET-1CEST,M3.5.0,M10.5.0/3_1"

+            }, {

+                name: "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris",

+                value: "CET-1CEST,M3.5.0,M10.5.0/3_2"

+            }, {

+                name: "(GMT+01:00) Sarajevo, Skopje,Warsaw, Zagreb",

+                value: "CET-1CEST,M3.5.0,M10.5.0/3_3"

+            }, {

+                name: "(GMT+01:00) Western Central African",

+                value: "<+01>-1_4"

+            }, {

+                name: "(GMT+02:00) Bucharest",

+                value: "EET-2EEST,M3.5.0/3,M10.5.0/4_0"

+            }, {

+                name: "(GMT+02:00) Pretoria, Harare",

+                value: "CAT-2_1"

+            }, {

+                name: "(GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius",

+                value: "EET-2EEST,M3.5.0/3,M10.5.0/4_2"

+            }, {

+                name: "(GMT+02:00) Cairo",

+                value: "EET-2_3"

+            }, {

+                name: "(GMT+02:00) Athens, Beirut, Istanbul, Minsk",

+                value: "EET-2EEST,M3.5.0/3,M10.5.0/4_4"

+            }, {

+                name: "(GMT+02:00) Jerusalem",

+                value: "IST-2IDT,M3.4.5/02:00:00,M10.5.0/02:00:00_5"

+            }, {

+                name: "(GMT+03:00) Baghdad",

+                value: "<+03>-3_0"

+            }, {

+                name: "(GMT+03:00) Riyadh, Kuwait",

+                value: "<+03>-3_1"

+            }, {

+                name: "(GMT+03:00) Moscow, St Petersburg, Volgograd",

+                value: "<+03>-3_2"

+            }, {

+                name: "(GMT+03:00) Nairobi",

+                value: "EAT-3_3"

+            }, {

+                name: "(GMT+03:30) Teheran",

+                value: "<+0330>-3:30<+0430>,J80/0,J264/0_0"

+            }, {

+                name: "(GMT+04:00) Abu Zabi, Muscat",

+                value: "<+04>-4_0"

+            }, {

+                name: "(GMT+04:00) Baku, Tbilisi, Yerevan",

+                value: "<+04>-4_1"

+            }, {

+                name: "(GMT+04:30) Kabul",

+                value: "<+0430>-4:30_0"

+            }, {

+                name: "(GMT+05:00) Yekaterinburg",

+                value: "<+05>-5_0"

+            }, {

+                name: "(GMT+05:00) Islamabad, Karachi, Tashkent",

+                value: "PKT-5_1"

+            }, {

+                name: "(GMT+05:30) Madras, Calcutta, Mumbai, New Delhi",

+                value: "<+0530>-5:30_0"

+            }, {

+                name: "(GMT+05:45) Kathmandu",

+                value: "<+0545>-5:45_0"

+            }, {

+                name: "(GMT+06:00) Ala Mutu, Novosibirsk",

+                value: "<+06>-6_0"

+            }, {

+                name: "(GMT+06:00) Dhaka, Astana",

+                value: "<+06>-6_1"

+            }, {

+                name: "(GMT+06:00) Sri Haya Ed Denny Pla",

+                value: "<+06>-6_2"

+            }, {

+                name: "(GMT+06:30) Yangon",

+                value: "<+0630>-6:30_0"

+            }, {

+                name: "(GMT+07:00) Krasnoyarsk",

+                value: "<+07>-7_0"

+            }, {

+                name: "(GMT+07:00) Bangkok, Hanoi, Jakarta",

+                value: "<+07>-7_1"

+            }, {

+                name: "(GMT+08:00) Beijing, Chongqing, Hongkong Special Administrative Region, Urumqi",

+                value: "CST-8_0"

+            }, {

+                name: "(GMT+08:00) Kuala Lumpur, Singapore",

+                value: "<+08>-8_1"

+            }, {

+                name: "(GMT+08:00) Perth",

+                value: "AWST-8_2"

+            }, {

+                name: "(GMT+08:00) Taipei",

+                value: "CST-8_3"

+            }, {

+                name: "(GMT+08:00) Irkutsk, Ulam Batu",

+                value: "<+08>-8_4"

+            }, {

+                name: "(GMT+09:00) Osaka, Sapporo, Tokyo",

+                value: "JST-9_0"

+            }, {

+                name: "(GMT+09:00) Seoul",

+                value: "KST-9_1"

+            }, {

+                name: "(GMT+09:00) Yakutsk",

+                value: "<+09>-9_2"

+            }, {

+                name: "(GMT+09:30) Adelaide",

+                value: "ACST-9:30ACDT,M10.1.0,M4.1.0/3_0"

+            }, {

+                name: "(GMT+09:30) Darwin",

+                value: "ACST-9:30_1"

+            }, {

+                name: "(GMT+10:00) Brisbane",

+                value: "AEST-10_0"

+            }, {

+                name: "(GMT+10:00) Vladivostok",

+                value: "<+10>-10_1"

+            }, {

+                name: "(GMT+10:00) Guam, Port Moresby",

+                value: "<+10>-10_2"

+            }, {

+                name: "(GMT+10:00) Hobart",

+                value: "AEST-10AEDT,M10.1.0,M4.1.0/3_3"

+            }, {

+                name: "(GMT+10:00) Canberra, Melbourne, Sydney",

+                value: "AEST-10AEDT,M10.1.0,M4.1.0/3_4"

+            }, {

+                name: "(GMT+11:00) Magadan, Solomon islands, New Caledonia",

+                value: "<+11>-11_0"

+            }, {

+                name: "(GMT+12:00) Wellington, Oakland",

+                value: "<+12>-12_0"

+            }, {

+                name: "(GMT+12:00) Fiji, Kamchatka, Marshall Islands",

+                value: "<+12>-12_1"

+            }, {

+                name: "(GMT+13:00) Nukualofa",

+                value: "<+13>-13_0"

+            }

+        ],

+

+        //短信保存时间

+        SMS_VALIDITY: [{

+                name: '12 hours',

+                value: 'twelve_hours'

+            }, {

+                name: 'A day',

+                value: 'one_day'

+            }, {

+                name: 'A week',

+                value: 'one_week'

+            }, {

+                name: 'The longest period',

+                value: 'largest'

+            }

+        ],

+        MAP_PROTOCOL_MODES: [{

+                name: "TCP+UDP",

+                value: "TCP&UDP"

+            }, {

+                name: "TCP",

+                value: "TCP"

+            }, {

+                name: "UDP",

+                value: "UDP"

+            }

+        ],

+        //端口转发协议

+        FORWARD_PROTOCOL_MODES: [{

+                name: "TCP+UDP",

+                value: "TCP&UDP"

+            }, {

+                name: "TCP",

+                value: "TCP"

+            }, {

+                name: "UDP",

+                value: "UDP"

+            }

+        ],

+        FILTER_PROTOCOL_MODES: [{

+                name: "NONE",

+                value: "None"

+            }, {

+                name: "TCP",

+                value: "TCP"

+            }, {

+                name: "UDP",

+                value: "UDP"

+            }, {

+                name: "ICMP",

+                value: "ICMP"

+            }

+        ],

+

+        //HTTPSHARE模式

+        SD_SHARE_ENABLE: [{

+                name: "Enable",

+                value: "1"

+            }, {

+                name: "Disable",

+                value: "0"

+            }

+        ],

+

+        SD_ACCESS_TYPE: [{

+                name: "entire_sd_card",

+                value: "1"

+            }, {

+                name: "custom_setting",

+                value: "0"

+            }

+        ],

+

+        SD_FILE_TO_SHARE: [{

+                name: "entire_sd_card",

+                value: "1"

+            }, {

+                name: "custom_setting",

+                value: "0"

+            }

+        ],

+

+        //国家码所述类型

+        countryCodeType: {

+            world: 3,

+            mkkc: 3,

+            apld: 7,

+            etsic: 3,

+            fcca: 1

+        },

+

+        countries_5g: {

+            NONE: "NONE",

+            AR: "ARGENTIA",

+            AM: "ՀԱՅԱՍՏԱՆ",

+            AU: "AUSTRILIA",

+            AT: "ÖSTERREICH",

+            AZ: "AZƏRBAYCAN",

+            BH: "البحرين",

+            BY: "БЕЛАРУСЬ",

+            BE: "BELGIË",

+            BA: "БОСНА И ХЕРЦЕГОВИНА",

+            BR: "BRASIL",

+            BN: "BRUNEI DARUSSALAM",

+            BG: "БЪЛГАРИЯ",

+            CL: "CHILE",

+            CN: "中国",

+            CR: "COSTA RICA",

+            HR: "HRVATSKA",

+            CY: "ΚΎΠΡΟΣ",

+            CZ: "ČESKÁ REPUBLIKA",

+            DK: "DANMARK",

+            EC: "ECUADOR",

+            EG: "مصر",

+            SV: "EL SALVADOR",

+            EE: "EESTI",

+            FI: "SUOMI",

+            FR: "FRANCE",

+            GE: "საქართველო",

+            DE: "DEUTSCHLAND",

+            GR: "ΕΛΛΆΔΑ",

+            HK: "香港",

+            HU: "MAGYARORSZÁG",

+            IS: "ÍSLAND",

+            IN: "INDIA",

+            ID: "INDONESIA",

+            IR: "ایران",

+            IE: "ÉIRE",

+            IL: "إسرائيل",

+            IT: "ITALIA",

+            JM: "JAMAICA",

+            JO: "الأردن",

+            KP: "조선민주주의인민공화국",

+            KR: "한국 ROK",

+            LV: "LATVIJA",

+            LI: "LIECHTENSTEIN",

+            LT: "LIETUVA",

+            LU: "LUXEMBOURG",

+            MO: "澳門",

+            MY: "MALAYSIA",

+            MT: "MALTA",

+            MC: "MONACO",

+            NL: "NEDERLAND",

+            AN: "Netherlands Antilles",

+            NO: "NORGE",

+            OM: "سلطنة عمان",

+            PE: "PERÚ",

+            PH: "PHILIPPINES",

+            PL: "POLSKA",

+            PT: "PORTUGAL",

+            SA: "السعودية",

+            SG: "SINGAPORE",

+            SK: "SLOVENSKÁ REPUBLIKA",

+            SI: "SLOVENIJA",

+            ZA: "SOUTH AFRICA",

+            ES: "ESPAÑA",

+            LK: "SRILANKA",

+            SE: "SVERIGE",

+            CH: "SCHWEIZ",

+            TT: "TRINIDAD AND TOBAGO",

+            TN: "تونس",

+            TR: "TÜRKİYE",

+            GB: "UNITED KINGDOM",

+            UY: "URUGUAY",

+            JP: "日本",

+            BZ: "BELIZE",

+            BO: "BOLIVIA",

+            NZ: "NEW ZEALAND",

+            VE: "VENEZUELA",

+            CA: "CANADA",

+            CO: "COLOMBIA",

+            DO: "REPÚBLICA DOMINICANA",

+            GT: "GUATEMALA",

+            MX: "MEXICO",

+            PA: "PANAMÁ",

+            PR: "PUERTO RICO",

+            TW: "台灣",

+            US: "UNITED STATES",

+            UZ: "O’zbekiston"

+        },

+

+        //国家码与语言匹配表

+        countries: {

+            NONE: "NONE",

+            AL: "SHQIPERI",

+            DZ: "الجزائر",

+            AR: "ARGENTIA",

+            AM: "ՀԱՅԱՍՏԱՆ",

+            AU: "AUSTRALIA",

+            AT: "ÖSTERREICH",

+            AZ: "AZƏRBAYCAN",

+            BD: "বাংলাদেশ",

+            BH: "البحرين",

+            BY: "БЕЛАРУСЬ",

+            BE: "BELGIË",

+            BA: "БОСНА И ХЕРЦЕГОВИНА",

+            BR: "BRASIL",

+            BN: "BRUNEI DARUSSALAM",

+            BG: "БЪЛГАРИЯ",

+            CL: "CHILE",

+            CN: "中国",

+            CR: "COSTA RICA",

+            HR: "HRVATSKA",

+            CY: "ΚΎΠΡΟΣ",

+            CZ: "ČESKÁ REPUBLIKA",

+            DK: "DANMARK",

+            EC: "ECUADOR",

+            EG: "مصر",

+            SV: "EL SALVADOR",

+            EE: "EESTI",

+            FI: "SUOMI",

+            FR: "FRANCE",

+            GE: "საქართველო",

+            DE: "DEUTSCHLAND",

+            GR: "ΕΛΛΆΔΑ",

+            HN: "HONDURAS",

+            HK: "香港",

+            HU: "MAGYARORSZÁG",

+            IS: "ÍSLAND",

+            IN: "INDIA",

+            ID: "INDONESIA",

+            IR: "ایران، جمهوری اسلامی",

+            IE: "ÉIRE",

+            IL: "إسرائيل",

+            IT: "ITALIA",

+            JM: "JAMAICA",

+            JO: "الأردن",

+            KZ: "КАЗАХСТАН",

+            KE: "KENYA",

+            KP: "조선민주주의인민공화국",

+            KR: "한국 ROK",

+            KW: "الكويت",

+            LV: "LATVIJA",

+            LB: "لبنان",

+            LI: "LIECHTENSTEIN",

+            LT: "LIETUVA",

+            LU: "LUXEMBOURG",

+            MO: "澳門",

+            MK: "МАКЕДОНИЈА",

+            MY: "MALAYSIA",

+            MT: "MALTA",

+            MC: "MONACO",

+            MA: "المغرب",

+            NL: "NEDERLAND",

+            AN: "NETHERLANDS ANTILLES",

+            NO: "NORGE",

+            OM: "سلطنة عمان",

+            PK: "PAKISTAN",

+            PE: "PERÚ",

+            PH: "PHILIPPINES",

+            PL: "POLSKA",

+            PT: "PORTUGAL",

+            QA: "قطر",

+            RO: "ROMÂNIA",

+            RU: "Российская Федерация",

+            SA: "السعودية",

+            SG: "SINGAPORE",

+            SK: "SLOVENSKÁ REPUBLIKA",

+            SI: "SLOVENIJA",

+            ZA: "SOUTH AFRICA",

+            ES: "ESPAÑA",

+            LK: "SRILANKA",

+            SE: "SVERIGE",

+            CH: "SCHWEIZ",

+            SY: "الجمهورية العربية السورية",

+            TH: "ประเทศไทย",

+            TT: "TRINIDAD AND TOBAGO",

+            TN: "تونس",

+            TR: "TÜRKİYE",

+            UA: "Україна",

+            AE: "الإمارات العربية المتحدة",

+            GB: "UNITED KINGDOM",

+            UY: "URUGUAY",

+            VN: "VIỆT NAM",

+            YE: "اليمن",

+            ZW: "ZIMBABWE",

+            JP: "日本",

+            BZ: "BELIZE",

+            BO: "BOLIVIA",

+            NZ: "NEW ZEALAND",

+            VE: "REPÚBLICA BOLIVARIANA DE VENEZUELA",

+            CA: "CANADA",

+            CO: "COLOMBIA",

+            DO: "REPÚBLICA DOMINICANA",

+            GT: "GUATEMALA",

+            MX: "MEXICO",

+            PA: "PANAMÁ",

+            PR: "PUERTO RICO",

+            TW: "台灣",

+            US: "UNITED STATES",

+            UZ: "O’zbekiston"

+        },

+        //国家码与类型匹配表

+        countryCode_5g: {

+            //88 countries of world【36 40 44 48】

+            one: {

+                codes: ["AL", "AI", "AW", "AT", "BY", "BM", "BA", "BW", "IO", "BG",

+                    "CV", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", "GF", "PF",

+                    "TF", "GI", "DE", "GR", "GP", "GG", "HU", "IS", "IE", "IT",

+                    "KE", "LA", "LV", "LS", "LI", "LT", "LU", "MK", "MT", "IM",

+                    "MQ", "MR", "MU", "YT", "MC", "MS", "NL", "AN", "NO",

+                    "OM", "PL", "PT", "RE", "RO", "SM", "SN", "RS", "SK", "SI",

+                    "ZA", "ES", "SE", "CH", "TC", "UG", "GB", "VG", "WF", "ZM",

+                    "AF", "JO", "MA", "EH", "EU", "DZ", "IL", "MX", "PM", "TN",

+                    "TR", "JP"],

+                channels: [36, 40, 44, 48]

+            },

+            //60 countrys of world【36 40 44 48 149 153 157 161 165】

+            two: {

+                codes: ["AS", "AG", "AZ", "BR", "KH", "KY", "CO", "CR", "DM", "DO",

+                    "EC", "GH", "GD", "HK", "KZ", "KI", "FM", "MZ", "NA", "NZ",

+                    "NI", "NE", "PW", "PE", "PH", "PR", "VC", "TH", "TT", "UY",

+                    "ZW", "AU", "BH", "BB", "CA", "CL", "CX", "EG", "SV", "GT",

+                    "HT", "IN", "MY", "NF", "PA", "PG", "SG", "US", "VN"],

+                channels: [36, 40, 44, 48, 149, 153, 157, 161, 165]

+            },

+            //9 countrys of world【149 153 157 161】

+            three: {

+                codes: ["CU", "IR", "KR", "SY", "LB", "MW", "MO", "QA"],

+                channels: [149, 153, 157, 161]

+            },

+            //12 countrys of world【149 153 157 161 165】

+            four: {

+                codes: ["BD", "BF", "CN", "HN", "JM", "PK", "PY", "KN", "AR", "TW", "NG"],

+                channels: [149, 153, 157, 161, 165]

+            },

+            //1 country of world【36 40 44 48 149 153 157 161】

+            five: {

+                codes: ["SA"],

+                channels: [36, 40, 44, 48, 149, 153, 157, 161]

+            }

+        },

+        countryCode: {

+            world: ["AL", "DZ", "AR", "AM", "AU", "AT", "AZ", "BH", "BY",

+                "BE", "BA", "BR", "BN", "BG", "CL", "CN", "CR", "HR", "CY",

+                "CZ", "DK", "EC", "EG", "SV", "EE", "FI", "FR", "GE",

+                "DE", "GR", "HN", "HK", "HU", "IS", "IN", "ID", "IR", "IE",

+                "IL", "IT", "JM", "JO", "KZ", "KE", "KP", "KR", "KW", "LV",

+                "LB", "LI", "LT", "LU", "MO", "MK", "MY", "MT", "MC", "MA",

+                "NL", "AN", "NO", "OM", "PK", "PE", "PH", "PL", "PT", "QA",

+                "RO", "RU", "SA", "SG", "SK", "SI", "ZA", "ES", "LK",

+                "SE", "CH", "SY", "TH", "TT", "TN", "TR", "UA", "AE", "GB",

+                "UY", "VN", "YE", "ZW", "BD"],

+            mkkc: ["JP"],

+            apld: [],

+            etsic: ["BZ", "BO", "NZ", "VE"],

+            fcca: ["CA", "CO", "DO", "GT", "MX", "PA", "PR", "TW", "US", "UZ"]

+        },

+        //休眠时间

+        SLEEP_MODES: [{

+                name: "Always on",

+                value: "-1"

+            }, {

+                name: "5 minutes",

+                value: "5"

+            }, {

+                name: "10 minutes",

+                value: "10"

+            }, {

+                name: "20 minutes",

+                value: "20"

+            }, {

+                name: "30 minutes",

+                value: "30"

+            }, {

+                name: "1 hour",

+                value: "60"

+            }, {

+                name: "2 hours",

+                value: "120"

+            }

+        ],

+        DDNSSetMode: [{

+                name: 'Enable',

+                value: '1'

+            }, {

+                name: 'Disable',

+                value: '0'

+            }

+        ],

+        ddns_Modeselect: [{

+                name: 'manual',

+                value: 'manual'

+            }, {

+                name: 'auto',

+                value: 'auto'

+            }

+        ],

+        DDNSDDP: [{

+                name: 'dyndns.org',

+                value: 'dyndns.org'

+            }, {

+                name: 'freedns.afraid.org',

+                value: 'freedns.afraid.org'

+            }, {

+                name: 'zoneedit.com',

+                value: 'zoneedit.com'

+            }, {

+                name: 'no-ip.com',

+                value: 'no-ip.com'

+            }, {

+                name: 'None',

+                value: 'none'

+            }

+        ],

+        //RJ45连接模式

+        pppoeModes: [{

+                name: "PPPoE",

+                value: "PPPOE"

+            }, {

+                name: "Static",

+                value: "STATIC"

+            }, {

+                name: "DHCP",

+                value: "DHCP"

+            }, {

+                name: "AUTO",

+                value: "AUTO"

+            }

+        ],

+        //联网模式

+        AUTO_MODES: [{

+                name: 'Automatic',

+                value: 'NETWORK_auto'

+            }, {

+                name: '4G Only',

+                value: 'Only_LTE'

+            }, {

+                name: '3G Only',

+                value: 'Only_WCDMA'

+            }, {

+                name: '2G Only',

+                value: 'Only_GSM'

+            }

+        ],

+        //APN鉴权模式

+        APN_AUTH_MODES: [{

+                name: "NONE",

+                value: "none"

+            }, {

+                name: "CHAP",

+                value: "chap"

+            }, {

+                name: "PAP",

+                value: "pap"

+            }

+        ],

+        //语言

+        LANGUAGES: [{

+                name: 'English',

+                value: 'en'

+            }, {

+                name: '中文',

+                value: 'zh-cn'

+            }

+        ],

+        //wifi加密模式

+        AUTH_MODES: [{

+                name: 'NO ENCRYPTION',

+                value: 'OPEN'

+            }, {

+                name: 'WPA2(AES)-PSK',

+                value: 'WPA2PSK'

+            }, {

+                name: 'WPA-PSK/WPA2-PSK',

+                value: 'WPAPSKWPA2PSK'

+            }, {

+                name: 'WPA3-Personal',

+                value: 'WPA3Personal'

+            }, {

+                name: 'WPA2(AES)/WPA3-Personal',

+                value: 'WPA2WPA3'

+            }

+        ],

+        AUTH_MODES_WEP: [{

+                name: 'NO ENCRYPTION',

+                value: 'OPEN'

+            }, {

+                name: 'SHARED',

+                value: 'SHARED'

+            }, {

+                name: 'WPA2(AES)-PSK',

+                value: 'WPA2PSK'

+            }, {

+                name: 'WPA-PSK/WPA2-PSK',

+                value: 'WPAPSKWPA2PSK'

+            }, {

+                name: 'WPA3-Personal',

+                value: 'WPA3Personal'

+            }, {

+                name: 'WPA2(AES)/WPA3-Personal',

+                value: 'WPA2WPA3'

+            }

+        ],

+        AUTH_MODES_ALL: [{

+                name: 'NO ENCRYPTION',

+                value: 'OPEN'

+            }, {

+                name: 'SHARED',

+                value: 'SHARED'

+            }, {

+                name: 'WPA-PSK',

+                value: 'WPAPSK'

+            }, {

+                name: 'WPA2-PSK',

+                value: 'WPA2PSK'

+            }, {

+                name: 'WPA-PSK/WPA2-PSK',

+                value: 'WPAPSKWPA2PSK'

+            }, /*{

+                name: 'WPA3-Personal',

+                value: 'WPA3Personal'

+            }, {

+                name: 'WPA2(AES)/WPA3-Personal',

+                value: 'WPA2WPA3'

+            }, */{

+                name: 'EAP-SIM/AKA',

+                value: 'EAP-SIM/AKA'

+            }

+        ],

+

+        NETWORK_MODES: [{

+                name: '802.11 b/g/n',

+                value: '4'

+            }, {

+                name: '802.11 n only',

+                value: '2'

+            }

+        ],

+        NETWORK_MODES_BAND: [{

+                name: '802.11 a only',

+                value: '5'

+            }, {

+                name: '802.11 n only',

+                value: '2'

+            }, {

+                name: '802.11 a/n',

+                value: '4'

+            }

+        ],

+        resetContentModifyValue: function () {

+            this.CONTENT_MODIFIED.checkChangMethod = function () {

+                return false;

+            };

+            this.CONTENT_MODIFIED.modified = false;

+            this.CONTENT_MODIFIED.message = 'leave_page_info';

+            this.CONTENT_MODIFIED.callback = {

+                ok: $.noop,

+                no: function () {

+                    return true;

+                }

+            }; //如果no返回true,页面则保持原状

+            this.CONTENT_MODIFIED.data = {};

+        },

+        CONTENT_MODIFIED: {

+            modified: false,

+            message: 'leave_page_info',

+            data: {},

+            checkChangMethod: function () {

+                return false;

+            },

+            callback: {

+                ok: $.noop,

+                no: function () {

+                    return true;

+                }

+            } //如果no返回true,页面则保持原状

+        }, //当前页面内容是否已经修改

+

+    };

+

+    require([config.DEVICE + '/set'], function (otherConf) {

+        $.extend(config, otherConf);

+    });

+

+    return config;

+});

diff --git a/ap/app/zte_webui/js/sim_device.js b/ap/app/zte_webui/js/sim_device.js
new file mode 100755
index 0000000..06fbd32
--- /dev/null
+++ b/ap/app/zte_webui/js/sim_device.js
@@ -0,0 +1,5005 @@
+define("sim_abnormal","jquery knockout service set main opmode".split(" "),

+    function ($, ko, service, config, home, opmode) {

+

+    function init() {

+        var container = $('#container')[0];

+        ko.cleanNode(container);

+        var vm = new simViewMode();

+        ko.applyBindings(vm, container);

+

+        $('#frmPUK').validate({

+            submitHandler: function () {

+                vm.enterPUK();

+            },

+            rules: {

+                txtNewPIN: "pin_check",

+                txtConfirmPIN: {

+                    equalToPin: "#txtNewPIN"

+                },

+                txtPUK: "puk_check"

+            }

+        });

+		

+        $('#frmPIN').validate({

+            submitHandler: function () {

+                vm.enterPIN();

+            },

+            rules: {

+                txtPIN: "pin_check"

+            }

+        });

+    }

+

+    function simViewMode() {

+        var target = this;

+        var staInfo = service.getStatusInfo();

+        var curCableMode = "PPPOE" == staInfo.blc_wan_mode || "AUTO_PPPOE" == staInfo.blc_wan_mode;

+        target.hasRj45 = config.RJ45_SUPPORT;

+        target.hasSms = config.HAS_SMS;

+        target.hasPhonebook = config.HAS_PHONEBOOK;

+        target.isSupportSD = config.SD_CARD_SUPPORT;

+        if (config.WIFI_SUPPORT_QR_SWITCH) {

+            var wifiInfo = service.getWifiBasic();

+            target.showQRCode = config.WIFI_SUPPORT_QR_CODE && wifiInfo.show_qrcode_flag;

+        } else {

+            target.showQRCode = config.WIFI_SUPPORT_QR_CODE;

+        }

+        target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + $.now();

+        target.hasParentalControl = ko.observable(config.HAS_PARENTAL_CONTROL && curCableMode);

+        target.pageState = {

+            NO_SIM: 0,

+            WAIT_PIN: 1,

+            WAIT_PUK: 2,

+            PUK_LOCKED: 3,

+            LOADING: 4

+        };

+        target.isHomePage = ko.observable(false);

+        if (window.location.hash == "#main") {

+            target.isHomePage(true);

+        }

+

+        var info = service.getLoginData();

+        target.PIN = ko.observable();

+        target.newPIN = ko.observable();

+        target.confirmPIN = ko.observable();

+        target.PUK = ko.observable();

+        target.pinNumber = ko.observable(info.pinnumber);

+        target.pukNumber = ko.observable(info.puknumber);

+

+        var state = computePageState(info);

+        target.page = ko.observable(state);

+        if (state == target.pageState.LOADING) {

+            addTimeout(refreshPage, 500);

+        }

+        target.showOpModeWindow = function () {

+            showSettingWindow("change_mode", "opmode_popup", "opmode_popup", 400, 300, function () {});

+        };

+        target.isLoggedIn = ko.observable(false);

+        target.enableFlag = ko.observable(false);

+        //更新当前工作模式状态信息

+        target.refreshOpmodeInfo = function () {

+            var staInfo = service.getStatusInfo();

+            target.isLoggedIn(staInfo.isLoggedIn);

+

+            if (!curCableMode && checkCableMode(staInfo.blc_wan_mode)) { //如果有线,则重新加载

+                if (target.page() == target.pageState.NO_SIM || target.page() == target.pageState.WAIT_PIN || target.page() == target.pageState.WAIT_PUK || target.page() == target.pageState.PUK_LOCKED) {

+                    window.location.reload();

+                }

+            }

+

+            curCableMode = checkCableMode(staInfo.blc_wan_mode);

+            target.hasParentalControl(config.HAS_PARENTAL_CONTROL && curCableMode);

+            if (curCableMode && staInfo.ethWanMode.toUpperCase() == "DHCP") {

+                target.enableFlag(true);

+            } else if ((!curCableMode && staInfo.connectStatus != "ppp_disconnected") || (curCableMode && staInfo.rj45ConnectStatus != "idle" && staInfo.rj45ConnectStatus != "dead")) {

+                target.enableFlag(false);

+            } else {

+                target.enableFlag(true);

+            }

+            var mode = (staInfo.blc_wan_mode == "AUTO_PPP" || staInfo.blc_wan_mode == "AUTO_PPPOE") ? "AUTO" : staInfo.blc_wan_mode;

+            var currentOpMode = "";

+            switch (mode) {

+            case "PPP":

+                currentOpMode = "opmode_gateway";

+                break;

+            case "PPPOE":

+                currentOpMode = "opmode_cable";

+                break;

+            case "AUTO":

+                currentOpMode = "opmode_auto";

+                break;

+            default:

+                break;

+            }

+            $("#opmode").attr("data-trans", currentOpMode).text($.i18n.prop(currentOpMode));

+        }

+        //刷新页面状态

+        function refreshPage() {

+            var data = service.getLoginData();

+            var state = computePageState(data);

+            if (state == target.pageState.LOADING) {

+                addTimeout(refreshPage, 500);

+            } else {

+                target.page(state);

+                target.pinNumber(data.pinnumber);

+                target.pukNumber(data.puknumber);

+            }

+        }

+        //输入PUK设置新PIN事件处理

+        target.enterPUK = function () {

+            showLoading();

+            target.page(target.pageState.LOADING);

+            var newPIN = target.newPIN();

+            var confirmPIN = target.confirmPIN();

+            var params = {};

+            params.PinNumber = newPIN;

+            params.PUKNumber = target.PUK();

+            service.enterPUK(params, function (data) {

+                if (!data.result) {

+                    hideLoading();

+                    if (target.pukNumber() == 2) {

+                        showAlert("last_enter_puk", function () {

+                            refreshPage();

+                        });

+                    } else {

+                        showAlert("puk_error", function () {

+                            refreshPage();

+                            if (target.page() == target.pageState.PUK_LOCKED) {

+                                hideLoading();

+                            }

+                        });

+                    }

+                    target.PUK('');

+                    target.newPIN('');

+                    target.confirmPIN('');

+                } else {

+                    refreshPage();

+                    if (target.page() == target.pageState.PUK_LOCKED) {

+                        hideLoading();

+                    }

+                }

+            });

+        };

+        //验证输入PIN事件处理

+        target.enterPIN = function () {

+            showLoading();

+            target.page(target.pageState.LOADING);

+            var pin = target.PIN();

+            service.enterPIN({

+                PinNumber: pin

+            }, function (data) {

+                if (!data.result) {

+                    hideLoading();

+                    if (target.pinNumber() == 2) {

+                        showAlert("last_enter_pin", function () {

+                            refreshPage();

+                        });

+                    } else {

+                        showAlert("pin_error", function () {

+                            refreshPage();

+                        });

+                    }

+                    target.PIN('');

+                }

+                refreshPage();

+                if (target.page() == target.pageState.WAIT_PUK) {

+                    hideLoading();

+                }

+            });

+        };

+

+        if (target.hasRj45) {

+            target.refreshOpmodeInfo();

+            addInterval(function () {

+                target.refreshOpmodeInfo();

+            }, 1000);

+        }

+        //根据登录状态和SIM卡状态设置页面状态

+        function computePageState(data) {

+            var state = data.modem_main_state;

+            if (state == "modem_undetected" || state == "modem_sim_undetected" || state == "modem_sim_destroy") {

+                return target.pageState.NO_SIM;

+            } else if (state == "modem_waitpin") {

+                return target.pageState.WAIT_PIN;

+            } else if ((state == "modem_waitpuk" || data.pinnumber == 0) && (data.puknumber != 0)) {

+                return target.pageState.WAIT_PUK;

+            } else if ((data.puknumber == 0 || state == "modem_sim_destroy") && state != "modem_sim_undetected" && state != "modem_undetected") {

+                return target.pageState.PUK_LOCKED;

+            } else if ($.inArray(state, config.TEMPORARY_MODEM_MAIN_STATE) != -1) {

+                return target.pageState.LOADING;

+            } else {

+                location.reload();

+            }

+        }

+

+    }

+

+    return {

+        init: init

+    };

+});

+

+define("ota_update", "jquery jq_fileinput service knockout set statusBar".split(" "), 

+

+    function ($, fileinput, service, ko, config, status) {

+

+    function FotaUpdateViewModel() {

+        var target    = this;

+        var setting = service.getOTAUpdateSetting();		

+

+        target.allowRoamingUpdate = ko.observable(setting.allowRoamingUpdate);		

+		target.hasDdns            = config.DDNS_SUPPORT;

+		target.hasUpdateCheck     = config.HAS_UPDATE_CHECK;	

+		target.hasUssd            = config.HAS_USSD;		

+        target.isDataCard         = config.PRODUCT_TYPE == 'DATACARD';

+        target.lastCheckTime      = ko.observable('');	

+        target.updateIntervalDay  = ko.observable(setting.updateIntervalDay);		

+        target.updateMode         = ko.observable(setting.updateMode);

+		target.updateType         = ko.observable(service.getUpdateType().update_type);

+	

+

+        // 自动检测设置按钮事件

+        target.apply = function () {

+            var updateSettingInfo = {

+                updateMode: target.updateMode(),

+                updateIntervalDay: target.updateIntervalDay(),

+                allowRoamingUpdate: target.allowRoamingUpdate()

+            };

+            showLoading();

+            service.setOTAUpdateSetting(updateSettingInfo, function (settingInfo) {

+                if (settingInfo && settingInfo.result == "success") {

+                    setting.allowRoamingUpdate = target.allowRoamingUpdate();

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+        };

+

+		

+        // 按钮【检测】点击事件处理接口

+        target.checkNewVersion = function () {

+            var newVersionState = service.getNewVersionState();

+			if(newVersionState.fota_package_already_download == "yes"){

+				showAlert("fota_package_already_download");

+				return;

+			}

+

+            if(config.UPGRADE_TYPE=="FOTA"){

+                var checkingState = ["checking"];

+                if ($.inArray(newVersionState.fota_current_upgrade_state, checkingState) != -1) {

+                    showAlert("ota_update_running");

+                    return;

+                }

+            }

+            

+			// FOTA开始下载前,判断当前是否已经在下载过程中,防止错误清空fota_new_version_state状态

+            var statusInfo = service.getStatusInfo();

+            if (newVersionState.fota_current_upgrade_state == "prepare_install") {

+                showInfo('ota_download_success');

+                return;

+            }

+			

+            var upgradingState = ["downloading", "confirm_dowmload"];

+            if ($.inArray(newVersionState.fota_current_upgrade_state, upgradingState) != -1) {

+                status.showOTAAlert();

+                return;

+            }

+

+            if (statusInfo.roamingStatus) {

+                showConfirm("ota_check_roaming_confirm", function () {

+                    checkNewVersion();

+                });

+            } else {

+                checkNewVersion();

+            }

+            // 检测是否有新版本

+            function checkNewVersion() {

+                showLoading("ota_new_version_checking");

+                function checkNewVersionResult() {

+                    var result = service.getNewVersionState();

+                    if (result.hasNewVersion) {

+						if(result.fota_new_version_state == "already_has_pkg"&&result.fota_current_upgrade_state !="prepare_install"&&result.fota_current_upgrade_state !="low_battery")

+						{

+							addTimeout(checkNewVersionResult, 1000);

+						}

+						else

+						{

+							status.showOTAAlert();

+						}

+                    } else if (result.fota_new_version_state == "no_new_version") {

+                        showAlert("ota_no_new_version");

+                    }else if (result.fota_new_version_state == "check_failed" ) {

+                        errorOverlay("ota_check_fail");

+                    } else if ( result.fota_new_version_state == "bad_network"){

+                     	errorOverlay("ota_connect_server_failed");

+                    }else {

+                        addTimeout(checkNewVersionResult, 1000);

+                    }

+                }

+

+                service.setUpgradeSelectOp({selectOp: 'check'}, function (result) {

+                    if (result.result == "success") {

+                        checkNewVersionResult();

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            }

+        };

+		

+		

+		

+        // 确认按钮状态:可用/灰化

+        target.fixPageEnable = function () {

+            var connectStatusInfo = service.getStatusInfo();

+			var opModeData = service.getOpMode();

+            if (checkConnectedStatus(connectStatusInfo.connectStatus, opModeData.rj45_state, connectStatusInfo.connectWifiStatus)) {

+                enableBtn($("#btnCheckNewVersion"));

+            } else {

+                disableBtn($("#btnCheckNewVersion"));

+            }

+        };

+

+        target.clickAllowRoamingUpdate = function () {

+            var checkedbox = $("#chkUpdateRoamPermission:checked");

+            if (checkedbox && checkedbox.length == 0) {

+                target.allowRoamingUpdate("1");

+            } else {

+                target.allowRoamingUpdate("0");

+            }

+        };

+		

+        service.getOTAlastCheckTime({}, function(info){

+            target.lastCheckTime(info.dm_last_check_time);

+        });

+	

+	}

+    // 获取升级文件大小

+	function getFileSize(object){

+		var fileLenth = 0;

+		var isIE = /msie/i.test(navigator.userAgent) && !window.opera; 

+		if (isIE) {  //如果是ie

+			var objectValue = object.value;

+			try {  

+				var fso = new ActiveXObject("Scripting.FileSystemObject");  

+				fileLenth = parseInt(fso.GetFile(objectValue).size);

+				} catch (e) {  

+				fileLenth = 1;					

+			} 

+		}else{  //对于非IE获得要上传文件的大小			

+			try{			

+				fileLenth = parseInt(object.files[0].size);

+			}catch (e) {

+				fileLenth = 1;  //获取不到取-1

+			}

+		}

+		return fileLenth/1024/1024;

+	} 

+	

+    function init() {

+        var container = $('#container')[0];

+        ko.cleanNode(container);

+        var fwVm = new FotaUpdateViewModel();

+        ko.applyBindings(fwVm, container);		

+		

+        if(fwVm.updateType() == "mifi_fota"){

+            fwVm.fixPageEnable();

+            addInterval(function () {            

+                fwVm.fixPageEnable();          

+            }, 1000);

+		}else{			

+	        if ($(".customfile").length == 0) {

+			    $("#fileField").customFileInput();

+		    }

+		}

+

+        $('#frmOTAUpdate').validate({

+            submitHandler: function () {

+                fwVm.apply();

+            }

+        });

+    }

+

+    return {

+        init: init

+    };

+});

+

+// SD卡 模块

+

+define("sd", "jquery set service knockout".split(" ") , function($, config, service, ko) {

+

+	// 基目录。感觉此根目录不显示给用户会更友好

+	var basePath = config.SD_BASE_PATH;

+

+	function SDCardViewModel() {

+		var target = this;

+		var SDConfiguration      = service.getSDConfiguration();

+		

+        target.selectedMode        = ko.observable(SDConfiguration.sd_mode);

+        target.orignalMode         = ko.observable(SDConfiguration.sd_mode);

+        target.sdStatus            = ko.observable(SDConfiguration.sd_status);

+		target.orignalSdStatus     = ko.observable(SDConfiguration.sd_status);

+        target.sdStatusInfo        = ko.observable("sd_card_status_info_" + SDConfiguration.sd_status);

+        target.selectedShareEnable = ko.observable(SDConfiguration.share_status);

+        target.selectedFileToShare = ko.observable(SDConfiguration.file_to_share);

+        target.selectedAccessType  = ko.observable(SDConfiguration.share_auth);

+		

+		var path = SDConfiguration.share_file.substring(basePath.length);

+        

+        target.pathToShare         = ko.observable(path);

+        target.isInvalidPath       = ko.observable(false);

+		target.checkEnable         = ko.observable(true);

+

+

+	    addInterval(function(){

+			target.refreshSimStatus();

+		}, 3000);

+		

+        // 检查共享路径是否有效

+        target.checkPathIsValid = ko.computed(function () {

+            if (target.orignalMode() == 0 && target.selectedShareEnable() == '1' && target.selectedFileToShare() == '0'

+                && target.pathToShare() != '' && target.pathToShare() != '/') {

+                service.checkFileExists({

+                    "path": basePath + target.pathToShare()

+                }, function (info) {

+                    if (info.status != "exist") {

+                        target.isInvalidPath(true);

+                    } else {

+                        target.isInvalidPath(false);

+                    }

+                });

+            } else {

+                target.isInvalidPath(false);

+            }

+        });	

+

+		

+        target.disableApplyBtn = ko.computed(function(){

+            return target.selectedMode() == target.orignalMode() && target.selectedMode() == '1';

+        });

+		

+		// 文件共享方式radio点击事件

+		target.fileToShareClickHandle = function(){

+			if(target.selectedFileToShare() == "1"){

+				target.pathToShare("/");

+			}

+			return true;

+		};		

+		

+		// T卡热插拔时状态监控,拔插卡重刷界面

+		target.refreshSimStatus = function(){

+			if(target.checkEnable()){

+				var SDConfiguration = service.getSDConfiguration();

+			    if(SDConfiguration.sd_status && (SDConfiguration.sd_status != target.orignalSdStatus())){

+				    if(SDConfiguration.sd_status != '1'){

+						target.sdStatusInfo("sd_card_status_info_" + SDConfiguration.sd_status);

+						target.sdStatus(SDConfiguration.sd_status);

+		                target.orignalSdStatus(SDConfiguration.sd_status);

+						$("#sd_card_status_info").translate();

+					}else{

+						clearTimer();

+					    clearValidateMsg();

+					    init();

+					}

+			    }

+			}			

+		}

+		 

+

+		

+

+

+		// 表单submit事件处理

+		target.save = function(){

+			showLoading('waiting');

+			target.checkEnable(false);

+			if(target.orignalMode() == target.selectedMode()){

+				showAlert("setting_no_change");

+			} else {

+				service.setSdCardMode({

+					mode : target.selectedMode()

+				}, function(info) {

+					if(info.result){

+                        target.orignalMode(target.selectedMode());

+						if(info.result == "processing"){

+							errorOverlay("sd_usb_forbidden");

+						}else{								

+						    successOverlay();

+						}

+					} else {

+						if (target.selectedMode() == "0") {

+							errorOverlay("sd_not_support");

+						} else {

+						    errorOverlay();

+						}

+					}

+				}, function(error) {

+					if (target.selectedMode() == "0") {

+						errorOverlay("sd_not_support");

+					} else {

+					    errorOverlay();

+					}

+				});

+			}

+			target.checkEnable(true);

+			return true;

+		};

+		

+

+		

+		// 保存详细配置信息

+        target.saveShareDetailConfig = function() {

+            showLoading('waiting');

+            target.checkEnable(false);			

+            var param = {

+                share_status : target.selectedShareEnable(),

+                share_auth : target.selectedAccessType(),

+                share_file : basePath + target.pathToShare()

+            };

+			

+            if (target.selectedShareEnable() == "0") {

+                setSdCardSharing(param);

+            } else {

+                service.checkFileExists({

+                    "path" : param.share_file

+                }, function(info) {

+                    if (info.status != "exist" && info.status != "processing") {

+                        errorOverlay("sd_card_share_setting_" + info.status);

+                    } else {

+                        setSdCardSharing(param);

+                    }

+                }, function(){

+                    errorOverlay();

+                });

+            }

+			

+            target.checkEnable(true);

+            return true;

+		}

+

+		// 设置SD卡共享信息

+        function setSdCardSharing(param){

+			service.setSdCardSharing(param, function(result) {

+				if (isErrorObject(result)) {

+					if (result.errorType == "no_sdcard") {

+						errorOverlay("sd_card_share_setting_no_sdcard");

+					} else {

+						errorOverlay();

+					}

+				} else {

+					successOverlay();

+				}

+			});

+		}

+	}

+

+	// 将配置的option项转换成Option数组

+	// {Array} configItem [{name: "name1", value: "val1"},{name: "name2", value: "val2"}]

+	function getOptionArray(configItem) {

+		var arr = [];

+		for ( var i = 0; i < configItem.length; i++) {

+			arr.push(new Option(configItem.name, configItem.value));

+		}

+		return arr;

+	}

+

+	function init() {

+		var container = $('#container')[0];

+		ko.cleanNode(container);

+		var fwVm = new SDCardViewModel();

+		ko.applyBindings(fwVm, container);

+		$("#sd_card_status_info").translate();

+		$('#sdmode_form').validate({

+			submitHandler : function() {

+				fwVm.save();

+			}

+		});

+		$('#httpshare_form').validate({

+			submitHandler : function() {

+				fwVm.saveShareDetailConfig();

+			},

+			rules : {

+				path_to_share : "check_file_path"

+			}

+		});

+	}

+

+	return {

+		init : init

+	};

+});

+

+// SD卡 HttpShare模块

+

+define("sd_httpshare","jquery underscore jq_fileinput set service knockout".split(" ") , 

+

+	function($, _, fileinput, config, service, ko) {

+

+	// 每页记录条数

+	// 不能够设置每页数据个数,默认:10

+	// 默认值不可修改

+	var perPage = 10;

+	

+	// 当前页

+	var activePage = 1;

+	

+	// 当前目录,默认根目录""

+	var currentPath = "";

+	

+	// 基目录。是否需要显示给用户?用户友好度

+	var basePath = config.SD_BASE_PATH;

+	

+	// 前置路径,发现有的设备会将sd卡数据显示在web目录

+	// prePath = "/usr/conf/web";

+	var prePath = "";

+	

+	// 是否隐藏重命名按钮

+	var readwrite = true;

+	

+	// 文件列表模板

+	var sdFileItemTmpl = null;

+	

+	// 分页模板

+	var pagerTmpl = null;

+    // 配置信息原始状态

+    var originalStatus = null;

+

+    var zoneOffsetSeconds = new Date().getTimezoneOffset() * 60;

+

+    var shareFilePath = '';

+	

+	var sdIsUploading = false;//SD卡是否正在上传文件

+

+	// 生成分页数据数组

+	// @method generatePager

+	// @param {Integer} totalSize 总记录数

+	// @param {Integer} perPageNum 每页记录条数

+	// @param {Integer} currentPage 当前页

+	// @return {Array} 分页数据数组

+	function generatePager(totalSize, perPageNum, currentPage) {

+        if (totalSize == 0) {

+            return [];

+        }

+        var pagersArr = [];

+        var totalPages = getTotalPages(totalSize, perPageNum);

+        pagersArr.push({

+            pageNum: currentPage - 1,

+            isActive: false,

+            isPrev: true,

+            isNext: false,

+            isDot: false

+        });

+        if (currentPage == 6) {

+            pagersArr.push({

+                pageNum: 1,

+                isActive: false,

+                isPrev: false,

+                isNext: false,

+                isDot: false

+            });

+        } else if (currentPage > 5) {

+            pagersArr.push({

+                pageNum: 1,

+                isActive: false,

+                isPrev: false,

+                isNext: false,

+                isDot: false

+            });

+            pagersArr.push({

+                pageNum: 0,

+                isPrev: false,

+                isNext: false,

+                isActive: false,

+                isDot: true

+            });

+        }

+        var i;

+        var startPage = currentPage - 4 > 0 ? currentPage - 4 : 1;

+        var endPage = currentPage + 4;

+        for (i = startPage; i <= endPage && i <= totalPages; i++) {

+            pagersArr.push({

+                pageNum: i,

+                isActive: i == currentPage,

+                isPrev: false,

+                isNext: false,

+                isDot: false

+            });

+        }

+        if (currentPage + 5 == totalPages) {

+            pagersArr.push({

+                pageNum: totalPages,

+                isPrev: false,

+                isNext: false,

+                isActive: false,

+                isDot: false

+            });

+        } else if (currentPage + 3 <= totalPages && i - 1 != totalPages) {

+            pagersArr.push({

+                pageNum: 0,

+                isPrev: false,

+                isNext: false,

+                isActive: false,

+                isDot: true

+            });

+            pagersArr.push({

+                pageNum: totalPages,

+                isPrev: false,

+                isNext: false,

+                isActive: false,

+                isDot: false

+            });

+        }

+        pagersArr.push({

+            pageNum: parseInt(currentPage, 10) + 1,

+            isPrev: false,

+            isNext: true,

+            isActive: false,

+            isDot: false

+        });

+        return pagersArr;

+	}

+

+	function getTotalPages(total, perPage){

+		var totalPages = Math.floor(total / perPage);

+		if (total % perPage != 0) {

+			totalPages++;

+		}

+		return totalPages;

+	}

+

+	// 整理文件列表数据,并用模板显示

+	function showFileSet(files) {

+		var i = 0;

+		var shownFiles = $.map(files, function(n) {

+			var obj = {

+				fileName : HTMLEncode(n.fileName),

+				fileType : n.attribute == 'document' ? 'folder' : getFileType(n.fileName),

+				fileSize : getDisplayVolume(n.size, false),

+				filePath : basePath + getCurrentPath() + "/" + n.fileName,

+                lastUpdateTime : transUnixTime((parseInt(n.lastUpdateTime, 10) + zoneOffsetSeconds) * 1000),

+				trClass : i % 2 == 0 ? "even" : "",

+				readwrite : readwrite

+			};

+			i++;

+			return obj;

+		});

+

+		if(sdFileItemTmpl == null){

+			sdFileItemTmpl = $.template("sdFileItemTmpl", $("#sdFileItemTmpl"));

+		}

+		$("#fileList_container").html($.tmpl("sdFileItemTmpl", {data: shownFiles}));

+	}

+

+	// HttpShareViewModel

+	function HttpShareViewModel() {

+		var isGuest = false;

+		if(window.location.hash == "#httpshare_guest"){

+			isGuest = true;

+		}

+		readwrite = true;

+		activePage = 1;

+        setCurrentPath('');

+		basePath = config.SD_BASE_PATH;

+		showLoading('waiting');

+		service.getSDConfiguration({}, function(data){

+            originalStatus = data;

+            shareFilePath = data.share_file;

+            if(shareFilePath.charAt(shareFilePath.length - 1) == '/'){//如果路径中有/,则去掉

+            	shareFilePath = shareFilePath.substring(0, shareFilePath.length - 1);

+            }

+

+			if(data.sd_status == '1' && data.sd_mode == '0'){ //共享

+				if(isGuest && data.share_status == '1'){// guest and share

+					basePath = shareFilePath;

+					if(data.share_auth == '0'){ // readonly

+						readwrite = false;

+						$("#uploadSection, #delete_file_button, .sd_guest_hide_th", "#httpshare_form").hide();

+					}else{

+                        $("#uploadSection, #delete_file_button, .sd_guest_hide_th", "#httpshare_form").show();

+                    }

+					$("#go_to_login_button").removeClass("hide");

+					$('#sd_menu').hide();

+					$('.form-note').hide();

+					if ($(".customfile").length == 0) {

+						$("#fileField").customFileInput();

+					}

+					pagerItemClickHandler(1);

+				} else if(isGuest && data.share_status == '0'){ // guest not share

+					$(".form-body .content", "#httpshare_form").hide().remove();

+					$(".form-title", "#httpshare_form").attr("data-trans", "httpshare").html($.i18n.prop("httpshare"));

+					$(".form-note", "#httpshare_form").attr("data-trans", "note_http_share_cannot_access").html($.i18n.prop("note_http_share_cannot_access"));

+                    hideLoading();

+				} else {

+					if ($(".customfile").length == 0) {

+						$("#fileField").customFileInput();

+					}

+					pagerItemClickHandler(1);

+				}

+			} else { // usb

+				$(".form-body .content", "#httpshare_form").hide().remove();

+				$(".form-title", "#httpshare_form").attr("data-trans", "httpshare").html($.i18n.prop("httpshare"));

+				$(".form-note", "#httpshare_form").attr("data-trans", "note_http_share_usb_access").html($.i18n.prop("note_http_share_usb_access"));

+                $(".form-note", "#httpshare_form").addClass("margintop10");

+				hideLoading();

+			}

+		}, function(){

+            errorOverlay();

+            $(".form-body .content", "#httpshare_form").hide().remove();

+            $(".form-title", "#httpshare_form").attr("data-trans", "httpshare").html($.i18n.prop("httpshare"));

+            $(".form-note", "#httpshare_form").attr("data-trans", "note_http_share_cannot_access").html($.i18n.prop("note_http_share_cannot_access"));

+        });

+		

+		addInterval(function(){

+			!sdIsUploading && self.checkSdStatus();

+		}, 3000);

+		

+		// T卡热插拔时状态监控,拔插卡重刷界面

+		self.checkSdStatus = function(){			

+			var data = service.getSDConfiguration();

+			if(data.sd_status && (data.sd_status != originalStatus.sd_status)){

+				if(data.sd_status == '1'){

+					window.location.reload();

+				}else{

+					clearTimer();

+					clearValidateMsg();

+					init();

+				}

+			}			

+		}

+	}

+	

+	// 页码点击事件处理

+	pagerItemClickHandler = function(num) {

+		activePage = num;

+		refreshFileList(getCurrentPath(), activePage);

+	};

+

+    function checkConfiguration(){

+        var data = service.getSDConfiguration();

+        if(!_.isEqual(originalStatus, data)){

+            showAlert('sd_config_changed_reload', function(){

+                init();

+            });

+            return false;

+        }

+        return true;

+    }

+

+    //检查操作路径是否为共享路径,如果是共享路径,给用户提示

+    function inSharePath(path, wording) {

+        var tmpShareFilePath = shareFilePath + '/';

+        var tmpPath = path + '/';

+        if (originalStatus.share_status == '1' && shareFilePath != '' && shareFilePath != '/' && tmpShareFilePath.indexOf(tmpPath) != -1) {

+            showAlert(wording);

+            return true;

+        }

+        return false;

+    }

+

+	// 进入文件夹

+	enterFolder = function(name) {

+        if(!checkConfiguration()){

+            return false;

+        }

+		var path;

+		if (name == "") {

+			path = "";

+		} else {

+			path = getCurrentPath() + '/' + name;

+		}

+		refreshFileList(path, 1);

+        return true;

+	};

+

+	// 回到上一级目录

+	backFolder = function() {

+        if(!checkConfiguration()){

+            return false;

+        }

+		var path = getCurrentPath().substring(0, getCurrentPath().lastIndexOf("/"));

+		refreshFileList(path, 1);

+        return true;

+	};

+

+	// 更新按钮状态

+	refreshBtnsStatus = function() {

+		if (getCurrentPath() == "") {

+			$("#rootBtnLi, #backBtnLi").hide();

+		} else {

+			$("#rootBtnLi, #backBtnLi").show();

+		}

+		if (readwrite) {

+            $("#createNewFolderLi").hide();

+            $("#createNewFolderLi").find(".error").hide();

+            $("#newFolderBtnLi").show();

+            $("#newFolderName").val('');

+            $("#createNewFolderErrorLabel").removeAttr('data-trans').text('');

+		} else {

+            $("#newFolderBtnLi, #createNewFolderLi").hide().remove();

+		}

+        checkDeleteBtnStatus();

+	};

+

+	

+	// 刷新文件列表

+	refreshFileList = function(path, index, alertShown) {

+		if(!alertShown){

+            showLoading('waiting');

+        }

+		service.getFileList({

+			path : prePath + basePath + path,

+			index : index

+		}, function(data) {

+			if (isErrorObject(data)) {

+				showAlert(data.errorType);

+				return;

+            }

+            setCurrentPath(path);

+			$("#sd_path").val(path);

+			activePage = index;

+			totalSize = data.totalRecord;

+			showFileSet(data.details);

+			pagination(totalSize); //测试分页时可以将此处totalSize调大

+			refreshBtnsStatus();

+			updateSdMemorySizes();

+            if(!alertShown){

+			    hideLoading();

+            }

+		});

+	};

+

+

+	// 显示新建文件夹按钮点击事件

+	openCreateNewFolderClickHandler = function() {

+		$("#newFolderBtnLi").hide();

+		$("#newFolderName").show();

+		$("#createNewFolderLi").show();

+	};

+

+	// 取消显示新建文件夹按钮点击事件

+	cancelCreateNewFolderClickHandler = function() {

+		$("#createNewFolderLi").hide();

+        $("#newFolderName").val('');

+		$("#newFolderBtnLi").show();

+		$("#createNewFolderLi").find(".error").hide();

+	};

+

+	// 新建文件夹按钮点击事件

+	createNewFolderClickHandler = function() {

+        if(!checkConfiguration()){

+            return false;

+        }

+		var newFolderName = $.trim($("#newFolderName").val());

+		var newPath = prePath + basePath + getCurrentPath() + "/" + newFolderName;

+        showLoading('creating');

+		service.checkFileExists({

+			path : newPath

+		}, function(data1) {

+			if (data1.status == "noexist" || data1.status == "processing") {

+				service.createFolder({

+					path : newPath

+				}, function(data) {

+					if (isErrorObject(data)) {

+						showAlert(data.errorType);

+						return false;

+					} else {

+                        successOverlay();

+                        refreshFileList(getCurrentPath(), 1);

+                    }

+				});

+			} else if (data1.status == "no_sdcard") {

+                showAlert("no_sdcard", function(){

+                    window.location.reload();

+                });

+			} else if (data1.status == "exist") {

+				$("#createNewFolderErrorLabel").attr('data-trans', 'sd_card_share_setting_exist').text($.i18n.prop("sd_card_share_setting_exist"));

+				hideLoading();

+			}

+		}, function(){

+            errorOverlay();

+        });

+        return true;

+	};

+

+	// 重命名按钮点击事件

+	renameBtnClickHandler = function(oldName) {

+        var oldPath = prePath + basePath + getCurrentPath() + "/" + oldName;

+        if(inSharePath(oldPath, 'sd_share_path_cant_rename')){

+            return false;

+        }

+		showPrompt("sd_card_folder_name_is_null", function() {

+            renamePromptCallback(oldName);

+        }, 160, oldName, checkPromptInput);

+    };

+	

+    function renamePromptCallback(oldName){

+        if(!checkConfiguration()){

+            return false;

+        }

+        var promptInput = $("div#confirm div.promptDiv input#promptInput");

+        var newFolderName = $.trim(promptInput.val());

+        var newPath = prePath + basePath + getCurrentPath() + "/" + newFolderName;

+        service.checkFileExists({

+                path : newPath

+            }, function(data1) {

+				if (data1.status == "noexist" || data1.status == "processing") {

+					hideLoadingButtons();

+					var oldPath = prePath + basePath + getCurrentPath() + "/" + oldName;

+					service.fileRename({

+						oldPath : oldPath,

+						newPath : newPath,

+						path : prePath + basePath + getCurrentPath()

+					}, function(data) {

+						if (isErrorObject(data)) {							

+							showAlert($.i18n.prop(data.errorType));

+							if(data.errorType == "no_exist"){

+								var alertShown = true;

+								refreshFileList(getCurrentPath(), 1, alertShown);

+							} else if(data.errorType == "processing"){

+								//

+							}							

+						} else {

+                            refreshFileList(getCurrentPath(), 1);

+                            successOverlay();

+                        }

+                        showLoadingButtons();

+						return true;

+					});

+				} else if (data1.status == "no_sdcard") {

+					showAlert("no_sdcard", function(){

+                        window.location.reload();

+                    });

+					return false;

+				} else if (data1.status == "exist") {

+					$(".promptErrorLabel").text($.i18n.prop("sd_card_share_setting_exist"));

+					return false;

+				}

+                return true;

+            }, function(){

+                errorOverlay();

+        });

+        return false;

+    }

+	

+    // Prompt弹出框INPUT校验函数

+    function checkPromptInput(){

+        var promptInput = $("div#confirm div.promptDiv input#promptInput");

+        var newFileName = $.trim(promptInput.val());

+        var newPath = (prePath + basePath + getCurrentPath() + "/" + newFileName).replace("//", "/");

+        var checkResult = checkFileNameAndPath(newFileName, newPath);

+        if (1 == checkResult) {

+            $(".promptErrorLabel").text($.i18n.prop("sd_upload_rename_null"));//tip filena is null

+            return false;

+        }else if (2 == checkResult) {

+            $(".promptErrorLabel").text($.i18n.prop("sd_card_path_too_long"));

+            return false;

+        }else if (3 == checkResult) {

+            $(".promptErrorLabel").text($.i18n.prop("check_file_path"));

+            return false;

+        }else{

+            $(".promptErrorLabel").text("");

+            return true;

+        }

+        return true;;

+    }

+

+    hideLoadingButtons = function () {

+        $(".buttons", "#confirm").hide();

+    };

+

+    showLoadingButtons = function () {

+        $(".buttons", "#confirm").show();

+    };

+

+	// 删除按钮点击事件

+	deleteBtnClickHandler = function() {

+        if(!checkConfiguration()){

+            return false;

+        }

+		var files = $("input:checkbox:checked", "#fileList_container");

+		var fileNames = "";

+		if (!files || files.length == 0) {

+			return false;

+		}

+        var hasSharePath = false;

+        $.each(files, function (i, n) {

+            var theFile = $(n).val();

+            if (inSharePath(prePath + basePath + getCurrentPath() + "/" + theFile, {msg: 'sd_share_path_cant_delete', params: [theFile]})) {

+                hasSharePath = true;

+                return false;

+            }

+            return true;

+        });

+        if (hasSharePath) {

+            return false;

+        }

+		showConfirm("confirm_data_delete", function(){

+			$.each(files, function(i, n) {

+				fileNames += $(n).val() + "*";

+			});

+			var thePath = prePath + basePath + getCurrentPath();

+			service.deleteFilesAndFolders({

+				path : thePath,

+				names : fileNames

+			}, function(data) {

+				if (data.status == "failure") {

+					showAlert("delete_folder_failure");

+				}

+				else if(data.status == "no_sdcard"){

+					showAlert("no_sdcard");

+				}

+				else if(data.status == "processing"){

+					showAlert("sd_file_processing_cant_delete");

+				}

+				else if(data.status == "success"){

+					successOverlay();

+				}

+				refreshFileList(getCurrentPath(), 1);

+			}, function(){

+                errorOverlay();

+            });

+		});

+        return true;

+	};

+

+    // 文件上传按钮点击事件

+    fileUploadSubmitClickHandler = function(ifReName) {        

+        if(ifReName){

+            var fileName = $.trim($("div#confirm div.promptDiv input#promptInput").val());

+        }else{

+            var fileName = $(".customfile").attr('title');

+        }

+        var newPath = (basePath + getCurrentPath() + "/" + fileName).replace("//", "/");

+        var fileSize = getFileSize($("#fileField")[0]);

+        if(!checkuploadFileNameAndPath(fileName, newPath, fileSize)){

+            return false;

+        }		

+        doCheckAndUpload(fileName, newPath, fileSize);

+    };

+		

+    function doCheckAndUpload(fileName, newPath, fileSize){

+        service.getSdMemorySizes({}, function(data) {

+			if (isErrorObject(data)) {

+				showAlert(data.errorType);

+				return false;

+			}

+			if (data.availableMemorySize < fileSize) {

+				showAlert("sd_upload_space_not_enough");

+				return false;

+			}

+			$.modal.close();

+			showLoading('uploading', '<span data-trans="note_uploading_not_refresh">' + $.i18n.prop('note_uploading_not_refresh') + '</span>');

+			service.checkFileExists({

+				path : newPath

+			}, function(data1) {

+				if (data1.status == "noexist") {

+					$("#fileUploadForm").attr("action", "/cgi-bin/httpshare/" + URLEncodeComponent(fileName));

+					var currentTime = new Date().getTime();

+					$("#path_SD_CARD_time").val(transUnixTime(currentTime));

+					$("#path_SD_CARD_time_unix").val(Math.round((currentTime - zoneOffsetSeconds * 1000) / 1e3));

+					if(!iframeLoadBinded){

+						bindIframeLoad();

+					}

+					sdIsUploading = true;

+					$("#fileUploadForm").submit();

+				} else if (data1.status == "no_sdcard") {

+					showAlert("no_sdcard", function(){

+						window.location.reload();

+					});

+				} else if (data1.status == "processing") {

+					showAlert("sd_upload_file_is_downloading");//("system is downloading,try later!");

+				}else if (data1.status == "exist") {

+					showPrompt("sd_upload_rename",function(){

+						fileUploadSubmitClickHandler(true);

+					},160, fileName, checkPromptInput, clearUploadInput);

+				}

+			}, function(){

+				errorOverlay();

+			});

+        		return true;

+		});

+	}

+	

+    var iframeLoadBinded = false;

+    function bindIframeLoad(){

+        iframeLoadBinded = true;

+        $('#fileUploadIframe').load(function() {

+			sdIsUploading = false;

+            var txt = $('#fileUploadIframe').contents().find("body").html().toLowerCase();

+            var alertShown = false;

+            if (txt.indexOf('success') != -1) {

+                successOverlay();

+            } else if (txt.indexOf('space_not_enough') != -1) {

+                alertShown = true;

+                showAlert('sd_upload_space_not_enough');

+            } else if (txt.indexOf('data_lost') != -1) {

+                alertShown = true;

+                showAlert('sd_upload_data_lost');

+            } else {

+                errorOverlay();

+            }

+

+            clearUploadInput();

+            refreshFileList(getCurrentPath(), 1, alertShown);

+        });

+    }

+

+	// 更新SD卡容量显示数据

+	updateSdMemorySizes = function() {

+		service.getSdMemorySizes({}, function(data) {

+			if (isErrorObject(data)) {

+				showAlert(data.errorType);

+				return false;

+			}

+			var total = getDisplayVolume(data.totalMemorySize, false);

+			var used = getDisplayVolume(data.totalMemorySize - data.availableMemorySize, false);

+			$("#sd_volumn_used").text(used);

+			$("#sd_volumn_total").text(total);

+            return true;

+		});

+	};

+

+	// 翻页

+	pagination = function(fileTotalSize) {

+		var pagers = generatePager(fileTotalSize, perPage, parseInt(activePage, 10));

+		if(pagerTmpl == null){

+			pagerTmpl = $.template("pagerTmpl", $("#pagerTmpl"));

+		}

+		$(".pager", "#fileListButtonSection").html($.tmpl("pagerTmpl", {data: {pagers : pagers, total : getTotalPages(fileTotalSize, perPage)}}));

+		renderCheckbox();

+		$(".content", "#httpshare_form").translate();

+	};

+

+	// 下载文件是检查文件路径是否包含特殊字符

+	checkFilePathForDownload = function(path){

+        if(!checkConfiguration()){

+            return false;

+        }

+		var idx = path.lastIndexOf('/');

+		var prePath = path.substring(0, idx+1);

+		var name = path.substring(idx+1, path.length);

+		if(checkFileNameChars(prePath, true) && checkFileNameChars(name, false)){

+			return true;

+		}

+		showAlert('sd_card_invalid_chars_cant_download');

+		return false;

+	};

+	

+	gotoLogin = function(){

+		window.location.href="#entry";

+	};

+

+	// 事件绑定

+    function bindEvent(){

+		$('#createNewFolderForm').validate({

+			submitHandler : function() {

+				createNewFolderClickHandler();

+			},

+			rules : {

+				newFolderName : {sd_card_path_too_long:true,check_filefold_name: true}

+			}

+		});

+        $("p.checkbox", "#httpshare_form").die().live('click', function () {

+            addTimeout(function () {

+                checkDeleteBtnStatus();

+            }, 100);

+        });

+        $(".icon-download", "#httpshare_form").die().live("click", function () {

+            return checkFilePathForDownload($(this).attr("filelocal"));

+        });

+        $(".folderTd", "#httpshare_form").die().live("click", function () {

+            return enterFolder($(this).attr("filename"));

+        });

+        $(".fileRename", "#httpshare_form").die().live("click", function () {

+            return renameBtnClickHandler($(this).attr("filename"));

+        });

+        iframeLoadBinded = false;

+    }

+

+

+	// 刷新删除按钮状态

+    function checkDeleteBtnStatus(){

+        var checkedItem = $("p.checkbox.checkbox_selected", '#fileListSection');

+        if(checkedItem.length > 0){

+            enableBtn($('#delete_file_button'));

+        } else {

+            disableBtn($('#delete_file_button'));

+        }

+    }

+

+

+    // 文件名和路径检查

+    function checkFileNameAndPath(filename, path) {

+        if (filename == "" || filename.length > 25) {

+            return 1;

+        }

+        if (path.length >= 200) {

+            return 2;

+        }

+        if (!checkFileNameChars(filename, false)) {

+            return 3;

+        }

+    }

+

+	// 文件名特殊字符检查

+	function checkFileNameChars(filename, isIncludePath) {

+		var ASCStringInvalid = '+/:*?<>\"\'\\|#&`~';

+		if(isIncludePath){

+			ASCStringInvalid = '+:*?<>\"\'\\|#&`~';

+		}

+		var flag = false;

+		var dotFlag = false;

+		var reg = /^\.+$/;

+		for ( var filenamelen = 0; filenamelen < filename.length; filenamelen++) {

+			for ( var ACSlen = 0; ACSlen < ASCStringInvalid.length; ACSlen++) {

+				if (filename.charAt(filenamelen) == ASCStringInvalid.charAt(ACSlen)) {

+					flag = true;

+					break;

+				}

+			}

+			if (reg.test(filename)) {

+				dotFlag = true;

+			}

+			if (flag || dotFlag) {

+				return false;

+			}

+		}

+		return true;

+	}

+		

+	

+    function checkuploadFileNameAndPath(fileName, newPath, fileSize){

+        if(!checkConfiguration()){

+            return false;

+        }

+		

+		if (typeof fileName == "undefined" || fileName == '' || fileName == $.i18n.prop("no_file_selected")) {

+            showAlert("sd_no_file_selected");

+			return false;

+		}

+		if (newPath.length >= 200) {

+			showAlert("sd_card_path_too_long");

+			return false;

+		}

+		

+		if (fileSize/1024/1024/1024 > 2){  //no more than 2G

+			showAlert("sd_file_size_too_big");

+			return false;

+		}		

+		

+		if (fileName.indexOf('*') >= 0){  //no *

+			showAlert("sd_file_name_invalid");

+			return false;

+		}

+		return true;

+	}

+	

+

+	//清空上传控件

+    function clearUploadInput(){

+        $("#fileField").closest('.customfile').before('<input id="fileField" name="filename" maxlength="200" type="file" dir="ltr"/>').remove();

+        addTimeout(function(){

+            $("#fileField").customFileInput();

+        }, 0);

+        $("#uploadBtn", "#uploadSection").attr("data-trans", "browse_btn").html($.i18n.prop('browse_btn'));

+        $(".customfile", "#uploadSection").removeAttr("title");

+        $(".customfile span.customfile-feedback", "#uploadSection")

+            .html('<span data-trans="no_file_selected">'+$.i18n.prop('no_file_selected')+'</span>')

+            .attr('class', 'customfile-feedback');

+    }

+		

+	

+    function getCurrentPath(){

+        return currentPath;

+    }

+

+    function setCurrentPath(path){

+        if(path.lastIndexOf("/") == path.length - 1){

+            currentPath = path.substring(0, path.length - 1);

+        } else {

+            currentPath = path;

+        }

+    }

+	

+	

+    function getFileSize(object){

+        var isIE = /msie/i.test(navigator.userAgent) && !window.opera; 

+        if (isIE) {  //如果是ie

+            var objValue = object.value;

+            try {  

+                var fileSysObj = new ActiveXObject("Scripting.FileSystemObject");  

+                fileLenth = parseInt(fileSysObj.GetFile(objValue).size);

+                } catch (e) {  //('IE内核取不到长度'); 

+                fileLenth	= 1;					

+            } 

+        }else{  //其他

+            try{//对于非IE获得要上传文件的大小

+                fileLenth = parseInt(object.files[0].size);

+                }catch (e) {

+                fileLenth=1;  //获取不到取-1

+            }

+        }

+        return fileLenth;

+    } 

+		

+	function init() {

+		var container = $('#container')[0];

+		ko.cleanNode(container);

+		var fwVm = new HttpShareViewModel();

+		ko.applyBindings(fwVm, container);

+        bindEvent();

+	}

+

+	

+    jQuery.validator.addMethod("check_filefold_name", function(value, element, param) {

+        var result = checkFileNameChars(value, false);

+        return this.optional(element) || result;

+    });

+	

+    jQuery.validator.addMethod("sd_card_path_too_long", function(value, element, param) {

+        var newFolderName = $.trim($("#newFolderName").val());

+        var newPath = prePath + basePath + getCurrentPath() + "/" + newFolderName;

+        var result = true;

+        if (newPath.length >= 200) {

+            result = false;

+        }

+        return this.optional(element) || result;

+    });

+	

+	return {

+		init : init

+	};

+});

+

+define("ussd","set service knockout jquery".split(" "), function (set, fnc, libko, libjq) {

+    var time_interval = 0;

+    var initFlg = true;

+    var numTimeout = 0;

+    var replyFlg = false;

+    var ussd_action = 1;

+

+    function init() {

+        var container = libjq('#container')[0];

+        libko.cleanNode(container);

+        var vm = new vmUSSD();

+        libko.applyBindings(vm, container);

+

+    }

+    var USSDLocation = {

+        SEND: 0,

+        REPLY: 1

+    };

+    function vmUSSD() {

+        var target = this;

+

+        target.hasUpdateCheck = set.HAS_UPDATE_CHECK;

+        target.ussd_action = libko.observable(ussd_action);

+        target.USSDLocation = libko.observable(USSDLocation.SEND);

+        target.USSDReply = libko.observable("");

+        target.USSDSend = libko.observable("");

+        target.hasDdns = set.DDNS_SUPPORT;

+

+        function checkTimeout() {

+            if (replyFlg) {

+                replyFlg = true;

+                window.clearInterval(time_interval);

+                numTimeout = 0;

+            } else {

+                if (numTimeout > 28) {

+                    replyFlg = true;

+                    window.clearInterval(time_interval);

+                    showAlert("ussd_operation_timeout");

+                    target.USSDReply("");

+                    target.USSDSend("");

+                    target.USSDLocation(USSDLocation.SEND);

+                    numTimeout = 0;

+

+                } else {

+                    numTimeout++;

+                }

+

+            }

+        };

+

+        target.sendToNet = function () {

+            numTimeout = 0;

+            window.clearInterval(time_interval);

+            var command = target.USSDSend();

+

+            var idx_t = 0;

+            var indexChar;

+            for (idx_t = 0; idx_t < command.length; ) { //corem0418, delte left blanks and right blanks

+                indexChar = command.charAt(idx_t);

+                if (indexChar == ' ') {

+                    if (command.length > 1) {

+                        command = command.substr(idx_t + 1);

+                    } else {

+                        command = ''; // string is filled with blank

+                        break;

+                    }

+                } else {

+                    break;

+                }

+            }

+

+            for (idx_t = command.length - 1; idx_t >= 0 && command.length > 0; --idx_t) {

+                indexChar = command.charAt(idx_t);

+                if (indexChar == ' ') {

+                    if (command.length > 1) {

+                        command = command.substr(0, idx_t);

+                    } else {

+                        command = ''; // string is filled with blank

+                        break;

+                    }

+                } else {

+                    break;

+                }

+            }

+

+            if (('string' != typeof(command)) || ('' == command)) {

+                showAlert("ussd_error_input");

+                return;

+            }

+

+            showLoading('waiting');

+

+            var tmp = {};

+            tmp.operator = "ussd_send";

+            tmp.strUSSDCommand = command;

+            tmp.sendOrReply = "send";

+

+            fnc.getUSSDResponse(tmp, function (result, content) {

+                hideLoading();

+                if (result) {

+                    USSD_reset();

+                    target.USSDLocation(USSDLocation.REPLY);

+                    target.ussd_action(content.ussd_action);

+                    libjq("#USSD_Content").val(decodeMessage(content.data, true));

+                    replyFlg = false;

+                    numTimeout = 0;

+                } else {

+                    showAlert(content);

+                }

+            });

+        };

+

+        target.replyToNet = function () {

+            numTimeout = 0;

+            window.clearInterval(time_interval);

+            var command = target.USSDReply();

+

+            var idx_t = 0;

+            var indexChar;

+            for (idx_t = 0; idx_t < command.length; ) { //corem0418, delte left blanks and right blanks

+                indexChar = command.charAt(idx_t);

+                if (indexChar == ' ') {

+                    if (command.length > 1) {

+                        command = command.substr(idx_t + 1);

+                    } else {

+                        command = ''; // string is filled with blank

+                        break;

+                    }

+                } else {

+                    break;

+                }

+            }

+

+            for (idx_t = command.length - 1; idx_t >= 0 && command.length > 0; --idx_t) {

+                indexChar = command.charAt(idx_t);

+                if (indexChar == ' ') {

+                    if (command.length > 1) {

+                        command = command.substr(0, idx_t);

+                    } else {

+                        command = ''; // string is filled with blank

+                        break;

+                    }

+                } else {

+                    break;

+                }

+            }

+

+            if (('string' != typeof(command)) || ('' == command)) {

+                showAlert("ussd_error_input");

+                return;

+            }

+

+            showLoading('waiting');

+

+            var tmp = {};

+            tmp.operator = "ussd_reply";

+            tmp.strUSSDCommand = command;

+            tmp.sendOrReply = "reply";

+

+            fnc.getUSSDResponse(tmp, function (result, content) {

+                hideLoading();

+                if (result) {

+                    target.ussd_action(content.ussd_action);

+                    libjq("#USSD_Content").val(decodeMessage(content.data, true));

+                    replyFlg = false;

+                    USSD_reset();

+                    numTimeout = 0;

+                } else {

+                    showAlert(content);

+                }

+            });

+        };

+

+        USSD_reset = function () {

+            target.USSDReply("");

+            target.USSDSend("");

+        };

+        USSD_cancel = function () {

+            fnc.USSDReplyCancel(function (result) {});

+        };

+

+        target.noReplyCancel = function () {

+            numTimeout = 0;

+            replyFlg = true;

+            window.clearInterval(time_interval);

+            fnc.USSDReplyCancel(function (result) {

+                if (result) {

+                    USSD_reset();

+                    target.USSDLocation(USSDLocation.SEND);

+                } else {

+                    showAlert("ussd_fail");

+                }

+            });

+        };

+

+        //如果首次进入USSD菜单,先发送USSD取消命令,进行初始化

+        if (initFlg) {

+            USSD_cancel();

+            initFlg = false;

+        }

+    }

+

+    return {

+        init: init

+    };

+});

+

+

+define("phonebook","underscore jquery knockout set service jq_chosen".split(" "),

+

+    function (_, $, ko, config, service, chosen) {

+

+    var locationValue = {

+        SIM: "0",

+        DEVICE: "1"

+    };

+    var pageState = {

+        LIST: 0,

+        NEW: 1,

+        EDIT: 2,

+        VIEW: 3,

+        SEND_MSM: 4

+    };

+    //存储位置选项

+    var saveLocationOpts = function (hasSIMCard) {

+        var opts = [];

+        opts.push(new Option($.i18n.prop("device_book"), locationValue.DEVICE));

+        if (hasSIMCard) {

+            opts.push(new Option($.i18n.prop("sim_book"), locationValue.SIM));

+        }

+        return opts;

+    };

+

+    function getCurrentGroup() {

+        return $("#selectedFilterGroup").val();

+    }

+    //列表模板对应的Columns

+    var templateColumns = {

+        cardColumns: [{

+                rowText: "index",

+                display: false

+            }, {

+                rowText: "name"

+            }, {

+                rowText: "mobile_phone_number"

+            }, {

+                rowText: "home_phone_number"

+            }

+        ],

+        listColumns: [{

+                columnType: "checkbox",

+                headerTextTrans: "number",

+                rowText: "index",

+                width: "10%"

+            }, {

+                headerTextTrans: "name",

+                rowText: "name",

+                width: "25%",

+                sortable: true

+            }, {

+                columnType: "image",

+                headerTextTrans: "save_location",

+                rowText: "imgLocation",

+                width: "20%",

+                sortable: true

+            }, {

+                headerTextTrans: "mobile_phone_number",

+                rowText: "mobile_phone_number",

+                width: "30%",

+                sortable: true

+            }, {

+                headerTextTrans: "group",

+                rowText: "transGroup",

+                width: "15%",

+                sortable: true,

+                needTrans: true

+            }

+        ]

+    };

+    //分组选项

+    var groupOpts = function () {

+        var opts = [];

+        opts.push(new Option($.i18n.prop("common"), "common"));

+        opts.push(new Option($.i18n.prop("family"), "family"));

+        opts.push(new Option($.i18n.prop("friend"), "friend"));

+        opts.push(new Option($.i18n.prop("colleague"), "colleague"));

+        return opts;

+    };

+

+    var _phoneBookStopSMSSending = false;

+

+    function pbViewMode() {

+        var target = this;

+

+        //property for common

+        target.pageState = ko.observable(pageState.LIST);

+        target.initFail = ko.observable(true);

+        target.hasSms = ko.observable(config.HAS_SMS);

+

+        var smsHasCapability = true;

+        var smsLeftCount = 0;

+

+        //property for list

+        var capacity = {

+            simMaxNameLen: 0,

+            simMaxNumberLen: 0,

+            IsSimCardFull: true,

+            IsDeviceFull: true,

+            Used: 0,

+            Capacity: 0,

+            Ratio: "(0/0)"

+        };

+        target.capacity = ko.observable(capacity);

+        target.phoneBookCapacity = ko.observable(capacity.Ratio);

+        target.books = ko.observableArray();

+        //列表模板创建

+        target.gridTemplate = new ko.simpleGrid.viewModel({

+            tableClass: "table-fixed",

+            data: target.books(),

+            idName: "index",

+            columns: templateColumns.listColumns,

+            defaultSortField: "name",

+            defaultSortDirection: "ASC",

+            pageSize: 10,

+            tmplType: 'list',

+            searchColumns: ["name", "mobile_phone_number"],

+            primaryColumn: "mobile_phone_number",

+            showPager: true,

+            rowClickHandler: function (dataId) {

+                target.editBooks(dataId, 'view');

+            },

+            deleteHandler: function (dataId) {

+                target.deleteOneBook(dataId);

+            },

+            changeTemplateHandler: function () {

+                target.changeTemplate();

+            }

+        });

+

+        //property for edit or new

+        target.locations = ko.observableArray();

+        target.originLocation = "";

+        target.selectedLocation = ko.observable(locationValue.DEVICE);

+        target.locationTrans = ko.observable();

+        target.locationTransText = ko.observable();

+        target.index = ko.observable(-1);

+        target.name = ko.observable("");

+        target.nameMaxLength = ko.computed(function () {

+            var max = getNameMaxLength();

+            var name = target.name().substring(0, max);

+            target.name(name);

+            return getNameMaxLength();

+        });

+        function getNameMaxLength() {

+            var max = 22;

+            if (target.selectedLocation() == locationValue.DEVICE) {

+                var encodeType = getEncodeType(target.name());

+                if ("UNICODE" == encodeType.encodeType || encodeType.extendLen > 0) {

+                    max = 11;

+                } else {

+                    max = 22;

+                }

+                //max = 22;

+            } else {

+                //对"^"需要按照2个字符处理

+                var encodeType = getEncodeType(target.name());

+                if ("UNICODE" == encodeType.encodeType || encodeType.extendLen > 0) {

+                    max = (target.capacity().simMaxNameLen / 2) - 1;

+                } else {

+                    max = target.capacity().simMaxNameLen;

+                }

+            }

+            return max;

+        }

+

+        target.mobile_phone_number = ko.observable("");

+        target.mobileMaxLength = ko.computed(function () {

+            var max = getMobileMaxLength();

+            var mobileNumber = target.mobile_phone_number().substring(0, max);

+            target.mobile_phone_number(mobileNumber);

+            return getMobileMaxLength();

+        });

+        function getMobileMaxLength() {

+            var max = 40;

+            if (target.selectedLocation() == locationValue.DEVICE) {

+                max = 40;

+            } else {

+                max = target.capacity().simMaxNumberLen;

+            }

+            return max;

+        }

+

+        target.home_phone_number = ko.observable("");

+        target.office_phone_number = ko.observable("");

+        target.mail = ko.observable("");

+        target.transEditAreaTitle = ko.dependentObservable(function () {

+            var state = target.pageState();

+            if (state == pageState.EDIT) {

+                return "edit";

+            } else if (state == pageState.NEW) {

+                return "new";

+            } else if (state == pageState.VIEW) {

+                return "view";

+            }

+        });

+        var groups = groupOpts();

+        target.groups = ko.observableArray(groups);

+        target.selectedGroup = ko.observable();

+        target.groupTrans = ko.observable();

+        target.groupTransText = ko.observable();

+

+        target.selectedFilterGroup = ko.observable('all');

+        target.selectedFilterGroupChangeHandler = function () {

+            target.selectedFilterGroup($("#selectedFilterGroup").val());

+            getPhoneBookReady();

+        };

+

+        //property for sendMessage

+        target.showErrorInfo = ko.observable(false);

+        target.messageContent = ko.observable("");

+        target.messageCount = ko.computed(function () {

+            var msgInput = $("#txtSmsContent", "#sendMessage");

+            var msgInputDom = msgInput[0];

+            target.messageContent();

+            var strValue = msgInput.val();

+            var encodeType = getEncodeType(strValue);

+            var maxLength = encodeType.encodeType == 'UNICODE' ? 335 : 765;

+            if (strValue.length + encodeType.extendLen > maxLength) {

+                var scrollTop = msgInputDom.scrollTop;

+                var insertPos = getInsertPos(msgInputDom);

+                var moreLen = strValue.length + encodeType.extendLen - maxLength;

+                var insertPart = strValue.substr(insertPos - moreLen > 0 ? insertPos - moreLen : 0, moreLen);

+                var reversed = insertPart.split('').reverse();

+                var checkMore = 0;

+                var cutNum = 0;

+                for (var i = 0; i < reversed.length; i++) {

+                    if (getEncodeType(reversed[i]).extendLen > 0) {

+                        checkMore += 2;

+                    } else {

+                        checkMore++;

+                    }

+                    if (checkMore >= moreLen) {

+                        cutNum = i + 1;

+                        break;

+                    }

+                }

+                var iInsertToStartLength = insertPos - cutNum;

+

+                target.messageContent(strValue.substr(0, iInsertToStartLength) + strValue.substr(insertPos));

+                if (target.messageContent().length > maxLength) {

+                    target.messageContent(target.messageContent().substr(0, maxLength));

+                }

+                setInsertPos(msgInputDom, iInsertToStartLength);

+                msgInputDom.scrollTop = scrollTop;

+            }

+            pbDraftListener();

+            var newValue = $(msgInputDom).val();

+            var newEncodeType = getEncodeType(newValue);

+            var newMaxLength = newEncodeType.encodeType == 'UNICODE' ? 335 : 765;

+            if (newValue.length + newEncodeType.extendLen >= newMaxLength) {

+                $("#msgCount").addClass("colorRed");

+            } else {

+                $("#msgCount").removeClass("colorRed");

+            }

+            return "(" + (newValue.length + newEncodeType.extendLen) + "/" + newMaxLength + ")" + "(" + getSmsCount(newValue) + "/5)";

+        });

+

+        target.clear = function (isNeedInit) {

+            if (target.pageState() == pageState.SEND_MSM) {

+                smsPageCheckDraft(clearPhonebookForm, isNeedInit);

+            } else {

+                clearPhonebookForm(isNeedInit);

+            }

+            config.resetContentModifyValue();

+        };

+

+        //通过按钮返回列表状态事件处理

+        target.btnClear = function (isNeedInit) {

+            if (target.pageState() == pageState.SEND_MSM) {

+                smsPageCheckDraft(clearPhonebookForm, isNeedInit);

+                config.resetContentModifyValue();

+            } else if ((target.pageState() == pageState.NEW || target.pageState() == pageState.EDIT) && (target.preContent.location != target.selectedLocation()

+                     || target.preContent.name != target.name()

+                     || target.preContent.mobile_phone_number != target.mobile_phone_number()

+                     || target.preContent.home_phone_number != target.home_phone_number()

+                     || target.preContent.office_phone_number != target.office_phone_number()

+                     || target.preContent.mail != target.mail()

+                     || target.preContent.group != target.selectedGroup())) {

+                showConfirm("leave_page_info", {

+                    ok: function () {

+                        clearPhonebookForm(isNeedInit);

+                        config.resetContentModifyValue();

+                    },

+                    no: function () {

+                        return false;

+                    }

+                });

+            } else {

+                clearPhonebookForm(isNeedInit);

+                config.resetContentModifyValue();

+            }

+        };

+

+        function clearPhonebookForm(isNeedInit) {

+            $("#frmPhoneBook").hide();

+            target.pageState(pageState.LIST);

+            target.index(-1);

+            target.name("");

+            target.mobile_phone_number("");

+            target.home_phone_number("");

+            target.office_phone_number("");

+            target.mail("");

+            target.messageContent("");

+            if (true == isNeedInit) {

+                refreshPage();

+            }

+            target.gridTemplate.clearAllChecked();

+            clearValidateMsg();

+            $("#books ").translate();

+            $("#frmPhoneBook").show();

+        }

+

+        //检查SIM卡状态

+        target.checkHasSIMCard = function (showMsg) {

+            var status = service.getStatusInfo();

+            if (status.simStatus != "modem_init_complete") {

+                if (showMsg) {

+                    showAlert("sim_removed", function () {

+                        target.pageState(pageState.LIST);

+                        target.clear(true);

+                    });

+                }

+                return false;

+            }

+            return true;

+        };

+

+        //保存电话本事件

+        target.save = function () {

+            var saveBook = function (index) {

+                var isSaveInSIM = (location == locationValue.SIM);

+                if (isSaveInSIM) {

+                    if (!target.checkHasSIMCard(true)) {

+                        return;

+                    }

+                }

+                if (target.pageState() == pageState.NEW || (target.pageState() == pageState.EDIT && location != target.originLocation)) {

+                    if (isSaveInSIM) {

+                        if (target.capacity().IsSimCardFull) {

+                            showAlert("sim_full");

+                            return;

+                        }

+                    } else {

+                        if (target.capacity().IsDeviceFull) {

+                            showAlert("device_full");

+                            return;

+                        }

+                    }

+                }

+                var name = target.name();

+                var mobile_phone_number = target.mobile_phone_number();

+                if ($.trim(name) == "" || $.trim(mobile_phone_number) == "") {

+                    return;

+                }

+                showLoading('saving');

+                var params = {};

+                params.location = location;

+                params.index = index;

+                params.name = name;

+                params.mobile_phone_number = mobile_phone_number;

+                if (!isSaveInSIM) {

+                    params.home_phone_number = target.home_phone_number();

+                    params.office_phone_number = target.office_phone_number();

+                    params.mail = target.mail();

+                    params.group = target.selectedGroup();

+                }

+                if (target.selectedLocation() != target.originLocation) {

+                    params.delId = target.index();

+                }

+                service.savePhoneBook(params, target.callback);

+            }

+            var location = target.selectedLocation();

+            var editIndex = (location == target.originLocation) ? target.index() : -1;

+            if (location == locationValue.SIM && target.originLocation == locationValue.DEVICE) {

+                showConfirm("change_device_to_sim_confirm", function () {

+                    saveBook(editIndex);

+                });

+            } else {

+                saveBook(editIndex);

+            }

+        };

+        //打开添加电话本记录页面事件

+        target.openNewPage = function () {

+            if (target.pageState() == pageState.SEND_MSM) {

+                pbDraftListener();

+                smsPageCheckDraft(openNewPageAct, false);

+            } else if (target.pageState() == pageState.EDIT && (target.preContent.location != target.selectedLocation()

+                     || target.preContent.name != target.name()

+                     || target.preContent.mobile_phone_number != target.mobile_phone_number()

+                     || target.preContent.home_phone_number != target.home_phone_number()

+                     || target.preContent.office_phone_number != target.office_phone_number()

+                     || target.preContent.mail != target.mail()

+                     || target.preContent.group != target.selectedGroup())) {

+                showConfirm("leave_page_info", {

+                    ok: function () {

+                        openNewPageAct(false);

+                    },

+                    no: function () {

+                        return false;

+                    }

+                });

+            } else {

+                openNewPageAct(false);

+            }

+        };

+        function openNewPageAct(isNeedInit) {

+            target.pageState(pageState.NEW);

+            target.selectedLocation(locationValue.DEVICE);

+            target.originLocation = "";

+            if (target.checkHasSIMCard(false)) {

+                target.locations(saveLocationOpts(true));

+            } else {

+                target.locations(saveLocationOpts(false));

+            }

+            var group = getCurrentGroup();

+            if (group != "all") {

+                target.selectedGroup(group);

+            } else {

+                target.selectedGroup("common");

+            }

+            target.name("");

+            target.mobile_phone_number("");

+            target.home_phone_number("");

+            target.office_phone_number("");

+            target.mail("");

+            target.index(-1);

+            target.dynamicTranslate();

+            preOpenEditPage();

+        }

+        //打开添加电话本记录编辑页面事件

+        target.openPage = function (option) {

+            var index;

+            if (target.pageState() == pageState.LIST) {

+                var result = target.checkSelect(option);

+                if (!result.isCorrectData)

+                    return;

+                index = result.selectedIds[0];

+            } else {

+                index = target.index();

+            }

+            target.editBooks(index, option);

+        };

+        //打开添加电话本记录查看页面事件

+        target.openViewPage = function () {

+            target.openPage("view");

+        };

+        //打开添加电话本记录查看页面事件

+        target.openEditPage = function () {

+            target.openPage("edit");

+            if ($.browser.mozilla) {

+                $("#txtName, #txtMobile").removeAttr('maxlength');

+            }

+            preOpenEditPage();

+        };

+        //编辑电话本事件处理

+        target.editBooks = function (selectedId, option) {

+            if (!selectedId)

+                return;

+

+            if (target.checkHasSIMCard(false)) {

+                target.locations(saveLocationOpts(true));

+            } else {

+                target.locations(saveLocationOpts(false));

+            }

+            var data = target.books();

+            for (var i = 0; i < data.length; i++) {

+                var n = data[i];

+                if (n.index == selectedId) {

+                    target.index(n.index);

+                    target.selectedLocation(n.location);

+                    target.originLocation = n.location;

+                    var trans = (n.location == locationValue.DEVICE) ? "device" : "sim";

+                    target.locationTrans(trans);

+                    var transText = $.i18n.prop("trans");

+                    target.locationTransText(transText);

+                    target.name(n.name);

+                    target.mobile_phone_number(n.mobile_phone_number);

+                    target.home_phone_number(n.home_phone_number);

+                    target.office_phone_number(n.office_phone_number);

+                    target.mail(n.mail);

+                    target.selectedGroup(n.group);

+                    target.groupTrans("group_" + n.group);

+                    target.groupTransText($.i18n.prop(target.groupTrans()));

+                    if (option == "edit") {

+                        target.pageState(pageState.EDIT);

+                    } else {

+                        target.pageState(pageState.VIEW);

+                    }

+                    break;

+                }

+            }

+            target.dynamicTranslate();

+

+            if (target.selectedLocation() == locationValue.SIM) {

+                target.checkHasSIMCard(true)

+            }

+        };

+        //翻译编辑区域

+        target.dynamicTranslate = function () {

+            $("#container").translate();

+        };

+        //删除一条电话本事件处理(card模式使用)

+        target.deleteOneBook = function (index) {

+            showConfirm("confirm_pb_delete", function () {

+                showLoading('deleting');

+                var params = {};

+                params.indexs = [String(index)];

+                service.deletePhoneBooks(params, target.callback);

+            });

+            return false;

+        };

+        //删除一条电话本事件处理

+        target.deleteBook = function () {

+            target.deleteOneBook(target.index());

+        };

+        //删除一条或多条电话本事件处理

+        target.deleteBooks = function () {

+            var result = target.checkSelect("delete");

+            if (!result.isCorrectData)

+                return;

+            showConfirm("confirm_pb_delete", function () {

+                showLoading('deleting');

+                var params = {};

+                params.indexs = result.selectedIds;

+                service.deletePhoneBooks(params, target.callback);

+            });

+        };

+        //判断电话本选中

+        target.checkSelect = function (pState) {

+            var ids;

+            if ("send" == pState) {

+                ids = target.gridTemplate.selectedPrimaryValue();

+            } else {

+                ids = target.gridTemplate.selectedIds();

+            }

+

+            var isCorrectData = true;

+            if (ids.length == 0) {

+                showAlert("no_data_selected");

+                isCorrectData = false;

+            } else if ("edit" == pState || "view" == pState) {

+                if (ids.length > 1) {

+                    showAlert("too_many_data_selected");

+                    isCorrectData = false;

+                }

+            } else if ("send" == pState) {

+                if (ids.length > 5) {

+                    showAlert("max_send_number");

+                    isCorrectData = false;

+                }

+            }

+            return {

+                selectedIds: ids,

+                isCorrectData: isCorrectData

+            };

+        };

+        //全部删除电话本事件处理

+        target.deleteAllBooks = function () {

+            showConfirm("confirm_data_delete", function () {

+                showLoading('deleting');

+                var group = getCurrentGroup();

+                var params = {};

+                if (group == "all") {

+                    params.location = 2;

+                    service.deleteAllPhoneBooks(params, target.callback);

+                } else {

+                    params.location = 3;

+                    params.group = group;

+                    service.deleteAllPhoneBooksByGroup(params, target.callback);

+                }

+            });

+        };

+

+        target.callback = function (data) {

+            if (data && data.result == "success") {

+                target.clear(true);

+                $("#books ").translate();

+                renderCheckbox();

+                successOverlay(null, true);

+            } else {

+                errorOverlay();

+            }

+        };

+        //变换显示方式事件处理

+        target.changeTemplate = function () {

+            if (target.gridTemplate.tmplType == "card") {

+                target.gridTemplate.tmplType = "list";

+                target.gridTemplate.pageSize = 10;

+                target.gridTemplate.columns = templateColumns.listColumns;

+            } else {

+                target.gridTemplate.tmplType = "card";

+                target.gridTemplate.pageSize = 10;

+                target.gridTemplate.columns = templateColumns.cardColumns;

+            }

+            refreshPage();

+            $("#books ").translate();

+        };

+        //显示发送短信页面

+        target.openSendMessagePage = function () {

+            if (pageState.SEND_MSM == target.pageState()) {

+                return;

+            }

+            if ((target.pageState() == pageState.EDIT || pageState.NEW == target.pageState()) && (target.preContent.location != target.selectedLocation()

+                     || target.preContent.name != target.name()

+                     || target.preContent.mobile_phone_number != target.mobile_phone_number()

+                     || target.preContent.home_phone_number != target.home_phone_number()

+                     || target.preContent.office_phone_number != target.office_phone_number()

+                     || target.preContent.mail != target.mail()

+                     || target.preContent.group != target.selectedGroup())) {

+                showConfirm("leave_page_info", {

+                    ok: function () {

+                        openSendMessagePageAct();

+                    },

+                    no: function () {

+                        return false;

+                    }

+                });

+            } else {

+                openSendMessagePageAct();

+            }

+        };

+

+        function openSendMessagePageAct() {

+            if (pageState.NEW == target.pageState()) {

+                target.pageState(pageState.SEND_MSM);

+                showAlert("no_data_selected");

+                target.clear();

+                return;

+            }

+            var selectedNumber = null;

+            if (pageState.LIST == target.pageState()) {

+                var result = target.checkSelect("send");

+                if (!result.isCorrectData)

+                    return;

+                selectedNumber = result.selectedIds;

+            } else {

+                selectedNumber = target.mobile_phone_number();

+            }

+

+            var select = $("#chosenUserList .chosen-select-deselect");

+            select.empty();

+            var options = [];

+            var tmp = [];

+            for (var j = 0; j < config.phonebook.length; j++) {

+                var book = config.phonebook[j];

+                if ($.inArray(book.pbm_number, tmp) == -1) {

+                    options.push(new Option(book.pbm_name + "/" + book.pbm_number, book.pbm_number, false, true));

+                    tmp.push(book.pbm_number);

+                } else {

+                    for (var i = 0; i < options.length; i++) {

+                        if (options[i].value == book.pbm_number) {

+                            options[i].text = book.pbm_name + "/" + book.pbm_number;

+                            break;

+                        }

+                    }

+                }

+            }

+            var opts = "";

+            $.each(options, function (i, e) {

+                opts += "<option value='" + HTMLEncode(e.value) + "'>" + HTMLEncode(e.text) + "</option>";

+            });

+            select.append(opts);

+            select.chosen({

+                max_selected_options: 5,

+                search_contains: true,

+                width: '545px'

+            });

+            $("#chosenUserSelect").val(selectedNumber);

+            $("#chosenUserSelect").trigger("chosen:updated.chosen");

+            config.resetContentModifyValue();

+            pbDraftListener();

+            target.pageState(pageState.SEND_MSM);

+        }

+

+        //发送短信

+        target.sendMessage = function () {

+            service.getSmsCapability({}, function (capability) {

+                var hasCapability = capability.nvUsed < capability.nvTotal;

+                if (!hasCapability) {

+                    showAlert("sms_capacity_is_full_for_send");

+                    return false;

+                }

+                var numbers = syncSelectAndChosen($("select#chosenUserSelect"), $('.search-choice', '#chosenUserSelect_chosen'));

+                if (numbers.length + capability.nvUsed > capability.nvTotal) {

+                    showAlert({

+                        msg: "sms_capacity_will_full_just",

+                        params: [capability.nvTotal - capability.nvUsed]

+                    });

+                    return false;

+                }

+                target.sendMessageAction();

+                return true;

+            });

+        };

+

+        target.sendMessageAction = function () {

+            var numbers = syncSelectAndChosen($("select#chosenUserSelect"), $('.search-choice', '#chosenUserSelect_chosen'));

+

+            if (!numbers || numbers.length == 0) {

+                target.showErrorInfo(true);

+                var timer = addTimeout(function () {

+                    target.showErrorInfo(false);

+                    window.clearTimeout(timer);

+                }, 5000);

+                return;

+            }

+            var content = target.messageContent();

+            var sentCount = 0;

+            var failCount = 0;

+            if (numbers.length > 1) {

+                showLoading("sending", "<button id='btnStopSending' onclick='phoneBookStopSMSSending();' class='btn btn-primary'>"

+                     + $.i18n.prop("sms_stop_sending")

+                     + "</button>");

+            } else {

+                showLoading('sending');

+            }

+            var callback = function (data) {

+                sentCount++;

+                if (sentCount == numbers.length) {

+                    $("#chosenUserSelect").val("");

+                    target.messageContent("");

+                    config.CONTENT_MODIFIED.modified = false;

+                    if (failCount == 0) {

+                        successOverlay();

+                        location.hash = "#msg_list";

+                    } else {

+                        var msg = $.i18n.prop("success_info") + $.i18n.prop("colon") + (sentCount - failCount)

+                             + "<br/>" + $.i18n.prop("error_info") + $.i18n.prop("colon") + (failCount);

+                        showAlert(msg, function () {

+                            location.hash = "#msg_list";

+                        });

+                    }

+

+                } else {

+                    sendSMS();

+                }

+            }

+            _phoneBookStopSMSSending = false;

+            var sendSMS = function () {

+                if (_phoneBookStopSMSSending) {

+                    hideLoading();

+                    return;

+                }

+                if ((sentCount + 1) == numbers.length) {

+                    $("#loading #loading_container").html("");

+                }

+                service.sendSMS({

+                    number: numbers[sentCount],

+                    message: content,

+                    id: -1

+                }, function (data) {

+                    callback(data);

+                }, function (data) {

+                    failCount++;

+                    callback(data);

+                });

+            };

+            sendSMS();

+        };

+        //清除搜索关键字事件

+        target.clearSearchKey = function () {

+            target.gridTemplate.searchInitStatus(true);

+            target.gridTemplate.searchKey($.i18n.prop("search"));

+            $("#ko_grid_search_txt").addClass("ko-grid-search-txt-default").attr("data-trans", "search");

+        };

+        //点击搜索输入框事件

+        target.searchTextClick = function () {

+            var searchText = $("#ko_grid_search_txt");

+            if (searchText.hasClass("ko-grid-search-txt-default")) {

+                target.gridTemplate.searchKey("");

+                target.gridTemplate.searchInitStatus(false);

+                searchText.removeClass("ko-grid-search-txt-default").removeAttr("data-trans");

+            }

+        };

+        //离开搜索输入框事件

+        target.searchTextBlur = function () {

+            var txt = $.trim(target.gridTemplate.searchKey()).toLowerCase();

+            if (txt == "") {

+                target.clearSearchKey();

+            }

+        };

+        //当前表格是否有数据

+        target.hasData = ko.computed(function () {

+            return target.gridTemplate.afterSearchData().length > 0;

+        });

+        //当前表格是否有选中的数据

+        target.hasChecked = ko.computed(function () {

+            return target.gridTemplate.checkedCount() > 0;

+        });

+        //是否可以点击发送按钮

+        target.canSend = ko.computed(function () {

+            var checked = target.gridTemplate.checkedCount();

+            if (!target.checkHasSIMCard(false)) {

+                return false;

+            }

+            return (checked > 0 && checked <= 5);

+        });

+

+        //发送短信时,选择用户变化的监控事件

+        target.draftListenerEvent = function () {

+            pbDraftListener();

+        };

+        //文档内容监听,判断是否修改过

+        function pbDraftListener() {

+            var smsHasCapability = true;

+            if (smsHasCapability) {

+                var content = target.messageContent();

+                var hasContent = false;

+                var numbers = getSelectValFromChosen($('.search-choice', '#chosenUserSelect_chosen'));

+                var noContactSelected = !(numbers && numbers.length > 0);

+                if (typeof content == "undefined" || content == '') {

+                    config.resetContentModifyValue();

+                    return false;

+                } else {

+                    hasContent = true;

+                }

+                if (hasContent && !noContactSelected) {

+                    config.CONTENT_MODIFIED.modified = true;

+                    config.CONTENT_MODIFIED.message = 'sms_to_save_draft';

+                    config.CONTENT_MODIFIED.callback.ok = saveDraftAction;

+                    config.CONTENT_MODIFIED.callback.no = $.noop;

+                    config.CONTENT_MODIFIED.data = {

+                        content: content,

+                        numbers: numbers

+                    };

+                    return false;

+                }

+                if (hasContent && noContactSelected) {

+                    config.CONTENT_MODIFIED.modified = true;

+                    config.CONTENT_MODIFIED.message = 'sms_no_recipient';

+                    config.CONTENT_MODIFIED.callback.ok = $.noop;

+                    config.CONTENT_MODIFIED.callback.no = function () {

+                        // 返回true,页面保持原状

+                        return true;

+                    };

+                    return false;

+                }

+            }

+            /*else { cov_2

+            config.resetContentModifyValue();

+            }*/

+        }

+

+        function saveDraftAction(data) {

+            var datetime = new Date();

+            var params = {

+                index: -1,

+                currentTimeString: getCurrentTimeString(datetime),

+                groupId: data.numbers.length > 1 ? datetime.getTime() : '',

+                message: data.content,

+                numbers: data.numbers

+            };

+            service.saveSMS(params, function () {

+                successOverlay('sms_save_draft_success');

+            }, function () {

+                errorOverlay("sms_save_draft_failed")

+            });

+        }

+        function smsPageCheckDraft(clearCallback, isNeedInit) {

+            if (config.CONTENT_MODIFIED.message != 'sms_to_save_draft') {

+                if (config.CONTENT_MODIFIED.modified) {

+                    showConfirm(config.CONTENT_MODIFIED.message, {

+                        ok: function () {

+                            config.CONTENT_MODIFIED.callback.ok(config.CONTENT_MODIFIED.data);

+                            clearCallback(isNeedInit);

+                        },

+                        no: function () {

+                            if (config.CONTENT_MODIFIED.message == 'sms_to_save_draft') {

+                                clearCallback(isNeedInit);

+                            }

+                            return false;

+                        }

+                    });

+                    return false;

+                } else {

+                    clearCallback(isNeedInit);

+                }

+            } else {

+                config.CONTENT_MODIFIED.callback.ok(config.CONTENT_MODIFIED.data);

+                clearCallback(isNeedInit);

+            }

+        }

+

+        //重新获取页面数据并显示

+        function getPhoneBookReady() {

+            service.getPhoneBookReady({}, function (data) {

+                if (data.pbm_init_flag == "6") {

+                    target.initFail(true);

+                    hideLoading();

+                    showAlert("phonebook_init_fail");

+                } else if (data.pbm_init_flag != "0") {

+                    addTimeout(getPhoneBookReady, 1000);

+                } else {

+                    target.initFail(false);

+                    var capacity = getCapacity();

+                    target.capacity(capacity);

+                    target.phoneBookCapacity(capacity.Ratio);

+                    var phoneBooks = getBooks(capacity.Used);

+                    target.books(phoneBooks);

+                    target.gridTemplate.data(phoneBooks);

+                    $('#books').find('tbody').translate();

+                    hideLoading();

+                }

+            });

+        }

+

+        showLoading('waiting');

+        addTimeout(getPhoneBookReady, 200);

+

+        //重新获取页面数据并显示

+        function refreshPage() {

+            showLoading();

+            var capacity = getCapacity();

+            target.phoneBookCapacity(capacity.Ratio);

+            target.capacity(capacity);

+            var books = getBooks(capacity.Used);

+            target.books(books);

+            target.gridTemplate.data(books);

+            hideLoading();

+        }

+

+        target.preContent = {};

+        //保存编辑前的内容

+        function setPreContent() {

+            target.preContent.location = target.selectedLocation();

+            target.preContent.name = target.name();

+            target.preContent.mobile_phone_number = target.mobile_phone_number();

+            target.preContent.home_phone_number = target.home_phone_number();

+            target.preContent.office_phone_number = target.office_phone_number();

+            target.preContent.mail = target.mail();

+            target.preContent.group = target.selectedGroup();

+        }

+

+        //检测数据是否改变

+        function checkContentChang() {

+            var changed = (target.preContent.location != target.selectedLocation()

+                 || target.preContent.name != target.name()

+                 || target.preContent.mobile_phone_number != target.mobile_phone_number()

+                 || target.preContent.home_phone_number != target.home_phone_number()

+                 || target.preContent.office_phone_number != target.office_phone_number()

+                 || target.preContent.mail != target.mail()

+                 || target.preContent.group != target.selectedGroup());

+            config.CONTENT_MODIFIED.modified = changed;

+        }

+

+        function preOpenEditPage() {

+            config.resetContentModifyValue();

+            setPreContent();

+            config.CONTENT_MODIFIED.checkChangMethod = checkContentChang;

+        }

+    }

+

+    //设置停止发送标志为true

+    phoneBookStopSMSSending = function () {

+        _phoneBookStopSMSSending = true;

+        $("#loading #loading_container").html($.i18n.prop("sms_cancel_sending"));

+    }

+

+    //获取电话本

+    function getBooks(capacity) {

+        var para = {};

+        para.page = 0;

+        para.data_per_page = capacity;

+        para.orderBy = "name";

+        para.isAsc = true;

+        var books = [];

+        var group = getCurrentGroup();

+        if (config.HAS_SMS) {

+            books = service.getPhoneBooks(para);

+            config.phonebook = books.pbm_data;

+            if (group != "all") {

+                books = {

+                    "pbm_data": _.filter(books.pbm_data, function (item) {

+                        return item.pbm_group == group;

+                    })

+                };

+            }

+        } else {

+            if (group != "all") {

+                para.group = group;

+                books = service.getPhoneBooksByGroup(para);

+            } else {

+                books = service.getPhoneBooks(para);

+            }

+        }

+        return translateData(books.pbm_data);

+    }

+

+    //获取电话本容量信息

+    function getCapacity() {

+        var sim = service.getSIMPhoneBookCapacity();

+        var device = service.getDevicePhoneBookCapacity();

+        return {

+            simUsed: sim.simPbmUsedCapacity,

+            deviceUsed: device.pcPbmUsedCapacity,

+            simCapacity: sim.simPbmTotalCapacity,

+            deviceCapacity: device.pcPbmTotalCapacity,

+            simMaxNameLen: sim.maxNameLen,

+            simMaxNumberLen: sim.maxNumberLen,

+            IsSimCardFull: (sim.simPbmUsedCapacity == sim.simPbmTotalCapacity),

+            IsDeviceFull: (device.pcPbmUsedCapacity == device.pcPbmTotalCapacity),

+            Used: sim.simPbmUsedCapacity + device.pcPbmUsedCapacity,

+            Capacity: sim.simPbmTotalCapacity + device.pcPbmTotalCapacity,

+            Ratio: "(" + (sim.simPbmUsedCapacity + device.pcPbmUsedCapacity) + "/" + (sim.simPbmTotalCapacity + device.pcPbmTotalCapacity) + ")"

+        };

+    }

+

+    function translateData(books) {

+        var ret = [];

+        var group = getCurrentGroup();

+        var hasFilter = (group != "all");

+        if (books) {

+            for (var i = 0; i < books.length; i++) {

+                if (hasFilter) {

+                    var currentGroup = books[i].pbm_group;

+                    if (books[i].pbm_location == locationValue.SIM || currentGroup != group) {

+                        continue;

+                    }

+                }

+                var temp = {

+                    index: books[i].pbm_id,

+                    location: books[i].pbm_location,

+                    imgLocation: books[i].pbm_location == locationValue.SIM ? "pic/simcard.png" : "pic/res_device.png",

+                    name: books[i].pbm_name,

+                    mobile_phone_number: books[i].pbm_number,

+                    home_phone_number: books[i].pbm_anr,

+                    office_phone_number: books[i].pbm_anr1,

+                    mail: books[i].pbm_email,

+                    group: books[i].pbm_group,

+                    transGroup: (!books[i].pbm_group) ? "group_null" : "group_" + books[i].pbm_group

+                };

+                ret.push(temp);

+            }

+        }

+        return ret;

+    }

+    //初始化ViewModel并进行绑定

+    function init() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var vm = new pbViewMode();

+        ko.applyBindings(vm, container[0]);

+        $("#txtSmsContent").die().live("contextmenu", function () {

+            return false;

+        });

+        $('#frmPhoneBook').validate({

+            submitHandler: function () {

+                vm.save();

+            },

+            rules: {

+                txtMail: "email_check",

+                txtName: "name_check",

+                txtMobile: "phonenumber_check",

+                txtHomeNumber: "phonenumber_check",

+                txtOfficeNumber: "phonenumber_check"

+            }

+        });

+

+    }

+

+    return {

+        init: init

+    };

+});

+

+define("sms_list","underscore jquery knockout set service jq_chosen".split(" "),

+    function (_, $, ko, config, service, chosen) {

+

+    var currentPage = 1;

+    //数据是否加载完成

+    var ready = false,

+    //聊天室信息正在加载中

+    chatRoomInLoading = false;

+    //快速添加联系人模板

+    var addPhonebookTmpl = null,

+    //短消息模板

+    smsTableTmpl = null,

+    //接收短消息模板

+    smsOtherTmpl = null,

+    //发送短消息模板

+    smsMeTmpl = null,

+    //群聊草稿

+    groupDrafts = [],

+    //短消息列表显示群聊草稿

+    groupDraftItems = [],

+    //短消息列表显示群聊草稿及其草稿群聊细节

+    groupedDraftsObject = {},

+    //短消息容量信息

+    smsCapability = {},

+    //短消息是否还有存储空间

+    hasCapability = true;

+    //获取全部短消息,并将短信通过回调函数getPhoneBooks,与电话本进行关联

+    function getSMSMessages(callback) {

+        return service.getSMSMessages({

+            page: 0,

+            smsCount: 500,

+            nMessageStoreType: 1,

+            tags: 10,

+            orderBy: "order by id desc"

+        }, function (data) {

+            tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), data.messages.length);

+            config.dbMsgs = data.messages;

+            config.listMsgs = groupSms(config.dbMsgs);

+            callback();

+        }, function () {

+            tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), 0);

+            config.dbMsgs = [];

+            config.listMsgs = [];

+            cleanSmsList();

+        });

+    }

+

+    //清楚短消息列表内容

+    cleanSmsList = function () {

+        $("#smslist-table").empty();

+    };

+

+    //关联后的短消息根据电话号码进行分组

+    function groupSms(messages) {

+        var peoples = {},

+        theSortedPeoples = [];

+        config.listMsgs = [];

+        groupDrafts = [];

+        $.each(messages, function (i, e) {

+            if (e.tag == '4' && e.groupId != '') { // 群聊草稿

+                groupDrafts.push(e);

+                return;

+            }

+            e.target = e.number;

+            if (parseInt(e.id, 10) > config.smsMaxId) {

+                config.smsMaxId = e.id;

+            }

+            var last8 = getLastNumber(e.number, config.SMS_MATCH_LENGTH);

+            if (last8 in peoples) {

+                peoples[last8].push(e);

+            } else {

+                peoples[last8] = [e];

+                theSortedPeoples.push(e);

+            }

+        });

+        theSortedPeoples = _.sortBy(theSortedPeoples, function (ele) {

+            return 0 - parseInt(ele.id + "", 10);

+        });

+        $.each(theSortedPeoples, function (s_i, sp) {

+            var people = getLastNumber(sp.number, config.SMS_MATCH_LENGTH);

+            var newCount = 0;

+            var hasDraft = false;

+            for (var i = 0; i < peoples[people].length; i++) {

+                if (peoples[people][i].isNew) {

+                    newCount++;

+                }

+                if (peoples[people][i].tag == '4' && peoples[people][i].groupId == '') { // 单条草稿

+                    hasDraft = true;

+                }

+            }

+            config.listMsgs.push({

+                id: peoples[people][0].id,

+                name: "",

+                number: peoples[people][0].number,

+                latestId: peoples[people][0].id,

+                totalCount: peoples[people].length,

+                newCount: newCount,

+                latestSms: peoples[people][0].content,

+                latestTime: peoples[people][0].time,

+                checked: false,

+                itemId: getLastNumber(people, config.SMS_MATCH_LENGTH),

+                groupId: peoples[people][0].groupId,

+                hasDraft: hasDraft

+            });

+        });

+        return config.listMsgs;

+    }

+

+    //获取电话本信息,并与短消息关联

+    function getPhoneBooks() {

+        var books = service.getPhoneBooks({

+            page: 0,

+            data_per_page: 2000,

+            orderBy: "name",

+            isAsc: true

+        });

+        if ($.isArray(books.pbm_data) && books.pbm_data.length > 0) {

+            config.phonebook = books.pbm_data;

+        }

+        dealPhoneBooks();

+    }

+

+    //双异步获取设备侧和sim卡侧的短信息,并将其合并

+    function dealPhoneBooks() {

+        var select = $("#chosenUserList .chosen-select-deselect");

+        select.empty();

+        var options = [];

+        var tmp = [];

+        var pbTmp = [];

+        for (var j = 0; j < config.phonebook.length; j++) {

+            var book = config.phonebook[j];

+            var last8Num = getLastNumber(book.pbm_number, config.SMS_MATCH_LENGTH);

+            if (last8Num && $.inArray(last8Num, pbTmp) == -1) {

+                options.push(new Option(book.pbm_name + "/" + book.pbm_number, last8Num, false, true));

+                if ($.inArray(last8Num, tmp) == -1) {

+                    tmp.push(last8Num);

+                }

+                pbTmp.push(last8Num);

+            } else {

+                for (var i = 0; i < options.length; i++) {

+                    if (options[i].value == last8Num) {

+                        options[i].text = book.pbm_name + "/" + book.pbm_number;

+                        break;

+                    }

+                }

+            }

+        }

+        var groupIds = [];

+        for (var k = 0; k < groupDrafts.length; k++) { // 将草稿做对象Map封装,供草稿组点击后的草稿分解

+            if ($.inArray(groupDrafts[k].groupId, groupIds) == -1) {

+                groupIds.push(groupDrafts[k].groupId);

+                var draft = groupDrafts[k];

+                groupedDraftsObject[groupDrafts[k].groupId] = [draft];

+            } else {

+                var draft = groupDrafts[k];

+                groupedDraftsObject[groupDrafts[k].groupId].push(draft);

+            }

+            var itemId = getLastNumber(groupDrafts[k].number, config.SMS_MATCH_LENGTH);

+            if ($.inArray(itemId, tmp) == -1) {

+                options.push(new Option(groupDrafts[k].number, itemId));

+                tmp.push(itemId);

+            }

+        }

+        for (var g in groupedDraftsObject) { // 处理列表显示的草稿信息

+            var drafts = groupedDraftsObject[g];

+            var draftItem = drafts[drafts.length - 1];

+            draftItem.draftShowName = '';

+            draftItem.draftShowNameTitle = '';

+            $.each(drafts, function (i, n) {

+                var showName = getShowNameByNumber(n.number);

+                draftItem.draftShowName += (i == 0 ? '' : ';') + showName;

+                draftItem.draftShowNameTitle += (i == 0 ? '' : ';') + showName;

+            });

+

+            var len = 10;

+            if (getEncodeType(draftItem.draftShowName).encodeType == "UNICODE") {

+                len = 10;

+            }

+            draftItem.draftShowName = draftItem.draftShowName.length > len ? draftItem.draftShowName.substring(0, len) + "..." : draftItem.draftShowName;

+            draftItem.totalCount = drafts.length;

+            draftItem.hasDraft = true;

+            draftItem.latestTime = draftItem.time;

+            groupDraftItems.push(draftItem);

+        }

+        for (var i = 0; i < config.listMsgs.length; i++) {

+            var smsItem = config.listMsgs[i];

+            for (var j = config.phonebook.length; j > 0; j--) {

+                var book = config.phonebook[j - 1];

+                var last8Num = getLastNumber(book.pbm_number, config.SMS_MATCH_LENGTH);

+                if (smsItem.itemId == last8Num) {

+                    smsItem.name = book.pbm_name;

+                    for (var k = 0; k < options.length; k++) {

+                        if (last8Num == options[k].value) {

+                            options[k].value = getLastNumber(smsItem.number, config.SMS_MATCH_LENGTH);

+                            options[k].text = book.pbm_name + '/' + smsItem.number;

+                            break;

+                        }

+                    }

+                    break;

+                }

+            }

+            if ($.inArray(smsItem.itemId, tmp) == -1) {

+                options.push(new Option(smsItem.number, getLastNumber(smsItem.number, config.SMS_MATCH_LENGTH)));

+                tmp.push(smsItem.itemId);

+            }

+        }

+

+        var opts = "";

+        $.each(options, function (i, e) {

+            opts += "<option value='" + HTMLEncode(e.value) + "'>" + HTMLEncode(e.text) + "</option>";

+        });

+        select.append(opts);

+        select.chosen({

+            max_selected_options: 5,

+            search_contains: true,

+            width: '740px'

+        });

+        showSmsListData();

+        showMultiDraftListData();

+        //changeShownMsgs();

+        ready = true;

+    }

+

+    function showSmsListData() {

+        if (smsTableTmpl == null) {

+            smsTableTmpl = $.template("smsTableTmpl", $("#smsTableTmpl"));

+        }

+        cleanSmsList();

+        $.tmpl("smsTableTmpl", {

+            data: config.listMsgs

+        }).translate().appendTo("#smslist-table");

+

+        if (config.HAS_PHONEBOOK) {

+            $(".sms-add-contact-icon").removeClass("hide");

+        } else {

+            $(".sms-add-contact-icon").addClass("hide");

+        }

+    }

+    //群组草稿列表显示

+    function showMultiDraftListData() {

+        if (groupDraftItems.length == 0) {

+            return false;

+        }

+        if (smsTableTmpl == null) {

+            smsTableTmpl = $.template("smsTableTmpl", $("#smsTableTmpl"));

+        }

+        $.tmpl("smsTableTmpl", {

+            data: groupDraftItems

+        }).translate().prependTo("#smslist-table");

+    }

+

+    // 页面发生滚动后,改变页面显示的短消息

+    function changeShownMsgs() {

+        var shownMsgsTmp = [];

+        var range = _.range((currentPage - 1) * 5, currentPage * 5);

+        $.each(range, function (i, e) {

+            if (config.listMsgs[e]) {

+                shownMsgsTmp.push(config.listMsgs[e]);

+            }

+        });

+        //shownMsgsTmp = config.listMsgs;

+        currentPage++;

+

+        if (smsTableTmpl == null) {

+            smsTableTmpl = $.template("smsTableTmpl", $("#smsTableTmpl"));

+        }

+        $.tmpl("smsTableTmpl", {

+            data: shownMsgsTmp

+        }).translate().appendTo("#smslist-table");

+

+        renderCheckbox();

+        if (shownMsgsTmp.length == 0) {

+            disableBtn($("#smslist-delete-all"));

+            tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), 0);

+        } else {

+            enableBtn($("#smslist-delete-all"));

+            tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), 1);

+        }

+        if (currentPage == 2 && window.innerHeight == $("body").height()) {

+            changeShownMsgs();

+        }

+        return shownMsgsTmp;

+    }

+

+    //将被checked的条目添加到self.checkedItem中,用于在滚动还原checkbox

+    checkboxClickHandler = function (id) {

+        checkDeleteBtnStatus();

+    };

+

+    //获取已选择的条目

+    getSelectedItem = function () {

+        var selected = [];

+        var checkedItem = $("#smslist-table input:checkbox:checked");

+        checkedItem.each(function (i, e) {

+            selected.push($(e).val());

+        });

+        return selected;

+    };

+

+    //删除按钮是否禁用

+    checkDeleteBtnStatus = function () {

+        var size = getSelectedItem().length;

+        if (size == 0) {

+            disableBtn($("#smslist-delete"));

+        } else {

+            enableBtn($("#smslist-delete"));

+        }

+    };

+

+    //刷新短消息列表

+    refreshClickHandler = function () {

+        $("#smslist-table").empty();

+        disableBtn($("#smslist-delete"));

+        disableCheckbox($("#smslist-checkAll", "#smsListForm"));

+        init();

+        renderCheckbox();

+    };

+

+    //删除全部短消息

+    deleteAllClickHandler = function () {

+        showConfirm("confirm_data_delete", function () {

+            showLoading('deleting');

+            service.deleteAllMessages({

+                location: "native_inbox"

+            }, function (data) {

+                cleanSmsList();

+                tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), 0);

+                successOverlay();

+            }, function (error) {

+                errorOverlay(error.errorText);

+            });

+        });

+    };

+

+    //删除选中的短消息

+    deleteSelectClickHandler = function () {

+        showConfirm("confirm_sms_delete", function () {

+            showLoading('deleting');

+            var items = getIdsBySelectedIds();

+            service.deleteMessage({

+                ids: items.ids

+            }, function (data) {

+                renderAfterDelete(items);

+                disableBtn($("#smslist-delete"));

+                $("#checkbox-all").removeAttr("checked");

+                renderCheckbox();

+                successOverlay();

+            }, function (error) {

+                errorOverlay(error.errorText);

+            });

+        });

+

+        function renderAfterDelete(items) {

+            var ids = items.ids;

+            var nums = [];

+            $.each(config.dbMsgs, function (i, e) {

+                if ($.inArray(e.id, items.normalIds) != -1) {

+                    nums.push(e.number);

+                }

+            });

+            nums = _.uniq(nums);

+            $.each(nums, function (i, e) {

+                $("#smslist-item-" + getLastNumber(e, config.SMS_MATCH_LENGTH)).hide().remove();

+            });

+            $.each(items.groups, function (i, e) {

+                $("#smslist-item-" + e).hide().remove();

+            });

+            synchSmsList(nums, ids);

+        }

+

+        function getIdsBySelectedIds() {

+            var nums = [];

+            var resultIds = [];

+            var normalIds = [];

+            var groups = [];

+            var selectedItem = getSelectedItem();

+            $.each(selectedItem, function (i, e) {

+                var checkbox = $("#checkbox" + e);

+                if (checkbox.attr("groupid")) {

+                    groups.push(checkbox.attr("groupid"));

+                } else {

+                    nums.push(getLastNumber(checkbox.attr("number"), config.SMS_MATCH_LENGTH));

+                }

+            });

+

+            $.each(config.dbMsgs, function (i, e) {

+                if ($.inArray(getLastNumber(e.number, config.SMS_MATCH_LENGTH), nums) != -1 && (typeof e.groupId == "undefined" || _.isEmpty(e.groupId + ''))) {

+                    resultIds.push(e.id);

+                    normalIds.push(e.id);

+                } else if ($.inArray(e.groupId + '', groups) != -1) { //删除草稿组

+                    resultIds.push(e.id);

+                }

+            });

+            resultIds = _.uniq(resultIds);

+            return {

+                ids: resultIds,

+                groups: groups,

+                normalIds: normalIds

+            };

+        }

+    };

+

+    //新短信按钮点击

+    newMessageClickHandler = function () {

+        $("#chosenUser1", "#smsChatRoom").addClass("hide");

+        $("#chosenUser", "#smsChatRoom").show();

+

+        cleanChatInput();

+        checkSmsCapacityAndAlert();

+        $("select.chosen-select-deselect").val("").trigger("chosen:updated.chosen");

+        switchPage('chat');

+        gotoBottom();

+        clearChatList();

+    };

+

+    //返回聊天室列表

+    chatCancelClickHandler = function () {

+        if (config.CONTENT_MODIFIED.modified) {

+            var confirmMessage = 'sms_to_save_draft';

+            var selectedContact = syncSelectAndChosen($("select#chosenUserSelect"), $('.search-choice', '#chosenUserSelect_chosen'));

+            var noContactSelected = !selectedContact || selectedContact.length == 0;

+            if (noContactSelected) {

+                confirmMessage = 'sms_no_recipient';

+            }

+            if (noContactSelected) {

+                showConfirm(confirmMessage, {

+                    ok: function () {

+                        if (!noContactSelected) {

+                            saveDraftAction({

+                                content: $("#chat-input", "#smsChatRoom").val(),

+                                numbers: selectedContact,

+                                isFromBack: true

+                            });

+                        }

+                        config.resetContentModifyValue();

+                        backToSmsListMainPage();

+                    },

+                    no: function () {

+                        if (noContactSelected) {

+                            return true;

+                        }

+                        config.resetContentModifyValue();

+                        backToSmsListMainPage();

+                    }

+                });

+            } else {

+                saveDraftAction({

+                    content: $("#chat-input", "#smsChatRoom").val(),

+                    numbers: selectedContact,

+                    isFromBack: true

+                });

+                config.resetContentModifyValue();

+                backToSmsListMainPage();

+            }

+            return false;

+        }

+        backToSmsListMainPage();

+    };

+

+    //跳转页面至SIM卡侧、设置界面

+    toOtherClickHandler = function (href) {

+        config.CONTENT_MODIFIED.checkChangMethod();

+        if (config.CONTENT_MODIFIED.modified) {

+            draftListener();

+            if (config.CONTENT_MODIFIED.message == 'sms_to_save_draft') {

+                config.CONTENT_MODIFIED.callback.ok(config.CONTENT_MODIFIED.data);

+                config.resetContentModifyValue();

+                window.location.hash = href;

+            } else {

+                showConfirm(config.CONTENT_MODIFIED.message, {

+                    ok: function () {

+                        config.CONTENT_MODIFIED.callback.ok(config.CONTENT_MODIFIED.data);

+                        config.resetContentModifyValue();

+                        window.location.hash = href;

+                    },

+                    no: function () {

+                        var result = config.CONTENT_MODIFIED.callback.no(config.CONTENT_MODIFIED.data);

+                        if (!result) {

+                            window.location.hash = href;

+                            config.resetContentModifyValue();

+                        }

+                    }

+                });

+            }

+            return false;

+        } else {

+            window.location.hash = href;

+        }

+    };

+

+    function backToSmsListMainPage() {

+        $("select.chosen-select-deselect").val("").trigger("chosen:updated.chosen");

+        config.currentChatObject = null;

+        $(".smslist-btns", "#smslist-main").removeClass('smsListFloatButs');

+        switchPage('list');

+    }

+

+    function switchPage(page) {

+        if (page == 'chat') {

+            $("#smslist-main").hide();

+            $("#smsChatRoom").show();

+        } else {

+            $("#smsChatRoom").hide();

+            $("#smslist-main").show();

+        }

+    }

+

+    var sendSmsErrorTimer = null;

+    //添加发送错误消息

+    addSendSmsError = function (msg) {

+        if (sendSmsErrorTimer) {

+            window.clearTimeout(sendSmsErrorTimer);

+            sendSmsErrorTimer = null;

+        }

+        $("#sendSmsErrorLi").text($.i18n.prop(msg));

+        sendSmsErrorTimer = addTimeout(function () {

+            $("#sendSmsErrorLi").text("");

+        }, 5000);

+    };

+

+    //发送短消息

+    sendSmsClickHandler = function () {

+        if (!hasCapability) {

+            showAlert("sms_capacity_is_full_for_send");

+            return;

+        }

+        var inputVal = $("#chat-input", "#smsChatRoom");

+        var msgContent = inputVal.val();

+        if (msgContent == $.i18n.prop("chat_input_placehoder")) {

+            inputVal.val("");

+            msgContent = "";

+        }

+        var nums = syncSelectAndChosen($("select#chosenUserSelect"), $('.search-choice', '#chosenUserSelect_chosen'));

+        if ($.isArray(nums)) {

+            nums = $.grep(nums, function (n, i) {

+                return !_.isEmpty(n);

+            });

+        }

+        if (!nums || nums.length == 0) {

+            addSendSmsError("sms_contact_required");

+            return;

+        }

+        if (nums.length + smsCapability.nvUsed > smsCapability.nvTotal) {

+            showAlert({

+                msg: "sms_capacity_will_full_just",

+                params: [smsCapability.nvTotal - smsCapability.nvUsed]

+            });

+            return;

+        }

+        if (nums.length == 1) {

+            config.currentChatObject = getLastNumber(nums[0], config.SMS_MATCH_LENGTH);

+            showLoading('sending');

+        } else if (nums.length > 1) {

+            showLoading("sending", "<button id='sms_cancel_sending' onclick='cancelSending()' class='btn btn-primary'>"

+                 + $.i18n.prop("sms_stop_sending")

+                 + "</button>");

+            config.currentChatObject = null;

+        }

+        var i = 0;

+        var leftNum = nums.length;

+        couldSend = true;

+        disableBtn($("#btn-send", "#inputpanel"));

+        sendSms = function () {

+            if (!couldSend) {

+                hideLoading();

+                return;

+            }

+            var newMsg = {

+                id: -1,

+                number: nums[i],

+                content: msgContent,

+                isNew: false

+            };

+

+            if (leftNum == 1) {

+                $("#loading #loading_container").html("");

+            }

+

+            leftNum--;

+            service.sendSMS({

+                number: newMsg.number,

+                message: newMsg.content,

+                id: -1

+            }, function (data) {

+                var latestMsg = getLatestMessage() || {

+                    id: parseInt(config.smsMaxId, 10) + 1,

+                    time: transUnixTime($.now()),

+                    number: newMsg.number

+                };

+                config.smsMaxId = latestMsg.id;

+                newMsg.id = config.smsMaxId;

+                newMsg.time = latestMsg.time;

+                newMsg.tag = 2;

+                newMsg.hasDraft = false;

+                if (nums.length > 1) {

+                    newMsg.targetName = getNameOrNumberByNumber(newMsg.number);

+                }

+                addSendMessage(newMsg, i + 1 != nums.length);

+                updateDBMsg(newMsg);

+                updateMsgList(newMsg);

+                tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), $(".smslist-item", "#smslist-table").length);

+                gotoBottom();

+                if (i + 1 == nums.length) {

+                    updateChatInputWordLength();

+                    enableBtn($("#btn-send", "#inputpanel"));

+                    hideLoading();

+                    return;

+                }

+                i++;

+                sendSms();

+            }, function (error) {

+                var latestMsg = getLatestMessage() || {

+                    id: parseInt(config.smsMaxId, 10) + 1,

+                    time: transUnixTime($.now()),

+                    number: newMsg.number

+                };

+                config.smsMaxId = latestMsg.id;

+                newMsg.id = config.smsMaxId;

+                newMsg.time = latestMsg.time;

+                newMsg.errorText = $.i18n.prop(error.errorText);

+                newMsg.tag = 3;

+                newMsg.target = newMsg.number;

+                newMsg.hasDraft = false;

+                if (nums.length > 1) {

+                    newMsg.targetName = getNameOrNumberByNumber(newMsg.number);

+                }

+                addSendMessage(newMsg, i + 1 != nums.length);

+                updateDBMsg(newMsg);

+                updateMsgList(newMsg);

+                tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), $(".smslist-item", "#smslist-table").length);

+                gotoBottom();

+                if (i + 1 == nums.length) {

+                    updateChatInputWordLength();

+                    enableBtn($("#btn-send", "#inputpanel"));

+                    hideLoading();

+                    return;

+                }

+                i++;

+                sendSms();

+            });

+        };

+        sendSms();

+    };

+

+    var couldSend = true;

+

+    //取消剩余短信发送操作

+    cancelSending = function () {

+        couldSend = false;

+        $("#loading #loading_container").html($.i18n.prop('sms_cancel_sending'));

+    };

+

+    //获取最新的短消息

+    getLatestMessage = function () {

+        var data = service.getSMSMessages({

+            page: 0,

+            smsCount: 5,

+            nMessageStoreType: 1,

+            tags: 10,

+            orderBy: "order by id desc"

+        });

+        if (data.messages.length > 0) {

+            for (var i = 0; i < data.messages.length; i++) {

+                if (data.messages[i].tag == '2' || data.messages[i].tag == '3') {

+                    return data.messages[i];

+                }

+            }

+            return null;

+        } else {

+            return null;

+        }

+    };

+

+    //发送短信后,更新短信数据对象

+    function updateDBMsg(msg) {

+        if (config.dbMsgs.length == 0) {

+            config.dbMsgs = [msg];

+        } else {

+            /* cov_2

+            for(var j = 0; j < config.dbMsgs.length; j++){

+            if(config.dbMsgs[j].id == msg.id){

+            config.dbMsgs[j] = msg;

+            return;

+            } else {

+            var newMsg = [msg];

+            $.merge(newMsg, config.dbMsgs);

+            config.dbMsgs = newMsg;

+            return;

+            }

+            }

+             */

+            if (config.dbMsgs[0].id == msg.id) {

+                config.dbMsgs[0] = msg;

+                return;

+            } else {

+                var newMsg = [msg];

+                $.merge(newMsg, config.dbMsgs);

+                config.dbMsgs = newMsg;

+                return;

+            }

+        }

+    }

+

+    //发送短信后,更新短信列表, number不为空做删除处理,为空做增加处理

+    function updateMsgList(msg, number, counter) {

+        if ((!msg || !msg.number) && !number) {

+            return;

+        }

+        var itemId = '';

+        if (msg && typeof msg.groupId != "undefined" && msg.groupId != '') {

+            itemId = msg.groupId;

+        } else {

+            itemId = getLastNumber((number || msg.number), config.SMS_MATCH_LENGTH);

+        }

+        var item = $("#smslist-item-" + itemId);

+        if (item && item.length > 0) {

+            var totalCountItem = item.find(".smslist-item-total-count");

+            var count = totalCountItem.text();

+            count = Number(count.substring(1, count.length - 1));

+            if (number) {

+                if (count == 1 || msg == null) {

+                    item.hide().remove();

+                    return;

+                } else {

+                    totalCountItem.text("(" + (count - (counter || 1)) + ")");

+                    item.find(".smslist-item-draft-flag").addClass('hide');

+                }

+            } else {

+                totalCountItem.text("(" + (count + 1) + ")");

+                if (msg.tag == '4') {

+                    item.find(".smslist-item-draft-flag").removeClass('hide');

+                }

+            }

+            item.find(".smslist-item-checkbox p.checkbox").attr("id", msg.id);

+            item.find(".smslist-item-checkbox input:checkbox").val(msg.id).attr("id", "checkbox" + msg.id);

+            var contentHtml = msg.content;

+			var msgContent;

+            if (msg.tag == '4') {

+                //contentHtml = '<span class="smslist-item-draft-flag colorRed" data-trans="draft"></span>: ' + contentHtml;

+				msgContent = item.find(".smslist-item-msg").html('<span class="smslist-item-draft-flag colorRed" data-trans="draft"></span>: ' + HTMLEncode(contentHtml)); //.addClass("font-weight-bold");

+            } else {

+				msgContent = item.find(".smslist-item-msg").html(HTMLEncode(contentHtml)); //.addClass("font-weight-bold");

+			}

+            //var msgContent = item.find(".smslist-item-msg").html(HTMLEncode(contentHtml)); //.addClass("font-weight-bold");

+            msgContent.closest('td').prop('title', msg.content);

+            item.find(".smslist-item-repeat span").die().click(function () {

+                forwardClickHandler(msg.id);

+            });

+            item.find("span.clock-time").text(msg.time);

+            var tmpItem = item;

+            item.hide().remove();

+            $("#smslist-table").prepend(tmpItem.show());

+        } else {

+            if (smsTableTmpl == null) {

+                smsTableTmpl = $.template("smsTableTmpl", $("#smsTableTmpl"));

+            }

+            msg.checked = false;

+            msg.newCount = 0;

+            msg.latestId = msg.id;

+            msg.latestSms = msg.content;

+            msg.latestTime = msg.time;

+            if (msg.groupId == '' || typeof msg.groupId == "undefined") {

+                msg.totalCount = 1;

+            }

+            if (!msg.hasDraft) {

+                msg.hasDraft = false;

+            }

+            msg.itemId = itemId;

+            msg.name = getNameByNumber(msg.number);

+            $.tmpl("smsTableTmpl", {

+                data: [msg]

+            }).translate().prependTo("#smslist-table");

+        }

+        if (config.HAS_PHONEBOOK) {

+            $(".sms-add-contact-icon").removeClass("hide");

+        } else {

+            $(".sms-add-contact-icon").addClass("hide");

+        }

+        $("#smslist-table").translate();

+        renderCheckbox();

+    }

+

+    //增加发送内容到聊天室, notCleanChatInput 是否清除输入框内容

+    addSendMessage = function (sms, notCleanChatInput) {

+        if (smsMeTmpl == null) {

+            smsMeTmpl = $.template("smsMeTmpl", $("#smsMeTmpl"));

+        }

+        $.tmpl("smsMeTmpl", sms).appendTo("#chatlist");

+        $("#chatlist").translate();

+        if (!notCleanChatInput) {

+            cleanChatInput();

+        }

+        clearMySmsErrorMessage(sms.id);

+    };

+

+    //清楚错误消息,避免翻译问题

+    clearMySmsErrorMessage = function (id) {

+        addTimeout(function () {

+            $("div.error", "#talk-item-" + id).text("");

+        }, 3000);

+    };

+

+    //快速添加联系人overlay是否打开

+    var isPoped = false;

+

+    //关闭快速添加联系人overlay

+    hidePopup = function () {

+        $(".tagPopup").remove();

+        isPoped = false;

+    };

+

+    //清空聊天室内容

+    clearChatList = function () {

+        $("#chatlist").empty();

+        updateChatInputWordLength();

+    };

+

+    //过滤短消息内容

+    dealContent = function (content) {

+        if (config.HAS_PHONEBOOK) {

+            return HTMLEncode(content).replace(/(\d{3,})/g, function (word) {

+                var r = (new Date().getTime() + '').substring(6) + (getRandomInt(1000) + 1000);

+                return "<a id='aNumber" + r + "' href='javascript:openPhoneBook(\"" + r + "\", \"" + word + "\")'>" + word + "</a>";

+            });

+        } else {

+            return HTMLEncode(content);

+        }

+

+    };

+

+    //打开快速添加联系人overlay

+    openPhoneBook = function (id, num) {

+        var target = null;

+        var outContainer = "";

+        var itemsContainer = null;

+        var isChatRoom = false;

+        if (!id) {

+            target = $("#listNumber" + getLastNumber(num, config.SMS_MATCH_LENGTH));

+            outContainer = ".smslist-item";

+            itemsContainer = $("#addPhonebookContainer");

+        } else {

+            target = $("#aNumber" + id);

+            outContainer = ".msg_container";

+            itemsContainer = $("#chatlist");

+            isChatRoom = true;

+        }

+        if (isPoped) {

+            hidePopup();

+        }

+        isPoped = true;

+        $("#tagPopup").remove();

+

+        if (addPhonebookTmpl == null) {

+            addPhonebookTmpl = $.template("addPhonebookTmpl", $("#addPhonebookTmpl"));

+        }

+        $.tmpl("addPhonebookTmpl", {

+            number: num

+        }).appendTo(itemsContainer);

+        var p = target.position();

+        var msgContainer = target.closest(outContainer);

+        var msgP = msgContainer.position();

+        var _left = 0,

+        _top = 0;

+        if (isChatRoom) {

+            var containerWidth = itemsContainer.width();

+            var containerHeight = itemsContainer.height();

+            var pop = $("#innerTagPopup");

+            _left = msgP.left + p.left;

+            _top = msgP.top + p.top + 20;

+            if (pop.width() + _left > containerWidth) {

+                _left = containerWidth - pop.width() - 20;

+            }

+            if (containerHeight > 100 && pop.height() + _top > containerHeight) {

+                _top = containerHeight - pop.height() - 5;

+            }

+        } else {

+            _left = p.left;

+            _top = p.top;

+        }

+        $("#innerTagPopup").css({

+            top: _top + "px",

+            left: _left + "px"

+        });

+        $('#quickSaveContactForm').translate().validate({

+            submitHandler: function () {

+                quickSaveContact(isChatRoom);

+            },

+            rules: {

+                name: "name_check",

+                number: "phonenumber_check"

+            }

+        });

+    };

+

+    //快速添加联系人

+    quickSaveContact = function () {

+        var name = $(".tagPopup #innerTagPopup #name").val();

+        var number = $(".tagPopup #innerTagPopup #number").val();

+        var newContact = {

+            index: -1,

+            location: 1,

+            name: name,

+            mobile_phone_number: number,

+            home_phone_number: "",

+            office_phone_number: "",

+            mail: ""

+        };

+        var device = service.getDevicePhoneBookCapacity();

+        if (device.pcPbmUsedCapacity >= device.pcPbmTotalCapacity) {

+            showAlert("device_full");

+            return false;

+        }

+        showLoading('waiting');

+        service.savePhoneBook(newContact, function (data) {

+            if (data.result == "success") {

+                config.phonebook.push({

+                    pbm_name: name,

+                    pbm_number: number

+                });

+                updateItemShowName(name, number);

+                hidePopup();

+                successOverlay();

+            } else {

+                errorOverlay();

+            }

+        }, function (data) {

+            errorOverlay();

+        });

+    };

+

+    function updateItemShowName(name, number) {

+        var lastNum = getLastNumber(number, config.SMS_MATCH_LENGTH);

+        $("span.smslist-item-name2", "#smslist-item-" + lastNum).text(name);

+        $("#listNumber" + lastNum).hide();

+    }

+

+    //聊天室删除单条消息

+    deleteSingleItemClickHandler = function (id, resendCallback) {

+        if (resendCallback) {

+            deleteTheSingleItem(id);

+        } else {

+            showConfirm("confirm_sms_delete", function () {

+                showLoading('deleting');

+                deleteTheSingleItem(id);

+            });

+        }

+

+        function deleteTheSingleItem(id) {

+            service.deleteMessage({

+                ids: [id]

+            }, function (data) {

+                var target = $(".smslist-item-delete", "#talk-item-" + id).attr("target");

+                $("#talk-item-" + id).hide().remove();

+

+                synchSmsList(null, [id]);

+                updateMsgList(getPeopleLatestMsg(target), target);

+                if (resendCallback) {

+                    resendCallback();

+                } else {

+                    hideLoading();

+                }

+                tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), $(".smslist-item", "#smslist-table").length);

+            }, function (error) {

+                if (resendCallback) {

+                    resendCallback();

+                } else {

+                    hideLoading();

+                }

+            });

+        }

+    };

+

+    //删除草稿

+    function deleteDraftSms(ids, numbers) {

+        stopNavigation();

+        service.deleteMessage({

+            ids: ids

+        }, function (data) {

+            updateSmsCapabilityStatus(null, function () {

+                draftListener();

+                restoreNavigation();

+            });

+            for (var i = 0; i < numbers.length; i++) {

+                updateMsgList(getPeopleLatestMsg(numbers[i]), numbers[i], ids.length);

+            }

+            synchSmsList(null, ids);

+            tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), $(".smslist-item", "#smslist-table").length);

+        }, function (error) {

+            restoreNavigation();

+            // Do nothing

+        });

+    }

+

+    //删除群聊草稿草稿

+    function deleteMultiDraftSms(ids, groupId) {

+        service.deleteMessage({

+            ids: ids

+        }, function (data) {

+            synchSmsList(null, ids);

+            $("#smslist-item-" + groupId).hide().remove();

+            checkSmsCapacityAndAlert();

+            tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), $(".smslist-item", "#smslist-table").length);

+        }, function (error) {

+            // Do nothing

+        });

+    }

+

+    getCurrentChatObject = function () {

+        var nums = $("select.chosen-select-deselect").val();

+        if (!nums) {

+            config.currentChatObject = null;

+        } else if (nums.length == 1) {

+            config.currentChatObject = getLastNumber(nums, config.SMS_MATCH_LENGTH);

+        } else if (nums.length > 1) {

+            config.currentChatObject = null;

+        }

+        return config.currentChatObject;

+    };

+

+    //获取当前聊天对象最新的短消息

+    getPeopleLatestMsg = function (number) {

+        for (var j = 0; j < config.dbMsgs.length; j++) {

+            if (!config.dbMsgs[j].groupId && getLastNumber(config.dbMsgs[j].number, config.SMS_MATCH_LENGTH) == getLastNumber(number, config.SMS_MATCH_LENGTH)) {

+                return config.dbMsgs[j];

+            }

+        }

+        return null;

+    };

+

+    //重新发送,复制消息到发送框

+    resendClickHandler = function (id) {

+        if (!hasCapability) {

+            showAlert("sms_capacity_is_full_for_send");

+            return;

+        }

+        showLoading('sending');

+        $("div.error", "#talk-item-" + id).text($.i18n.prop("sms_resending"));

+        var targetNumber = $("div.smslist-item-resend", "#talk-item-" + id).attr("target");

+        var content = $("div.J_content", "#talk-item-" + id).text();

+        for (var j = 0; j < config.dbMsgs.length; j++) {

+            if (config.dbMsgs[j].id == id) {

+                content = config.dbMsgs[j].content;

+            }

+        }

+

+        disableBtn($("#btn-send", "#inputpanel"));

+        var newMsg = {

+            id: -1,

+            number: targetNumber,

+            content: content,

+            isNew: false

+        };

+        service.sendSMS({

+            number: newMsg.number,

+            message: newMsg.content,

+            id: -1

+        }, function (data) {

+            var latestMsg = getLatestMessage() || {

+                id: parseInt(config.smsMaxId, 10) + 1,

+                time: transUnixTime($.now()),

+                number: newMsg.number

+            };

+            config.smsMaxId = latestMsg.id;

+            newMsg.id = config.smsMaxId;

+            newMsg.time = latestMsg.time;

+            newMsg.tag = 2;

+            newMsg.target = latestMsg.number;

+            newMsg.targetName = getNameOrNumberByNumber(targetNumber);

+            updateDBMsg(newMsg);

+            updateMsgList(newMsg);

+            deleteSingleItemClickHandler(id, function () {

+                addSendMessage(newMsg, true);

+                updateChatInputWordLength();

+                enableBtn($("#btn-send", "#inputpanel"));

+                hideLoading();

+                gotoBottom();

+            });

+        }, function (error) {

+            var latestMsg = getLatestMessage() || {

+                id: parseInt(config.smsMaxId, 10) + 1,

+                time: transUnixTime($.now()),

+                number: newMsg.number

+            };

+            config.smsMaxId = latestMsg.id;

+            newMsg.id = config.smsMaxId;

+            newMsg.time = latestMsg.time;

+            newMsg.errorText = $.i18n.prop("sms_resend_fail");

+            newMsg.tag = 3;

+            newMsg.target = latestMsg.number;

+            newMsg.targetName = getNameOrNumberByNumber(targetNumber);

+            updateDBMsg(newMsg);

+            updateMsgList(newMsg);

+            deleteSingleItemClickHandler(id, function () {

+                addSendMessage(newMsg, true);

+                updateChatInputWordLength();

+                enableBtn($("#btn-send", "#inputpanel"));

+                hideLoading();

+                gotoBottom();

+            });

+        });

+    };

+

+    //滚动到底部

+    gotoBottom = function () {

+        $("#chatpanel .clear-container").animate({

+            scrollTop: $("#chatlist").height()

+        });

+    };

+

+    //最后一条短消息距离顶部的距离

+    var lastItemOffsetTop = 0;

+    //页面是否处于滚动中

+    var scrolling = false;

+    //初始化页面状态信息

+    function initStatus() {

+        currentPage = 1;

+        ready = false;

+        shownMsgs = [];

+        scrolling = false;

+        lastItemOffsetTop = 0;

+        groupDrafts = groupDraftItems = [];

+        groupedDraftsObject = {};

+		config.dbMsgs = [];

+        config.listMsgs = null;

+        config.smsMaxId = 0;

+        config.phonebook = [];

+    }

+

+    function getReadyStatus() {

+        showLoading('waiting');

+        config.currentChatObject = null;

+        var getSMSReady = function () {

+            service.getSMSReady({}, function (data) {

+                if (data.sms_cmd_status_result == "2") {

+                    $("input:button", "#smsListForm .smslist-btns").attr("disabled", "disabled");

+                    hideLoading();

+                    showAlert("sms_init_fail");

+                } else if (data.sms_cmd_status_result == "1") {

+                    addTimeout(getSMSReady, 1000);

+                } else {

+                    if (config.HAS_PHONEBOOK) {

+                        getPhoneBookReady();

+                    } else {

+                        initSMSList(false);

+                    }

+                }

+            });

+        };

+

+        var getPhoneBookReady = function () {

+            service.getPhoneBookReady({}, function (data) {

+                if (data.pbm_init_flag == "6") {

+                    initSMSList(false);

+                } else if (data.pbm_init_flag != "0") {

+                    addTimeout(getPhoneBookReady, 1000);

+                } else {

+                    initSMSList(true);

+                }

+            });

+        };

+

+        var initSMSList = function (isPbmInitOK) {

+            initStatus();

+            if (isPbmInitOK) {

+                getSMSMessages(function () {

+                    getPhoneBooks();

+                    hideLoading();

+                });

+            } else {

+                getSMSMessages(function () {

+                    config.phonebook = [];

+                    //if(config.HAS_PHONEBOOK){

+                    dealPhoneBooks();

+                    //}

+                    hideLoading();

+                });

+            }

+            bindingEvents();

+            fixScrollTop();

+            window.scrollTo(0, 0);

+            initSmsCapability();

+        };

+

+        getSMSReady();

+    }

+

+    //初始化短信容量状态

+    function initSmsCapability() {

+        var capabilityContainer = $("#smsCapability");

+        updateSmsCapabilityStatus(capabilityContainer);

+        checkSimStatusForSend();

+        addInterval(function () {

+            updateSmsCapabilityStatus(capabilityContainer);

+            checkSimStatusForSend();

+        }, 5000);

+    }

+

+    //SIM卡未准备好时,禁用发送按钮

+    function checkSimStatusForSend() {

+        var data = service.getStatusInfo();

+        if (data.simStatus != 'modem_init_complete') {

+            disableBtn($("#btn-send"));

+            $("#sendSmsErrorLi").html('<span data-trans="no_sim_card_message">' + $.i18n.prop('no_sim_card_message') + '</span>');

+            $("#chatpanel .smslist-item-resend:visible").hide();

+        } else {

+            enableBtn($("#btn-send"));

+            $("#chatpanel .smslist-item-resend:hidden").show();

+        }

+    }

+

+    //更新短信容量状态

+    function updateSmsCapabilityStatus(capabilityContainer, callback) {

+        service.getSmsCapability({}, function (capability) {

+            if (capabilityContainer != null) {

+                capabilityContainer.text("(" + (capability.nvUsed > capability.nvTotal ? capability.nvTotal : capability.nvUsed) + "/" + capability.nvTotal + ")");

+            }

+            hasCapability = capability.nvUsed < capability.nvTotal;

+            smsCapability = capability;

+            if ($.isFunction(callback)) {

+                callback();

+            }

+        });

+    }

+

+    //初始化页面及VM

+    function init() {

+        getReadyStatus();

+    }

+

+    //事件绑定

+    bindingEvents = function () {

+        var $win = $(window);

+        var $smsListBtns = $("#smslist-main .smslist-btns");

+        var offsetTop = $("#mainContainer").offset().top;

+        $win.unbind("scroll").scroll(function () {

+            if ($win.scrollTop() > offsetTop) {

+                $smsListBtns.addClass("smsListFloatButs marginnone");

+            } else {

+                $smsListBtns.removeClass("smsListFloatButs marginnone");

+            }

+            //loadData(); //由于目前数据显示是全显示,不做动态加载,因此暂时注释掉

+        });

+

+        $("#smslist-table p.checkbox").die().live("click", function () {

+            checkboxClickHandler($(this).attr("id"));

+        });

+

+        $("#smslist-checkAll", "#smsListForm").die().live("click", function () {

+            checkDeleteBtnStatus();

+        });

+

+        $("#chat-input", "#smsChatRoom").die().live("drop", function () {

+            $("#inputpanel .chatform").addClass("chatformfocus");

+            var $this = $(this);

+            $this.removeAttr("data-trans");

+            if ($this.val() == $.i18n.prop("chat_input_placehoder")) {

+                $this.val("");

+            }

+            updateChatInputWordLength();

+        }).live("focusin", function () {

+            $("#inputpanel .chatform").addClass("chatformfocus");

+            var $this = $(this);

+            $this.removeAttr("data-trans");

+            if ($this.val() == $.i18n.prop("chat_input_placehoder")) {

+                $this.val("");

+            }

+            updateChatInputWordLength();

+        }).live("focusout", function () {

+            $("#inputpanel .chatform").removeClass("chatformfocus");

+            var $this = $(this);

+            if ($this.val() == "" || $this.val() == $.i18n.prop("chat_input_placehoder")) {

+                $this.val($.i18n.prop("chat_input_placehoder")).attr("data-trans", "chat_input_placehoder");

+            }

+            updateChatInputWordLength();

+        }).live("keyup", function () {

+            updateChatInputWordLength();

+        }).live("paste", function () {

+            window.setTimeout(function () {

+                updateChatInputWordLength();

+            }, 0);

+        }).live("cut", function () {

+            window.setTimeout(function () {

+                updateChatInputWordLength();

+            }, 0);

+        }).live("drop", function () {

+            window.setTimeout(function () {

+                updateChatInputWordLength();

+            }, 0);

+        }).live("contextmenu", function () {

+            return false;

+        });

+

+        $("#name").die().live("drop", function () {

+            updateNameInputWordLength();

+        }).live("focusin", function () {

+            updateNameInputWordLength();

+        }).live("focusout", function () {

+            updateNameInputWordLength();

+        }).live("keyup", function () {

+            updateNameInputWordLength();

+        }).live("paste", function () {

+            updateNameInputWordLength();

+        }).live("cut", function () {

+            updateNameInputWordLength();

+        }).live("dragend", function () {

+            updateNameInputWordLength();

+        }).live("contextmenu", function () {

+            return false;

+        });

+

+        $("select.chosen-select-deselect", "#smsChatRoom").die().live('change', function () {

+            draftListener();

+        });

+        $("#searchInput").die().live('blur', function () {

+            searchTextBlur();

+        }).live('keyup', function () {

+            updateSearchValue($("#searchInput").val());

+        });

+    };

+

+    //更新剩余字数

+    updateNameInputWordLength = function () {

+

+        var msgInput = $("#name", "#quickSaveContactForm");

+        var msgInputDom = msgInput[0];

+        var strValue = msgInput.val();

+        var encodeType = getEncodeType(strValue);

+        var maxLength = encodeType.encodeType == 'UNICODE' ? 11 : 22;

+        while (strValue.length + encodeType.extendLen > maxLength) {

+            strValue = strValue.substring(0, strValue.length - 1);

+            msgInputDom.value = strValue;

+            encodeType = getEncodeType(strValue);

+            maxLength = encodeType.encodeType == 'UNICODE' ? 11 : 22;

+        }

+    };

+	

+//获取聊天对象的名字

+    getNameByNumber = function (num) {

+        for (var i = config.phonebook.length; i > 0; i--) {

+            if (getLastNumber(config.phonebook[i - 1].pbm_number, config.SMS_MATCH_LENGTH) == getLastNumber(num, config.SMS_MATCH_LENGTH)) {

+                return config.phonebook[i - 1].pbm_name;

+            }

+        }

+        return "";

+    };

+    //获取聊天对象的名字和号码

+    getShowNameByNumber = function (num) {

+        for (var i = config.phonebook.length; i > 0; i--) {

+            if (getLastNumber(config.phonebook[i - 1].pbm_number, config.SMS_MATCH_LENGTH) == getLastNumber(num, config.SMS_MATCH_LENGTH)) {

+                return config.phonebook[i - 1].pbm_name /* + "/" + num*/;

+            }

+        }

+        return num;

+    };

+

+    //获取聊天对象的名字,如果没有名字,则显示号码

+    getNameOrNumberByNumber = function (num) {

+        for (var i = config.phonebook.length; i > 0; i--) {

+            if (config.phonebook[i - 1].pbm_number == num) {

+                return config.phonebook[i - 1].pbm_name;

+            }

+        }

+        for (var i = config.phonebook.length; i > 0; i--) {

+            if (getLastNumber(config.phonebook[i - 1].pbm_number, config.SMS_MATCH_LENGTH) == getLastNumber(num, config.SMS_MATCH_LENGTH)) {

+                return config.phonebook[i - 1].pbm_name;

+            }

+        }

+        return num;

+    };

+

+    //点击短信列表条目,进入聊天室页面

+    smsItemClickHandler = function (num) {

+        if (chatRoomInLoading) {

+            return false;

+        }

+        chatRoomInLoading = true;

+        if (smsOtherTmpl == null) {

+            smsOtherTmpl = $.template("smsOtherTmpl", $("#smsOtherTmpl"));

+        }

+        if (smsMeTmpl == null) {

+            smsMeTmpl = $.template("smsMeTmpl", $("#smsMeTmpl"));

+        }

+

+        var name = getShowNameByNumber(num);

+        $("#chosenUser", "#smsChatRoom").hide();

+        $("#chosenUser1", "#smsChatRoom").addClass("hide");

+

+        config.currentChatObject = getLastNumber(num, config.SMS_MATCH_LENGTH);

+        setAsRead(num);

+        cleanChatInput();

+        clearChatList();

+        var userSelect = $("select.chosen-select-deselect", "#smsChatRoom");

+        var ops = $("option", userSelect);

+        var numberExist = false;

+        for (var i = 0; i < ops.length; i++) {

+            var n = ops[i];

+            if (getLastNumber(n.value, config.SMS_MATCH_LENGTH) == config.currentChatObject) {

+                num = n.value;

+                numberExist = true;

+                break;

+            }

+        }

+        if (!numberExist) {

+            userSelect.append("<option value='" + HTMLEncode(num) + "' selected='selected'>" + HTMLEncode(num) + "</option>");

+        }

+        $("select.chosen-select-deselect").val(num).trigger("chosen:updated.chosen");

+        switchPage('chat');

+        config.dbMsgs = _.sortBy(config.dbMsgs, function (e) {

+            return 0 - e.id;

+        });

+        var draftIds = [];

+        var dbMsgsTmp = [];

+        var dbMsgsTmpIds = [];

+        var chatHasDraft = false;

+        for (var i = config.dbMsgs.length - 1; i >= 0; i--) {

+            var e = config.dbMsgs[i];

+            if (_.indexOf(dbMsgsTmpIds, e.id) != -1) {

+                continue;

+            }

+            if (getLastNumber(e.number, config.SMS_MATCH_LENGTH) == config.currentChatObject && _.isEmpty(e.groupId)) {

+                e.isNew = false;

+                e.errorText = '';

+                e.targetName = '';

+                if (e.tag == "0" || e.tag == "1") {

+                    $.tmpl("smsOtherTmpl", e).appendTo("#chatlist");

+                    dbMsgsTmpIds.push(e.id);

+                    dbMsgsTmp.push(e);

+                } else if (e.tag == "2" || e.tag == "3") {

+                    $.tmpl("smsMeTmpl", e).appendTo("#chatlist");

+                    dbMsgsTmpIds.push(e.id);

+                    dbMsgsTmp.push(e);

+                } else if (e.tag == "4") {

+                    draftIds.push(e.id);

+                    $("#chat-input", "#smsChatRoom").val(e.content).removeAttr('data-trans');

+                    updateChatInputWordLength();

+                    chatHasDraft = true;

+                }

+            } else {

+                dbMsgsTmpIds.push(e.id);

+                dbMsgsTmp.push(e);

+            }

+        }

+        $("#chatlist").translate();

+        if (chatHasDraft) {

+            $("#chosenUser", "#smsChatRoom").show();

+            $("#chosenUser1", "#smsChatRoom").addClass("hide");

+        } else {

+            $("#chosenUser", "#smsChatRoom").hide();

+            $("#chosenUser1", "#smsChatRoom").removeClass("hide").html(HTMLEncode(name));

+        }

+        config.dbMsgs = dbMsgsTmp.reverse();

+        if (draftIds.length > 0) {

+            deleteDraftSms(draftIds, [num]);

+        } else {

+            checkSmsCapacityAndAlert();

+        }

+

+        checkSimStatusForSend();

+        gotoBottom();

+        chatRoomInLoading = false;

+    };

+

+    function checkSmsCapacityAndAlert() {

+        var capabilityContainer = $("#smsCapability");

+        updateSmsCapabilityStatus(capabilityContainer);

+        addTimeout(function () {

+            if (!hasCapability) {

+                showAlert("sms_capacity_is_full_for_send");

+            }

+        }, 2000);

+    }

+

+    cleanChatInput = function () {

+        $("#chat-input", "#smsChatRoom").val($.i18n.prop("chat_input_placehoder")).attr("data-trans", "chat_input_placehoder");

+    };

+

+    //设置为已读

+    setAsRead = function (num) {

+        var ids = [];

+        $.each(config.dbMsgs, function (i, e) {

+            if (getLastNumber(e.number, config.SMS_MATCH_LENGTH) == getLastNumber(num, config.SMS_MATCH_LENGTH) && e.isNew) {

+                ids.push(e.id);

+                e.isNew = false;

+            }

+        });

+        if (ids.length > 0) {

+            service.setSmsRead({

+                ids: ids

+            }, function (data) {

+                if (data.result) {

+                    $("#smslist-item-" + getLastNumber(num, config.SMS_MATCH_LENGTH) + " .smslist-item-new-count").text("").addClass("hide");

+                    $("#smslist-item-" + getLastNumber(num, config.SMS_MATCH_LENGTH)).removeClass("font-weight-bold");

+                    $("#smslist-item-" + getLastNumber(num, config.SMS_MATCH_LENGTH) + " td:nth-child(2)").removeClass("font-weight-bold");

+                }

+                $.each(config.listMsgs, function (i, e) {

+                    if (e.number == num && e.newCount > 0) {

+                        e.newCount = 0;

+                    }

+                });

+            });

+        }

+    };

+

+    //转发按钮点击事件

+    forwardClickHandler = function (id) {

+        var selectedContact = syncSelectAndChosen($("select#chosenUserSelect"), $('.search-choice', '#chosenUserSelect_chosen'));

+        var content = $("#chat-input", "#smsChatRoom").val();

+        var hasContent = typeof content != "undefined" && content != '' && content != $.i18n.prop('chat_input_placehoder');

+        if (hasContent) {

+            saveDraftAction({

+                content: content,

+                numbers: selectedContact,

+                isFromBack: true,

+                noLoading: true

+            });

+        }

+

+        clearChatList();

+        config.currentChatObject = null;

+

+        $("#chosenUser1", "#smsChatRoom").addClass("hide");

+        $("#chosenUser", "#smsChatRoom").show();

+        for (var j = 0; j < config.dbMsgs.length; j++) {

+            if (config.dbMsgs[j].id == id) {

+                var theChatInput = $("#chat-input", "#smsChatRoom");

+                theChatInput.val(config.dbMsgs[j].content);

+                setInsertPos(theChatInput[0], config.dbMsgs[j].content.length);

+            }

+        }

+        updateChatInputWordLength();

+        $("select.chosen-select-deselect").val("").trigger("chosen:updated.chosen");

+        addTimeout(function () {

+            $("#chosen-search-field-input").focus();

+        }, 300);

+        switchPage('chat');

+        gotoBottom();

+    };

+

+    //更新剩余字数

+    updateChatInputWordLength = function () {

+        var msgInput = $("#chat-input", "#smsChatRoom");

+        var msgInputDom = msgInput[0];

+        var strValue = msgInput.val();

+        var encodeType = getEncodeType(strValue);

+        var maxLength = encodeType.encodeType == 'UNICODE' ? 335 : 765;

+        if (strValue.length + encodeType.extendLen > maxLength) {

+            var scrollTop = msgInputDom.scrollTop;

+            var insertPos = getInsertPos(msgInputDom);

+            var moreLen = strValue.length + encodeType.extendLen - maxLength;

+            var insertPart = strValue.substr(insertPos - moreLen > 0 ? insertPos - moreLen : 0, moreLen);

+            var reversed = insertPart.split('').reverse();

+            var checkMore = 0;

+            var cutNum = 0;

+            for (var i = 0; i < reversed.length; i++) {

+                if (getEncodeType(reversed[i]).extendLen > 0) {

+                    checkMore += 2;

+                } else {

+                    checkMore++;

+                }

+                if (checkMore >= moreLen) {

+                    cutNum = i + 1;

+                    break;

+                }

+            }

+            var iInsertToStartLength = insertPos - cutNum;

+            msgInputDom.value = strValue.substr(0, iInsertToStartLength) + strValue.substr(insertPos);

+            if (msgInputDom.value.length > maxLength) {

+                msgInputDom.value = msgInputDom.value.substr(0, maxLength);

+            }

+            setInsertPos(msgInputDom, iInsertToStartLength);

+            msgInputDom.scrollTop = scrollTop;

+        }

+        var textLength = 0;

+        var newValue = $(msgInputDom).val();

+        var newEncodeType = {

+            encodeType: 'GSM7_default',

+            extendLen: 0

+        };

+        if (newValue != $.i18n.prop('chat_input_placehoder')) {

+            newEncodeType = getEncodeType(newValue);

+        }

+        var newMaxLength = newEncodeType.encodeType == 'UNICODE' ? 335 : 765;

+        var $inputCount = $("#inputcount", "#inputpanel");

+        var $inputItemCount = $("#inputItemCount", "#inputpanel");

+        if (newValue.length + newEncodeType.extendLen >= newMaxLength) {

+            $inputCount.addClass("colorRed");

+            $inputItemCount.addClass("colorRed");

+        } else {

+            $("#inputcount", "#inputpanel").removeClass("colorRed");

+            $("#inputItemCount", "#inputpanel").removeClass("colorRed");

+        }

+        if ("" != newValue && $.i18n.prop('chat_input_placehoder') != newValue) {

+            textLength = newValue.length + newEncodeType.extendLen;

+        }

+        $inputCount.html("(" + textLength + "/" + newMaxLength + ")");

+        $inputItemCount.html("(" + getSmsCount(newValue) + "/5)");

+        draftListener();

+    };

+

+    //文档内容监听,判断是否修改过

+    function draftListener() {

+        var content = $("#chat-input", "#smsChatRoom").val();

+        if (hasCapability) {

+            var selectedContact = getSelectValFromChosen($('.search-choice', '#chosenUserSelect_chosen'));

+            var noContactSelected = !selectedContact || selectedContact.length == 0;

+            var hasContent = typeof content != "undefined" && content != '' && content != $.i18n.prop('chat_input_placehoder');

+

+            if (!hasContent) {

+                config.resetContentModifyValue();

+                return;

+            }

+            if (hasContent && !noContactSelected) {

+                config.CONTENT_MODIFIED.modified = true;

+                config.CONTENT_MODIFIED.message = 'sms_to_save_draft';

+                config.CONTENT_MODIFIED.callback.ok = saveDraftAction;

+                config.CONTENT_MODIFIED.callback.no = $.noop;

+                config.CONTENT_MODIFIED.data = {

+                    content: $("#chat-input", "#smsChatRoom").val(),

+                    numbers: selectedContact

+                };

+                return;

+            }

+            if (hasContent && noContactSelected) {

+                config.CONTENT_MODIFIED.modified = true;

+                config.CONTENT_MODIFIED.message = 'sms_no_recipient';

+                config.CONTENT_MODIFIED.callback.ok = $.noop;

+                config.CONTENT_MODIFIED.callback.no = function () {

+                    // 返回true,页面保持原状

+                    return true;

+                }; //$.noop;

+                return;

+            }

+        } else {

+            config.resetContentModifyValue();

+        }

+    }

+

+    //保存草稿回调动作

+    function saveDraftAction(data) {

+        var datetime = new Date();

+        var params = {

+            index: -1,

+            currentTimeString: getCurrentTimeString(datetime),

+            groupId: data.numbers.length > 1 ? datetime.getTime() : '',

+            message: data.content,

+            numbers: data.numbers

+        };

+        !data.noLoading && showLoading('waiting');

+        service.saveSMS(params, function () {

+            if (data.isFromBack) {

+                getLatestDraftSms(data.numbers);

+                !data.noLoading && successOverlay('sms_save_draft_success');

+            } else {

+                !data.noLoading && successOverlay('sms_save_draft_success');

+            }

+        }, function () {

+            !data.noLoading && errorOverlay("sms_save_draft_failed")

+        });

+

+        //获取最新的草稿信息

+        function getLatestDraftSms(numbers) {

+            service.getSMSMessages({

+                page: 0,

+                smsCount: 5,

+                nMessageStoreType: 1,

+                tags: 4,

+                orderBy: "order by id desc"

+            }, function (data) {

+                if (data.messages && data.messages.length > 0) {

+                    var theGroupId = '',

+                    draftShowName = '',

+                    draftShowNameTitle = '',

+                    i = 0,

+                    drafts = [];

+                    for (; i < data.messages.length; i++) {

+                        var msg = data.messages[i];

+                        for (var k = 0; k < numbers.length; k++) {

+                            var num = numbers[k];

+                            if (getLastNumber(num, config.SMS_MATCH_LENGTH) == getLastNumber(msg.number, config.SMS_MATCH_LENGTH)) { //if (num.indexOf(msg.number) == 0) {

+                                msg.number = num;

+                            }

+                        }

+                        if (theGroupId != '' && theGroupId != msg.groupId) {

+                            break;

+                        }

+                        updateDBMsg(msg);

+                        if (msg.groupId == '') { // 单条草稿

+                            break;

+                        } else { // 多条草稿

+                            theGroupId = msg.groupId;

+                            var showName = getShowNameByNumber(msg.number);

+                            draftShowName += (i == 0 ? '' : ';') + showName;

+                            draftShowNameTitle += (i == 0 ? '' : ';') + showName;

+                        }

+                        drafts.push(msg);

+                    }

+                    if (theGroupId == '') { // 单条草稿

+                        var msg = data.messages[0];

+                        msg.hasDraft = true;

+                        updateMsgList(msg);

+                    } else { // 多条草稿

+                        var msg = data.messages[0];

+                        var len = 10;

+                        if (getEncodeType(draftShowName).encodeType == "UNICODE") {

+                            len = 10;

+                        }

+                        msg.draftShowNameTitle = draftShowNameTitle;

+                        msg.draftShowName = draftShowName.length > len ? draftShowName.substring(0, len) + "..." : draftShowName;

+                        msg.hasDraft = true;

+                        msg.totalCount = i;

+                        groupedDraftsObject[theGroupId] = drafts;

+                        updateMsgList(msg);

+                    }

+                    tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), $(".smslist-item", "#smslist-table").length);

+                }

+            }, function () {

+                // do nothing

+            });

+        }

+    }

+

+    //点击群聊草稿进入草稿发送页面 在进入的过程中会先删掉草稿

+    draftSmsItemClickHandler = function (groupId) {

+        if (chatRoomInLoading) {

+            return false;

+        }

+        chatRoomInLoading = true;

+        var msgs = groupedDraftsObject[groupId];

+        var numbers = [];

+        var ids = [];

+        for (var i = 0; msgs && i < msgs.length; i++) {

+            numbers.push(getLastNumber(msgs[i].number, config.SMS_MATCH_LENGTH));

+            ids.push(msgs[i].id + '');

+        }

+        $("#chosenUser", "#smsChatRoom").show();

+        $("#chosenUser1", "#smsChatRoom").addClass("hide").html('');

+        $("select.chosen-select-deselect").val(numbers).trigger("chosen:updated.chosen");

+        $("#chat-input", "#smsChatRoom").val(msgs[0].content);

+        updateChatInputWordLength();

+        clearChatList();

+        switchPage('chat');

+        draftListener();

+        gotoBottom();

+        chatRoomInLoading = false;

+        deleteMultiDraftSms(ids, groupId);

+    };

+

+    //按列表条目删除短消息

+    deletePhoneMessageClickHandler = function (num) {

+        showConfirm("confirm_sms_delete", function () {

+            showLoading('deleting');

+            var ids = [];

+            $.each(config.dbMsgs, function (i, e) {

+                if (e.number == num) {

+                    ids.push(e.id);

+                }

+            });

+            service.deleteMessage({

+                ids: ids

+            }, function (data) {

+                $("#smslist-item-" + getLastNumber(num, config.SMS_MATCH_LENGTH)).hide().remove();

+                synchSmsList([num], ids);

+                successOverlay();

+                tryToDisableCheckAll($("#smslist-checkAll", "#smsListForm"), $(".smslist-item", "#smslist-table").length);

+            }, function (error) {

+                errorOverlay(error.errorText);

+            });

+        });

+    };

+

+    //同步短信列表数据

+    synchSmsList = function (nums, ids) {

+        if (nums && nums.length > 0) {

+            config.listMsgs = $.grep(config.listMsgs, function (n, i) {

+                return $.inArray(n.number, nums) == -1;

+            });

+        }

+        if (ids && ids.length > 0) {

+            var dbMsgsTmp = [];

+            $.each(config.dbMsgs, function (i, e) {

+                if ($.inArray(e.id, ids) == -1) {

+                    dbMsgsTmp.push(e);

+                }

+            });

+            config.dbMsgs = dbMsgsTmp;

+        }

+    };

+

+    //确定最后一条短消息距离顶部的距离

+    function fixScrollTop() {

+        var items = $(".smslist-item");

+        var lastOne;

+        if (items.length > 0) {

+            lastOne = items[items.length - 1];

+        } else {

+            lastOne = items[0];

+        }

+        lastItemOffsetTop = lastOne ? lastOne.offsetTop : 600;

+    }

+

+    function loadData() {

+        if (ready && !scrolling && lastItemOffsetTop < ($(window).scrollTop() + $(window).height())

+             && $(".smslist-item").length != config.listMsgs.length) {

+            scrolling = true;

+            addTimeout(function () {

+                removeChecked("smslist-checkAll");

+                changeShownMsgs();

+                fixScrollTop();

+                scrolling = false;

+            }, 100);

+        }

+    }

+

+    function stopNavigation() {

+        disableBtn($('#btn-back'));

+        $('a', '#left').bind("click", function () {

+            return false;

+        });

+        $('a', '#list-nav').bind("click", function () {

+            return false;

+        });

+    }

+

+    function restoreNavigation() {

+        enableBtn($('#btn-back'));

+        $('a', '#left').unbind("click");

+        $('a', '#list-nav').unbind("click");

+    }

+

+    function searchTable(key) {

+        key = $.trim(key);

+        var $trs = $('tr', '#smslist-table'),

+        trLength = $trs.length;

+        if (key == '') {

+            $trs.show();

+            return false;

+        }

+        $trs.hide();

+        while (trLength) {

+            var $tr = $($trs[trLength - 1]),

+            $tds = $('td', $tr),

+            tdLength = $tds.length;

+            while (tdLength - 1) {

+                var $td = $($tds[tdLength - 1]);

+                if ($td.text().toLowerCase().indexOf(key.toLowerCase()) != -1) {

+                    $tr.show();

+                    break;

+                }

+                tdLength--;

+            }

+            trLength--;

+        }

+

+        addTimeout(function () {

+            $(":checkbox:checked", "#addPhonebookContainer").removeAttr('checked');

+            vm.selectedItemIds([]);

+            vm.freshStatus($.now());

+            renderCheckbox();

+        }, 300);

+        return true;

+    }

+	updateSearchValue = function (key) {

+        if (key == "" || key == $.i18n.prop("search")) {

+            return true;

+        }

+        searchTable(key);

+    };

+	//清除搜索关键字事件

+    clearSearchKey = function () {

+        updateSearchValue($.i18n.prop("search"));

+        $("#searchInput").addClass("ko-grid-search-txt-default").attr("data-trans", "search");

+    };

+    //点击搜索输入框事件

+    searchTextClick = function () {

+        var searchText = $("#searchInput");

+        if (searchText.hasClass("ko-grid-search-txt-default")) {

+            updateSearchValue("");

+            searchText.val("");

+            searchText.removeClass("ko-grid-search-txt-default").removeAttr("data-trans");

+        }

+    };

+    //离开搜索输入框事件

+    searchTextBlur = function () {

+        var txt = $.trim($("#searchInput").val()).toLowerCase();

+        if (txt == "") {

+            clearSearchKey();

+        }

+    };

+	

+    window.smsUtil = {

+        changeLocationHandler: function (ele) {

+            if ($(ele).val() == 'sim') {

+                window.location.hash = '#msg_sim';

+            } else {

+                window.location.hash = '#msg_main';

+            }

+        }

+    };

+

+    return {

+        init: init

+    };

+});

+

+define("sms_set","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var validityModes = _.map(config.SMS_VALIDITY, function (item) {

+        return new Option(item.name, item.value);

+    });

+

+    function SmsSetViewMode() {

+        var target = this;

+        var setting = getSmsSetting();

+        target.modes = ko.observableArray(validityModes);

+        target.selectedMode = ko.observable(setting.validity);

+        target.centerNumber = ko.observable(setting.centerNumber);

+        target.deliveryReport = ko.observable(setting.deliveryReport);

+

+        target.clear = function () {

+            init();

+            clearValidateMsg();

+        };

+

+        target.save = function () {

+            showLoading('waiting');

+            var params = {};

+            params.validity = target.selectedMode();

+            params.centerNumber = target.centerNumber();

+            params.deliveryReport = target.deliveryReport();

+            service.setSmsSetting(params, function (result) {

+                if (result.result == "success") {

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+        };

+    }

+

+    //获取短信设置参数

+

+    function getSmsSetting() {

+        return service.getSmsSetting();

+    }

+

+    function init() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var vm = new SmsSetViewMode();

+        ko.applyBindings(vm, container[0]);

+        $('#smsSettingForm').validate({

+            submitHandler: function () {

+                vm.save();

+            },

+            rules: {

+                txtCenterNumber: "sms_service_center_check"

+            }

+        });

+    }

+

+    return {

+        init: init

+    };

+});

+

+define("sms_sim_messages","jquery knockout set service".split(" "),

+    function ($, ko, config, service) {

+    var simMsgListTmpl = null;

+    //每页记录条数

+    var perPage = 200;

+

+    //获取短信分页记录

+    function getSMSMessages() {

+        return service.getSMSMessages({

+            page: 0,

+            smsCount: perPage,

+            nMessageStoreType: 0,

+            tags: 10,

+            orderBy: "order by id desc"

+        }, function (data) {

+            tryToDisableCheckAll($("#simMsgList-checkAll"), data.messages.length);

+            dealPhoneBooks(data.messages);

+        }, function (data) {

+            dealPhoneBooks([]);

+        });

+    }

+

+    //短信显示联系人名字,并将结果显示在UI

+    function dealPhoneBooks(messages) {

+        $.each(messages, function (j, n) {

+            n.itemId = getLastNumber(n.number, config.SMS_MATCH_LENGTH);

+            for (var i = 0; i < config.phonebook.length; i++) {

+                var person = config.phonebook[i];

+                if (n.itemId == getLastNumber(person.pbm_number, config.SMS_MATCH_LENGTH)) {

+                    n.name = person.pbm_name;

+                    break;

+                }

+            }

+        });

+        renderSimMessageList(messages);

+    }

+

+    //清楚短信列表内容

+    cleanSimSmsList = function () {

+        $("#simMsgList_container").empty();

+    };

+

+    //将短信显示结果显示在UI

+    function renderSimMessageList(messages) {

+        if (simMsgListTmpl == null) {

+            simMsgListTmpl = $.template("simMsgListTmpl", $("#simMsgListTmpl"));

+        }

+        cleanSimSmsList();

+        $("#simMsgList_container").html($.tmpl("simMsgListTmpl", {

+                data: messages

+            }));

+        hideLoading();

+    }

+

+    //初始化电话本信息

+    function initPhoneBooks(cb) {

+        service.getPhoneBooks({

+            page: 0,

+            data_per_page: 2000,

+            orderBy: "name",

+            isAsc: true

+        }, function (books) {

+            if ($.isArray(books.pbm_data) && books.pbm_data.length > 0) {

+                config.phonebook = books.pbm_data;

+            } else {

+                config.phonebook = [];

+            }

+            cb();

+        }, function () {

+            errorOverlay();

+        });

+    }

+

+    function simSmsViewMode() {

+        var self = this;

+        start();

+    }

+

+    //短信删除事件处理

+    deleteSelectedSimMsgClickHandler = function () {

+        var checkbox = $("input[name=msgId]:checked", "#simMsgList_container");

+        var msgIds = [];

+        for (var i = 0; i < checkbox.length; i++) {

+            msgIds.push($(checkbox[i]).val());

+        }

+        if (msgIds.length == 0) {

+            return false;

+        }

+        showConfirm("confirm_sms_delete", function () {

+            showLoading('deleting');

+            service.deleteMessage({

+                ids: msgIds

+            }, function (data) {

+                removeChecked("simMsgList-checkAll");

+                disableBtn($("#simMsgList-delete"));

+                var idsForDelete = "";

+                checkbox.each(function (i, n) {

+                    idsForDelete += ".simMsgList-item-class-" + $(n).val() + ",";

+                });

+                if (idsForDelete.length > 0) {

+                    $(idsForDelete.substring(0, idsForDelete.length - 1)).hide().remove();

+                }

+                tryToDisableCheckAll($("#simMsgList-checkAll"), $(".smslist-item", "#simMsgList_container").length);

+                successOverlay();

+            }, function (error) {

+                errorOverlay(error.errorText);

+            });

+            //删除短信后需要刷新列表

+            updateSimSmsCapabilityStatus($("#simSmsCapability"));

+        });

+    };

+    //将被checked的条目添加到self.checkedItem中,用于在滚动还原checkbox

+    function checkboxClickHandler() {

+        if (getSelectedItemSize() == 0) {

+            disableBtn($("#simMsgList-delete"));

+        } else {

+            enableBtn($("#simMsgList-delete"));

+        }

+    }

+

+    //获取已选择的条目

+    function getSelectedItemSize() {

+        return $("input:checkbox:checked", '#simMsgList_container').length;

+    }

+

+    //模块开始,检查电话本及短信状态并加装页码数据

+    function start() {

+        showLoading('waiting');

+        var getSMSReady = function () {

+            service.getSMSReady({}, function (data) {

+                if (data.sms_cmd_status_result == "2") {

+                    hideLoading();

+                    showAlert("sms_init_fail");

+                } else if (data.sms_cmd_status_result == "1") {

+                    addTimeout(function () {

+                        getSMSReady();

+                    }, 1000);

+                } else {

+                    if (!config.HAS_PHONEBOOK) {

+                        initSMSList(config.HAS_PHONEBOOK);

+                    } else {

+                        getPhoneBookReady();

+                    }

+                }

+            });

+        };

+

+        var getPhoneBookReady = function () {

+            service.getPhoneBookReady({}, function (data) {

+                if (data.pbm_init_flag == "6") {

+                    initSMSList(false);

+                } else if (data.pbm_init_flag != "0") {

+                    addTimeout(function () {

+                        getPhoneBookReady();

+                    }, 1000);

+                } else {

+                    initSMSList(config.HAS_PHONEBOOK);

+                }

+            });

+        };

+

+        var initSMSList = function (isPbmInitOK) {

+            if (isPbmInitOK) {

+                initPhoneBooks(function () {

+                    getSMSMessages();

+                });

+            } else {

+                config.phonebook = [];

+                getSMSMessages();

+            }

+        };

+        getSMSReady();

+        initSimSmsCapability();

+    }

+

+    //初始化短信容量状态

+    function initSimSmsCapability() {

+        var capabilityContainer = $("#simSmsCapability");

+        updateSimSmsCapabilityStatus(capabilityContainer);

+        addInterval(function () {

+            updateSimSmsCapabilityStatus(capabilityContainer);

+        }, 5000);

+    }

+

+    //更新短信容量状态

+    function updateSimSmsCapabilityStatus(capabilityContainer) {

+        service.getSmsCapability({}, function (capability) {

+            if (capabilityContainer != null) {

+                capabilityContainer.text("(" + capability.simUsed + "/" + capability.simTotal + ")");

+            }

+        });

+    }

+

+    //清除搜索关键字事件

+    clearSearchKey = function () {

+        updateSearchValue($.i18n.prop("search"));

+        $("#searchInput").addClass("ko-grid-search-txt-default").attr("data-trans", "search");

+    };

+    //点击搜索输入框事件

+    searchTextClick = function () {

+        var searchText = $("#searchInput");

+        if (searchText.hasClass("ko-grid-search-txt-default")) {

+            updateSearchValue("");

+            searchText.val("");

+            searchText.removeClass("ko-grid-search-txt-default").removeAttr("data-trans");

+        }

+    };

+    //离开搜索输入框事件

+    searchTextBlur = function () {

+        var txt = $.trim($("#searchInput").val()).toLowerCase();

+        if (txt == "") {

+            clearSearchKey();

+        }

+    };

+

+    updateSearchValue = function (key) {

+        if (key == "" || key == $.i18n.prop("search")) {

+            return true;

+        }

+        searchTable(key);

+    }

+

+    function searchTable(key) {

+        key = $.trim(key);

+        var $trs = $('tr', '#smslist-table'),

+        trLength = $trs.length;

+        if (key == '') {

+            $trs.show();

+            return false;

+        }

+        $trs.hide();

+        while (trLength) {

+            var $tr = $($trs[trLength - 1]),

+            $tds = $('td', $tr),

+            tdLength = $tds.length;

+            while (tdLength - 1) {

+                var $td = $($tds[tdLength - 1]);

+                if ($td.text().toLowerCase().indexOf(key.toLowerCase()) != -1) {

+                    $tr.show();

+                    break;

+                }

+                tdLength--;

+            }

+            trLength--;

+        }

+

+        addTimeout(function () {

+            $(":checkbox:checked", "#addPhonebookContainer").removeAttr('checked');

+            vm.selectedItemIds([]);

+            vm.freshStatus($.now());

+            renderCheckbox();

+        }, 300);

+        return true;

+    }

+

+    //点击短信列表条目

+    simsmsItemClickHandler = function (tag, id, num) {

+        if (tag == "1") {

+            var ids = [];

+            ids.push(id);

+            service.setSmsRead({

+                ids: ids

+            }, function (data) {

+                if (data.result) {

+                    $(".simMsgList-item-class-" + id, "#simMsgTableContainer").removeClass('font-weight-bold');

+                }

+            });

+        }

+    }

+

+    //页面事件绑定

+    function initEventBind() {

+        $(".smslist-item-msg", "#simMsgTableContainer").die().live("click", function () {

+            var $this = $(this).addClass('showFullHeight');

+            $('.smslist-item-msg.showFullHeight', '#simMsgTableContainer').not($this).removeClass('showFullHeight');

+        });

+        $("#simMsgList_container p.checkbox, #simMsgListForm #simMsgList-checkAll").die().live("click", function () {

+            checkboxClickHandler();

+        });

+        $("#searchInput").die().live('blur', function () {

+            searchTextBlur();

+        }).live('keyup', function () {

+            updateSearchValue($("#searchInput").val());

+        });

+    }

+

+    //模块初始化开始

+    function init() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var vm = new simSmsViewMode();

+        ko.applyBindings(vm, container[0]);

+        initEventBind();

+    }

+

+    window.smsUtil = {

+        changeLocationHandler: function (ele) {

+            if ($(ele).val() == 'sim') {

+                window.location.hash = '#msg_sim';

+            } else {

+                window.location.hash = '#msg_main';

+            }

+        }

+    };

+

+    return {

+        init: init

+    };

+});

diff --git a/ap/app/zte_webui/js/wifi.js b/ap/app/zte_webui/js/wifi.js
new file mode 100755
index 0000000..725e2bc
--- /dev/null
+++ b/ap/app/zte_webui/js/wifi.js
@@ -0,0 +1,3726 @@
+define("wifi_advance","underscore jquery knockout set service jqui".split(" "),

+    function (_, $, ko, config, service, jqui) {

+    var $sliderRange = null;

+    //当前是否WiFi连接

+    var viaWifi = false;

+

+    function paintRateOption(data) {

+        var opts = [];

+        for (var i = 0; i < data.length; i++) {

+            var rate = data[i].rate == 0 ? "Auto" : data[i].rate + " Mbps";

+            opts.push(new Option(rate, data[i].index));

+        }

+        return opts;

+    }

+

+    //wifi传输速率

+    var transpeed = [0, 1, 2, 5.5, 6, 6.5, 9, 11, 12, 13, 18, 19.5, 24, 26, 36, 39, 48, 52, 54, 58.5, 65];

+

+    function rateSort(a, b) {

+        return a.rate - b.rate;

+    }

+    //删除重复速率值

+    function unionRate(rateTable) {

+        var rates = [],

+        result = [];

+        for (var i = 0; i < rateTable.length; i++) {

+            for (var j = 0; j < rateTable[i].length; j++) {

+                if (ko.utils.arrayIndexOf(rates, rateTable[i][j]) == -1) {

+                    rates.push(rateTable[i][j]);

+                    result.push({

+                        index: rateTable[i][j],

+                        rate: transpeed[rateTable[i][j]]

+                    });

+                }

+            }

+        }

+        result.sort(rateSort);

+        return result;

+    }

+

+    //根据模式生成速率选项

+    function modeRateOption(wifimode) {

+        var wifimodeN = [0, 5, 9, 11, 13, 15, 17, 19, 20];

+        var wifimodeG = [0, 4, 6, 8, 10, 12, 14, 16, 18];

+        var wifimodeB = [0, 1, 2, 3, 7];

+        var rate = [];

+

+        switch (wifimode) {

+            //--wifimode

+        case '5':

+            rate.push(wifimodeN);

+            rate.push(wifimodeG);

+            rate.push(wifimodeB);

+            break;

+        case '4':

+            rate.push(wifimodeN);

+            rate.push(wifimodeG);

+            rate.push(wifimodeB);

+            break;

+        case '3':

+            rate.push(wifimodeG);

+            rate.push(wifimodeB);

+            break;

+        case '2':

+            rate.push(wifimodeN);

+            break;

+        case '1':

+            rate.push(wifimodeG);

+            break;

+        case '0':

+            rate.push(wifimodeB);

+            break;

+

+        default:

+            rate.push(wifimodeN);

+            break;

+        }

+        var union = unionRate(rate);

+        return paintRateOption(union);

+    }

+

+    function getCountryCode(country) {

+        var countryCodeArr = config.countryCode;

+        var type = '';

+        for (key in countryCodeArr) {

+            var codes = countryCodeArr[key];

+            if ($.inArray(country, codes) != -1) {

+                type = key;

+                break;

+            }

+        }

+        var typeCode = config.countryCodeType[type];

+        return typeCode ? typeCode : "0";

+    }

+

+    function channelOption(country) {

+        var showOption = [new Option('Auto', '0')];

+        var type = getCountryCode(country) + '';

+        switch (type) {

+            //--type

+        case '9':

+            generateChannelOption(showOption, 2307, 13);

+            break;

+        case '7':

+            generateChannelOption(showOption, 2307, 13);

+            generateChannelOption(showOption, 2407, 11);

+            generateChannelOption(showOption, 2462, 2);

+            break;

+        case '3':

+            generateChannelOption(showOption, 2407, 11);

+            generateChannelOption(showOption, 2462, 2);

+            break;

+            //--type

+        case '2':

+            generateChannelOption(showOption, 2307, 13);

+            generateChannelOption(showOption, 2407, 11);

+            break;

+        case '1':

+            generateChannelOption(showOption, 2407, 11);

+            break;

+        default:

+            generateChannelOption(showOption, 2407, 11);

+        }

+        return showOption;

+    }

+    function generateChannelOption(showOption, start, count) {

+        for (var i = 1; i <= count; i++) {

+            var txt = start + i * 5 + "MHz (Channel " + showOption.length + ")";

+            showOption.push(new Option(txt, showOption.length + "_" + (start + i * 5)));

+        }

+    }

+

+    function channelOption5g(country) {

+        for (key in config.countryCode_5g) {

+            var item = config.countryCode_5g[key];

+            if ($.inArray(country, item.codes) != -1) {

+                return generate5gChannelOption(item.channels);

+            }

+        }

+        return [new Option('Auto', '0')];

+    }

+    function generate5gChannelOption(channels) {

+        var showOption = [new Option('Auto', '0')];

+        for (var i = 0; i < channels.length; i++) {

+            var channel = channels[i];

+            var mhz = channel * 5 + 5000;

+            var txt = mhz + "MHz (Channel " + channel + ")";

+            showOption.push(new Option(txt, channel + "_" + (mhz)));

+        }

+        return showOption;

+    }

+

+    function getBandOptions() {

+        var showOption = [];

+        if (!config.WIFI_HAS_5G) {

+            showOption.push(new Option('2.4GHz', 'b'));

+        } else {

+            showOption.push(new Option('5GHz', 'a'));

+            showOption.push(new Option('2.4GHz', 'b'));

+        }

+        return showOption;

+    }

+

+    function getChannelBandwidthsOptions(isSupport40) {

+        var showOption = [];

+        if (isSupport40) {

+            showOption.push(new Option('20MHz', '0'));

+            showOption.push(new Option('20MHz/40MHz', '1'));

+        } else {

+            showOption.push(new Option('20MHz', '0'));

+        }

+        return showOption;

+    }

+

+    function countryCodeOption(is5G) {

+        var countries = is5G ? config.countries_5g : config.countries;

+        var showOption = [];

+        for (key in countries) {

+            showOption.push(new Option(countries[key], key));

+        }

+        showOption = _.sortBy(showOption, function (opt) {

+            return opt.text;

+        });

+        return showOption;

+    }

+

+    function getWifiAdvance() {

+        return service.getWifiAdvance();

+    }

+

+    function getWpsState() {

+        return service.getWpsInfo();

+    }

+

+    function getModeOption(wifiBand) {

+        var modes = wifiBand == 'a' ? config.NETWORK_MODES_BAND : config.NETWORK_MODES;

+        if (wifiBand == 'a') {

+            $("#mode").hide();

+            $("#modeFor5HZ").show();

+            $("#modeLabel").attr('for', 'modeFor5HZ');

+        } else if (modes.length == 1) {

+            $("#mode").hide();

+            $("#modeFor5HZ").hide();

+        } else {

+            $("#mode").show();

+            $("#modeFor5HZ").hide();

+        }

+        var modeOptions = [];

+        for (var i = 0; i < modes.length; i++) {

+            modeOptions.push(new Option(modes[i].name, modes[i].value));

+        }

+        return modeOptions;

+    }

+

+    function getSelectedRateV(rate, rates) {

+        for (var i = 0; i < rates.length; i++) {

+            var opt = rates[i];

+            if (opt.text == rate + " Mbps") {

+                return opt.value;

+            }

+        }

+        return '0';

+    }

+    //获取所选的信道对应的value值

+    function getSelectedChannelV(channel, channels) {

+        for (var i = 0; i < channels.length; i++) {

+            var opt = $(channels[i]);

+            if (opt.val().split("_")[0] == channel) {

+                return opt.val();

+            }

+        }

+        return '0';

+    }

+

+    function WifiAdvanceViewModel() {

+        // Data

+        var target = this;

+

+        var wifiInfo = service.getWifiAdvance();

+        target.origin_ap_station_enable = wifiInfo.ap_station_enable;

+        target.modes = ko.observableArray(getModeOption(wifiInfo.wifiBand));

+        target.bands = ko.observableArray(getBandOptions());

+

+        var countryOpts = countryCodeOption(wifiInfo.wifiBand == 'a');

+        target.countries = ko.observableArray(countryOpts);

+        target.channels = ko.observableArray(wifiInfo.wifiBand == 'a' ? channelOption5g(wifiInfo.countryCode) : channelOption(wifiInfo.countryCode));

+        target.rates = ko.observableArray(modeRateOption(wifiInfo.mode));

+

+        target.hasAPStation = config.AP_STATION_SUPPORT;

+        target.hasWifiSwitch = config.WIFI_SWITCH_SUPPORT;

+        target.hasMultiSSID = config.HAS_MULTI_SSID;

+        target.hasWlanMacfilter = config.HAS_BLACK_AND_WHITE_FILTER;

+        target.hasWifiBand = ko.observable(config.WIFI_BAND_SUPPORT);

+        target.hasBandwidth = ko.observable(config.WIFI_BANDWIDTH_SUPPORT);

+

+        target.selectedMode = ko.observable(wifiInfo.mode);

+        target.selectedChannel = ko.observable(getSelectedChannelV(wifiInfo.channel, target.channels()));

+        target.selectedChannelBandwidth = ko.observable(wifiInfo.bandwidth); //5:a, 2.5:b

+        target.selectedCountry = ko.observable(wifiInfo.countryCode.toUpperCase());

+        target.selectedBand = ko.observable(wifiInfo.wifiBand); //5:a, 2.5:b

+        target.selectedRate = ko.observable(getSelectedRateV(wifiInfo.rate, target.rates()));

+

+        var baseInfo = service.getWifiBasic();

+        target.wifi_enable = ko.observable(baseInfo.wifi_enable);

+        if (config.HAS_MULTI_SSID && ((baseInfo.m_AuthMode == "OPEN" && baseInfo.m_encryptType == "WEP") || (baseInfo.m_AuthMode == "SHARED" && baseInfo.m_encryptType == "WEP") || baseInfo.m_encryptType == "TKIP")) {

+            target.isF = ko.observable(true);

+        } else if ((baseInfo.AuthMode == "OPEN" && baseInfo.encryptType == "WEP") || (baseInfo.AuthMode == "SHARED" && baseInfo.encryptType == "WEP") || baseInfo.encryptType == "TKIP") {

+            target.isF = ko.observable(true);

+        } else {

+            target.isF = ko.observable(false);

+        }

+        target.isShowSSIDInfoDiv = ko.observable(false);

+        if (config.WIFI_SWITCH_SUPPORT) {

+            if (baseInfo.wifi_enable == "1") {

+                target.isShowSSIDInfoDiv(true);

+            } else {

+                target.isShowSSIDInfoDiv(false);

+            }

+        } else {

+            target.isShowSSIDInfoDiv(true);

+        }

+        target.multi_ssid_enable = ko.observable(baseInfo.multi_ssid_enable);

+        target.origin_multi_ssid_enable = baseInfo.multi_ssid_enable;

+        target.maxStationNumber = ko.observable(wifiInfo.MAX_Station_num);

+        target.selectedStation = ko.observable(wifiInfo.MAX_Access_num);

+        target.selectedStationM = ko.observable(wifiInfo.m_MAX_Access_num);

+

+        target.oneBandTrans = ko.observable(wifiInfo.wifiBand == 'a' ? '5G' : '2.4G');

+        target.oneModeTrans = ko.observable((wifiInfo.wifiBand == 'a' ? 'network_modes_band_select_' : 'network_mode_select_') + wifiInfo.mode);

+

+        target.channelBandwidths = ko.computed(function () {

+            if (config.WIFI_BANDWIDTH_SUPPORT_40MHZ) {

+                return getChannelBandwidthsOptions(true);

+            } else {

+                return getChannelBandwidthsOptions(false);

+            }

+        });

+

+        wifiInfo = $.extend(wifiInfo, target);

+

+        //Event Handler 频段切换时更新对应的国家/地区码、信道和网络模式选项

+        target.bandChangeHandler = function () {

+            if (target.selectedBand() == 'a') { //5g

+                //802.11a only   802.11n only   802.11a/n

+                target.modes(getModeOption(target.selectedBand()));

+                target.countries(countryCodeOption(true));

+            } else { // 2.4g

+                //802.11 n only   802.11 b/g/n

+                target.modes(getModeOption(target.selectedBand()));

+                target.countries(countryCodeOption(false));

+            }

+            target.selectedCountry('0');

+            target.channels(target.generateChannelOption());

+            target.selectedChannel('0');

+        };

+

+        target.countryChangeHandler = function (data, event) {

+            var opts = target.generateChannelOption();

+            target.channels(opts);

+            target.selectedChannel('0');

+        };

+

+        target.modeChangeHandler = function (data, event) {

+            var opts = modeRateOption(target.selectedMode());

+            target.rates(opts);

+            target.selectedRate('0');

+        };

+

+        target.generateChannelOption = function () {

+            if (target.selectedBand() == 'a') {

+                return channelOption5g(target.selectedCountry());

+            } else {

+                return channelOption(target.selectedCountry());

+            }

+        };

+

+        target.save = function () {

+            var status = getWpsState();

+            if (status.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return;

+            }

+            var selectedRateTxt = $("#rate option:selected").text();

+            var rateVal = null;

+            if (selectedRateTxt != $.i18n.prop('rate_0')) {

+                rateVal = $.trim(selectedRateTxt.replace('Mbps', ''));

+            } else {

+                rateVal = 0;

+            }

+            var wifiParam = {};

+            wifiParam.countryCode = target.selectedCountry();

+            wifiParam.mode = target.selectedMode();

+            var selectedChannel = target.selectedChannel();

+            wifiParam.channel = selectedChannel == '0' ? '0' : selectedChannel.split("_")[0];

+            wifiParam.rate = rateVal;

+            wifiParam.wifiBand = target.selectedBand();

+            if (config.WIFI_BANDWIDTH_SUPPORT) {

+                wifiParam.bandwidth = target.selectedChannelBandwidth();

+            }

+            wifiParam.station = target.selectedStation();

+            wifiParam.m_station = target.selectedStationM();

+            showConfirm('wifi_disconnect_confirm', function () {

+                showLoading('waiting');

+                service.setWifiAdvance(wifiParam, function (result) {

+                    if (result.result == "success") {

+                        if (viaWifi) {

+                            setTimeout(advanceReloadVarWifi, 15000);

+                        } else {

+                            addInterval(advanceReload, 1000);

+                        }

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            });

+        };

+

+        target.checkSettings = function (ssid) {

+            var status = getWpsState();

+            if (status.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+            if (config.HAS_MULTI_SSID && baseInfo.multi_ssid_enable == "1") {

+                if ((ssid == "ssid1" && parseInt(target.selectedStation()) + parseInt(baseInfo.m_MAX_Access_num) > baseInfo.MAX_Station_num)

+                     || (ssid == "ssid2" && parseInt(target.m_selectedStation()) + parseInt(baseInfo.MAX_Access_num) > baseInfo.MAX_Station_num)) {

+                    showAlert({

+                        msg: 'multi_ssid_max_access_number_alert',

+                        wifiParam: baseInfo.MAX_Station_num

+                    });

+                    return true;

+                }

+            }

+

+            return false;

+        };

+

+        target.setMultiSSIDSwitch = function () {

+            if (target.checkSettings("switch")) {

+                return;

+            }

+

+            var setSwitch = function () {

+                showLoading('waiting');

+                var wifiParam = {};

+                wifiParam.m_ssid_enable = target.multi_ssid_enable();

+                if (config.WIFI_SWITCH_SUPPORT) {

+                    wifiParam.wifiEnabled = target.wifi_enable();

+                }

+                service.setWifiBasicMultiSSIDSwitch(wifiParam, function (result) {

+                    if (result.result == "success") {

+                        if (viaWifi) {

+                            setTimeout(hasApReloadVarWifi, 15000);

+                        } else {

+                            addInterval(hasApReload, 1000);

+                        }

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            };

+

+            var baseInfo = service.getStatusInfo();

+            if (config.HAS_MULTI_SSID && target.wifi_enable() == "1") {

+                if (target.multi_ssid_enable() == "1" && config.AP_STATION_SUPPORT && target.origin_ap_station_enable == "1") {

+                    if (!baseInfo.wifiStatus) {

+                        showConfirm("multi_ssid_enable_confirm", function () {

+                            setSwitch();

+                        });

+                    } else {

+                        showConfirm("multi_ssid_enable_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                } else {

+                    if (!baseInfo.wifiStatus) {

+                        setSwitch();

+                    } else {

+                        showConfirm("wifi_disconnect_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                }

+            } else {

+                setSwitch();

+            }

+            

+            function hasApReloadVarWifi() {

+                successOverlay();

+                setTimeout(function () {

+                    window.location.reload();

+                }, 1000);

+                clearTimer();

+                clearValidateMsg();

+                service.refreshAPStationStatus();

+                initialize();

+            }

+            function hasApReload() {

+                var baseInfo = service.getWifiBasic();

+                if (baseInfo.wifi_enable == target.wifi_enable()) {

+                    successOverlay();

+                    clearTimer();

+                    clearValidateMsg();

+                    service.refreshAPStationStatus();

+                    initialize();

+                }

+            }

+

+        };

+

+    }

+

+    function checkAccessMode() {

+        service.getParams({

+            nv: 'user_ip_addr'

+        }, function (dataIp) {

+            service.getParams({

+                nv: 'station_list'

+            }, function (dataList) {

+                viaWifi = isWifiConnected(dataIp.user_ip_addr, dataList.station_list);

+            });

+        });

+    }

+

+    function advanceReloadVarWifi() {

+        successOverlay();

+        setTimeout(function () {

+            window.location.reload();

+        }, 1000);

+    }

+

+    function advanceReload() {

+        var baseInfo = service.getWifiBasic();

+        if (baseInfo.wifi_enable == "1") {

+            successOverlay();

+            clearTimer();

+            clearValidateMsg();

+            initialize();

+        }

+    }

+

+    function initialize() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var vm = new WifiAdvanceViewModel();

+        ko.applyBindings(vm, container[0]);

+        addTimeout(function () {

+            checkAccessMode();

+        }, 600);

+

+        if (config.WDS_SUPPORT) {

+            checkWifiStatusUseWDS();

+        } else if (config.AP_STATION_SUPPORT) {

+            checkWifiStatus();

+        }

+        

+        $('#wifi_advance_form').validate({

+            submitHandler: function () {

+                vm.save();

+            }

+        });

+        

+        $('#frmWifiSwitch').validate({

+            submitHandler: function () {

+                vm.setMultiSSIDSwitch();

+            }

+        });

+    }

+

+    function checkWifiStatusUseWDS() {

+        var baseInfo = service.getWdsInfo();

+        if (baseInfo.currentMode == "0") {

+            $(':input', '#frmWifiSwitch,#wifi_advance_form').each(function () {

+                $(this).prop("disabled", false);

+            });

+        } else {

+            $(':input', '#frmWifiSwitch,#wifi_advance_form').each(function () {

+                $(this).prop("disabled", true);

+            });

+        }

+    }

+

+    function checkWifiStatus() {

+        var baseInfo = service.getAPStationBasic();

+        if (baseInfo.ap_station_enable != "1") {

+            $(':input', '#wifi_advance_form').each(function () {

+                $(this).prop("disabled", false);

+            });

+        } else {

+            $(':input', '#wifi_advance_form').each(function () {

+                $(this).prop("disabled", true);

+            });

+        }

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+define("wifi_ap_station","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+    var viaWifi = false;

+    function checkAccessMode() {

+        service.getParams({

+            nv: 'user_ip_addr'

+        }, function (dataIp) {

+            service.getParams({

+                nv: 'station_list'

+            }, function (dataList) {

+                viaWifi = isWifiConnected(dataIp.user_ip_addr, dataList.station_list);

+            });

+        });

+    }

+

+    function apStationViewMode() {

+        var target = this;

+        var ssid_ex = "";

+        target.hasMultiSSID = config.HAS_MULTI_SSID;

+        target.hasAPStation = config.AP_STATION_SUPPORT;

+        target.hasWifiSwitch = config.WIFI_SWITCH_SUPPORT;

+        target.hasWlanMacfilter = config.HAS_BLACK_AND_WHITE_FILTER;

+

+        var securityModes = _.map(config.AUTH_MODES_ALL, function (item) {

+            return new Option(item.name, item.value);

+        });

+        //当前页面标识  list列表页 add添加页面  edit编辑页面

+        target.page = {

+            list: 1,

+            add: 2,

+            edit: 3

+        };

+        //WiFi热点列表列的配置项

+        var gridColumn = [{

+                columnType: "radio",

+                headerTextTrans: "option",

+                rowText: "profileName",

+                width: "10%"

+            }, {

+                headerTextTrans: "ssid_title",

+                rowText: "ssid",

+                width: "30%"

+            }, {

+                columnType: "image",

+                headerTextTrans: "signal",

+                rowText: "imgSignal",

+                width: "30%"

+            }, {

+                headerTextTrans: "security_mode",

+                rowText: "authMode_show",

+                width: "30%"

+            }

+        ];

+        //搜索到的WiFi热点列表列的配置项

+        var searchGridColumn = [{

+                columnType: "radio",

+                rowText: "index",

+                width: "10%"

+            }, {

+                headerTextTrans: "ssid_title",

+                rowText: "ssid",

+                width: "30%"

+            }, {

+                columnType: "image",

+                headerTextTrans: "signal",

+                rowText: "imgSignal",

+                width: "30%"

+            }, {

+                headerTextTrans: "security_mode",

+                rowText: "authMode_show",

+                width: "30%"

+            }

+        ];

+

+        target.pageState = ko.observable(target.page.list);

+

+        var info = service.getAPStationBasic();

+

+        target.origin_ap_station_enable = info.ap_station_enable;

+        target.ap_station_enable = ko.observable(info.ap_station_enable);

+        target.apList = ko.observable([]);

+        if (target.origin_ap_station_enable == "1") {

+            var apList = service.getHotspotList();

+            target.apList(fixHotspotList(apList.hotspotList));

+        }

+

+        target.apSearchList = ko.observable([]);

+

+        target.connectButtonStatus = ko.observable("disable");

+        target.hasSelectFromUser = ko.observable();

+        target.showPassword = ko.observable(false);

+

+        target.isCableMode = ko.observable();

+

+        var infoBasic = service.getWifiBasic();

+        target.wifi_enable = ko.observable(infoBasic.wifi_enable);

+

+        target.isShowSSIDInfoDiv = ko.observable(false);

+        if (config.WIFI_SWITCH_SUPPORT) {

+            if (infoBasic.wifi_enable == "1") {

+                target.isShowSSIDInfoDiv(true);

+            } else {

+                target.isShowSSIDInfoDiv(false);

+            }

+        } else {

+            target.isShowSSIDInfoDiv(true);

+        }

+        target.multi_ssid_enable = ko.observable(infoBasic.multi_ssid_enable);

+

+        //密码显示事件

+        target.showPasswordHandler = function () {

+            $("#codeWPAKey").parent().find(".error").hide();

+            $("#pwdWepKey").parent().find(".error").hide();

+            var checkbox = $("#showPassword:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showPassword(true);

+            } else {

+                target.showPassword(false);

+            }

+        };

+

+        target.showWPAPasswordHandler = function () {

+            $("#codeWPAKey").parent().find(".error").hide();

+            $("#pwdWepKey").parent().find(".error").hide();

+            if ($("#showWPAPassword").is(":checked")) {

+                target.showPassword(true);

+            } else {

+                target.showPassword(false);

+            }

+        };

+

+        //列表模板创建

+        target.apGrid = new ko.simpleGrid.viewModel({

+            idName: "profileName",

+            data: target.apList(),

+            tmplType: 'list',

+            pageSize: 100,

+            columns: gridColumn,

+            primaryColumn: "fromProvider",

+            radioClickHandler: function () {

+                computeButtonState();

+            }

+        });

+        //热点搜索结果列表模板创建

+        target.apSearchGrid = new ko.simpleGrid.viewModel({

+            data: target.apSearchList(),

+            idName: "index",

+            tmplType: 'list',

+            pageSize: 100,

+            columns: searchGridColumn,

+            radioClickHandler: function () {

+                var index = target.apSearchGrid.radioSelectValue();

+                var aplist = target.apSearchList();

+                for (var i = 0; i < aplist.length; i++) {

+                    var list_item = aplist[i];

+                    if (list_item.index == index) {

+                        target.profileName("");

+                        target.ssid(list_item.ssid);

+                        ssid_ex = list_item.ssid;

+                        target.signal(list_item.signal);

+                        target.authMode(list_item.authMode);

+                        target.password(list_item.password);

+                        target.mac(list_item.mac);

+                        if (list_item.authMode == "WPAPSKWPA2PSK" || list_item.authMode == "WPA2PSK" || list_item.authMode == "WPAPSK" || list_item.authMode == "WPA3Personal" || list_item.authMode == "WPA2WPA3") {

+                            target.encryptType_WPA(list_item.encryptType);

+                        } else {

+                            target.encryptType(list_item.encryptType);

+                        }

+                        target.keyID(list_item.keyID);

+                        renderCustomElement($("#cipherGroup"));

+                        break;

+                    }

+                }

+            }

+        });

+

+        //计算并设置当前连接和按钮的状态

+        target.computeConnectStatus = function () {

+            computeButtonState();

+

+            var networkStatus = target.connectStatus();

+            if (networkStatus == "ppp_connected") {

+                target.current_status_trans("ap_station_wan_connected");

+                target.current_status_text($.i18n.prop("ap_station_wan_connected"));

+                return;

+            }

+

+            var ssid = target.connectWifiSSID();

+            var wifiStatus = target.connectWifiStatus();

+            if (ssid && wifiStatus == "connect") {

+                target.current_status_trans("ap_station_wlan_connected");

+                target.current_status_text($.i18n.prop("ap_station_wlan_connected"));

+                return;

+            }

+

+            target.current_status_trans("ap_station_no_connection");

+            target.current_status_text($.i18n.prop("ap_station_no_connection"));

+        };

+        //计算并设置按钮的状态

+        function computeButtonState() {

+            var profileName = target.apGrid.radioSelectValue();

+            if (!profileName) {

+                target.hasSelectFromUser(false);

+                target.connectButtonStatus("disable");

+                return;

+            }

+

+            var status = "";

+            var fromProvider = "";

+            for (var i = 0; i < target.apList().length; i++) {

+                var list_item = target.apList()[i];

+                if (list_item.profileName == profileName) {

+                    status = list_item.connectStatus;

+                    fromProvider = list_item.fromProvider;

+                    break;

+                }

+            }

+

+            if (status == "1") {

+                target.connectButtonStatus("hide");

+                target.hasSelectFromUser(false);

+            } else {

+                target.connectButtonStatus("show");

+                target.hasSelectFromUser(fromProvider == "0");

+            }

+        }

+        var statusInfo = service.getStatusInfo();

+        target.networkType = ko.observable(statusInfo.networkType);

+        target.networkOperator = ko.observable(statusInfo.networkOperator);

+        target.connectStatus = ko.observable(statusInfo.connectStatus);

+        target.connectWifiStatus = ko.observable(statusInfo.connectWifiStatus);

+        target.connectWifiProfile = ko.observable(statusInfo.connectWifiProfile);

+        target.connectWifiSSID = ko.observable(statusInfo.connectWifiSSID);

+

+        target.current_status_trans = ko.observable("");

+        target.current_status_text = ko.observable("");

+        target.current_status = ko.computed(function () {

+            target.computeConnectStatus()

+        });

+

+        target.modes = securityModes;

+        target.profileName = ko.observable("");

+        target.ssid = ko.observable();

+        target.signal = ko.observable("0");

+        target.authMode = ko.observable();

+        target.password = ko.observable();

+        target.encryptType = ko.observable();

+        target.encryptType_WPA = ko.observable("TKIPCCMP");

+        target.keyID = ko.observable("0");

+        target.mac = ko.observable();

+

+        target.openAddPage = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+            target.clear();

+            getSearchHotspot();

+        };

+

+        //打开基本设置页面

+        target.openListPage = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+            target.clear();

+            target.pageState(target.page.list);

+            target.apGrid.data(target.apList());

+            v.computeConnectStatus();

+        };

+

+        target.addHotspot = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+            if (target.pageState() == target.page.add && target.apList().length >= config.AP_STATION_LIST_LENGTH) {

+                showAlert({

+                    msg: "ap_station_exceed_list_max",

+                    params: config.AP_STATION_LIST_LENGTH

+                });

+                return;

+            }

+            showLoading('waiting');

+            var wifi_para = {};

+            var profileName = target.apGrid.radioSelectValue();

+            wifi_para.profileName = target.profileName();

+            wifi_para.ssid = target.ssid();

+            wifi_para.signal = target.signal();

+            wifi_para.authMode = target.authMode();

+            wifi_para.password = target.password();

+            if (wifi_para.authMode == "SHARED") {

+                wifi_para.encryptType = "WEP";

+            } else if (wifi_para.authMode == "WPAPSKWPA2PSK" || wifi_para.authMode == "WPA2PSK" || wifi_para.authMode == "WPAPSK" || wifi_para.authMode == "WPA3Personal" || wifi_para.authMode == "WPA2WPA3") {

+                wifi_para.encryptType = target.encryptType_WPA();

+            } else {

+                wifi_para.encryptType = target.encryptType();

+            }

+            wifi_para.keyID = target.keyID();

+            wifi_para.mac = (target.mac() == "" || target.ssid() != ssid_ex) ? "0F:00:00:00:00:00" : target.mac();

+            wifi_para.apList = target.apList();

+            service.saveHotspot(wifi_para, function (data) {

+                target.callback(data, true);

+            });

+        };

+

+        target.deleteHotspot = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+            showConfirm("confirm_data_delete", function () {

+                var wifi_para = {};

+                wifi_para.profileName = target.apGrid.radioSelectValue();

+                wifi_para.apList = target.apList();

+                showLoading('waiting');

+                service.deleteHotspot(wifi_para, function (data) {

+                    target.callback(data, true);

+                });

+            });

+        };

+

+        target.openEditPage = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+            var profileName = target.apGrid.radioSelectValue();

+            var aplist = target.apList();

+            for (var i = 0; i < aplist.length; i++) {

+                var list_item = aplist[i];

+                if (list_item.profileName == profileName) {

+                    target.profileName(profileName);

+                    target.ssid(list_item.ssid);

+                    target.signal(list_item.signal);

+                    target.authMode(list_item.authMode);

+                    target.password(list_item.password);

+                    target.mac(list_item.mac);

+                    if (list_item.authMode == "WPAPSKWPA2PSK" || list_item.authMode == "WPA2PSK" || list_item.authMode == "WPAPSK" || list_item.authMode == "WPA3Personal" || list_item.authMode == "WPA2WPA3") {

+                        target.encryptType_WPA(list_item.encryptType);

+                    } else {

+                        target.encryptType(list_item.encryptType);

+                    }

+                    target.keyID(list_item.keyID);

+                }

+            }

+            target.pageState(target.page.edit);

+        };

+

+        target.connectHotspot = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+            var profileName = target.apGrid.radioSelectValue();

+            var apList = target.apList();

+

+            function connect() {

+                showLoading("connecting");

+                var wifi_para = {};

+                var connectIndex = -1;

+                var ssid = "";

+                for (var i = 0; i < apList.length; i++) {

+                    if (apList[i].profileName == profileName) {

+

+                        wifi_para.EX_SSID1 = apList[i].ssid;

+                        wifi_para.EX_AuthMode = apList[i].authMode;

+                        wifi_para.EX_EncrypType = apList[i].encryptType;

+                        wifi_para.EX_DefaultKeyID = apList[i].keyID;

+                        wifi_para.EX_WEPKEY = apList[i].password;

+                        wifi_para.EX_WPAPSK1 = apList[i].password;

+                        wifi_para.EX_wifi_profile = apList[i].profileName;

+                        wifi_para.EX_mac = apList[i].mac;

+                        connectIndex = i;

+                        ssid = apList[i].ssid;

+                        break;

+                    }

+                }

+

+                target.connectWifiSSID(ssid);

+                target.connectWifiStatus("connecting");

+                target.apGrid.setRadioSelect(profileName);

+                target.connectButtonStatus("disable");

+

+                service.connectHotspot(wifi_para, function (data) {

+                    if (data && data.result == "success") {

+                        target.connectButtonStatus("disable");

+                        //延迟检测 确保取得的状态是最新的

+                        addTimeout(checkWifiStatus, 3000);

+                    } else if (data && data.result == "processing") {

+                        showAlert("ap_station_processing");

+                    } else {

+                        var apList = target.apList(); // cov_2

+                        apList[connectIndex].connectStatus = "0";

+                        target.connectWifiStatus("disconnect");

+                        target.connectButtonStatus("show");

+                        hideLoading();

+                        errorOverlay();

+                    }

+                    var apList = service.getHotspotList();

+                    target.apList(fixHotspotList(apList.hotspotList));

+                    target.connectWifiProfile(profileName);

+                    target.connectWifiSSID(ssid);

+                    target.apGrid.data([]);

+                    target.apGrid.data(target.apList());

+                    target.apGrid.setRadioSelect(profileName);

+                });

+            }

+

+            //将用户选中的profile排在运营商定制profile后的第一位

+            function refreshApList(profile, aplist) {

+                var apListLeft = [];

+                var apListPre = [];

+                for (var i = 0; i < aplist.length; i++) {

+                    if (aplist[i].fromProvider != "1") {

+                        if (aplist[i].profileName == profile) {

+                            apListPre.push(apList[i]);

+                        } else {

+                            apListLeft.push(apList[i]);

+                        }

+                    } else {

+                        apListPre.push(apList[i]);

+                    }

+                }

+                var apListNew = apListPre.concat(apListLeft);

+                service.saveHotspot({

+                    apList: apListNew

+                }, function (data) {

+                    if (data && data.result == "success") {

+                        apList = apListNew;

+                        target.apList(fixHotspotList(apList));

+                    }

+                });

+            }

+

+            var check_count = 0;

+            var connectStatus = false;

+

+            var status = service.getStatusInfo();

+            if (status.connectStatus == "ppp_connected" || status.connectStatus == "ppp_connecting") {

+                showConfirm("ap_station_connect_change_alert", function () {

+                    showLoading();

+                    connect();

+                });

+            } else {

+                connect();

+            }

+

+            function checkWifiStatus() {

+                check_count = check_count + 1;

+                if (check_count > 60) {

+                    hideLoading();

+                    errorOverlay();

+                    return;

+                }

+                if (!connectStatus) {

+                    var status = service.getStatusInfo();

+                    if (status.connectWifiStatus != "connect") {

+                        addTimeout(checkWifiStatus, 1000);

+                    } else {

+                        connectStatus = true;

+                    }

+                }

+                if (connectStatus) {

+                    //继续判断profile中连接状态是否为1

+                    service.getHotspotList({}, function (data) {

+                        for (var i = 0, len = data.hotspotList.length; i < len; i++) {

+                            var list_item = data.hotspotList[i];

+                            if (list_item.profileName == profileName) {

+                                if (list_item.connectStatus == "1") {

+                                    hideLoading();

+                                    return;

+                                } else {

+                                    var errorMsg = {

+                                        msg: 'ap_connect_error',

+                                        params: [list_item.ssid]

+                                    };

+                                    showAlert(errorMsg);

+                                    return;

+                                }

+                                break;

+                            }

+                        }

+                        addTimeout(checkWifiStatus, 1000);

+                    });

+                }

+            }

+

+        };

+

+        target.disconnectHotspot = function () {

+            if (wpsIsOn()) {

+                return;

+            }

+            showLoading('disconnecting');

+            service.disconnectHotspot({}, function (data) {

+                target.callback(data, true);

+            })

+        };

+

+        function getSearchHotspot() {

+            var check_count = 0;

+

+            function search() {

+                var result = service.getSearchHotspotList();

+                if (result.scan_finish == "0") {

+                    if (check_count <= 60) {

+                        check_count = check_count + 1;

+                        addTimeout(search, 1000);

+                    } else {

+                        hideLoading();

+                        showAlert("ap_station_search_hotspot_fail");

+                    }

+                } else {

+                    if ("2" == result.scan_finish) {

+                        hideLoading();

+                        showAlert("ap_station_processing");

+                    } else {

+                        target.apSearchList(fixHotspotList(result.hotspotList));

+                        target.apSearchGrid.data(target.apSearchList());

+                        hideLoading();

+                    }

+                }

+            }

+

+            showLoading('scanning');

+            service.searchHotspot({}, function (data) {

+                if (data && data.result == "processing") {

+                    hideLoading();

+                    showAlert("ap_station_processing");

+                } else if (data && data.result == "success") {

+                    if (target.pageState() != target.page.add) {

+                        target.pageState(target.page.add);

+                    }

+                    search();

+                } else {

+                    if (target.pageState() != target.page.add) {

+                        target.pageState(target.page.add);

+                    }

+                    hideLoading();

+                    showAlert("ap_station_search_hotspot_fail");

+                }

+            });

+        }

+

+        //清除编辑页面的信息

+        target.clear = function () {

+            target.apSearchGrid.clearRadioSelect();

+            target.profileName("");

+            target.ssid("");

+            target.signal("0");

+            target.authMode("OPEN");

+            target.password("");

+            target.encryptType("NONE");

+            target.encryptType_WPA("TKIPCCMP");

+            target.keyID("0");

+            target.mac("");

+        };

+

+        target.apply = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+

+            function setBasic() {

+                showLoading('waiting');

+                var wifi_para = {};

+                wifi_para.ap_station_enable = target.ap_station_enable();

+                service.setAPStationBasic(wifi_para, function (data) {

+                    if (target.origin_ap_station_enable == target.ap_station_enable()) {

+                        target.callback(data, true);

+                    } else {

+                        target.callback2(data, true);

+                    }

+                });

+                service.refreshAPStationStatus();

+            }

+            if (!config.HAS_MULTI_SSID) {

+                setBasic();

+            } else {

+                var infoBasic = service.getWifiBasic();

+                if (target.ap_station_enable() == "1" && infoBasic.multi_ssid_enable == "1") {

+                    showConfirm("ap_station_enable_confirm", setBasic);

+                } else {

+                    setBasic();

+                }

+            }

+        };

+        //刷新搜到的热点列表

+        target.searchHotspot = function () {

+            if (wifiIsClosed()) {

+                return;

+            }

+            if (wpsIsOn()) {

+                return;

+            }

+            getSearchHotspot();

+        };

+        //和webserver交互时的回调,wifi不重启的情况

+        target.callback = function (data, isInitPage) {

+            if (data) {

+                if (isInitPage) {

+                    initialize();

+                    $("#apList").translate();

+                }

+                if (data.result == "processing") {

+                    showAlert("ap_station_processing");

+                } else if (data.result == "spot_connected" || data.result == "spot_connecting") {

+                    showAlert("ap_station_update_fail");

+                } else if (data.result == "success") {

+                    successOverlay();

+                } else if (data.result == "exist") {

+                    showAlert("ap_station_exist");

+                } else {

+                    errorOverlay();

+                }

+            } else {

+                errorOverlay();

+            }

+        }

+

+        //和webserver交互时的回调,wifi会重启的情况

+        target.callback2 = function (data, isInitPage) {

+            if (data) {

+                if (!viaWifi) { //通过wifi登录webui

+                    addInterval(function () {

+                        var info = service.getWifiBasic();

+                        if (info.wifi_enable == "1") {

+                            clearTimer();

+                            clearValidateMsg();

+                            initialize();

+                            $("#apList").translate();

+                            if (data.result == "spot_connected" || data.result == "spot_connecting") {

+                                showAlert("ap_station_update_fail");

+                            } else if (data.result == "success") {

+                                successOverlay();

+                            } else {

+                                errorOverlay();

+                            }

+                        }

+                    }, 1000);

+                } else {

+                    setTimeout(function () {

+                        if (data.result == "processing") {

+                            showAlert("ap_station_processing");

+                        } else if (data.result == "spot_connecting" || data.result == "spot_connected") {

+                            showAlert("ap_station_update_fail");

+                        } else if (data.result == "success") {

+                            successOverlay();

+                            setTimeout(function () {

+                                window.location.reload();

+                            }, 1000);

+                            clearTimer();

+                            clearValidateMsg();

+                            initialize();

+                        } else {

+                            errorOverlay();

+                        }

+                    }, 15000);

+                }

+            } else {

+                errorOverlay();

+            }

+        };

+

+        target.checkSettings = function (ssid) {

+            var status = service.getWpsInfo();

+            if (status.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+            if (config.HAS_MULTI_SSID && info.multi_ssid_enable == "1") {

+                if ((ssid == "ssid1" && parseInt(target.selectedStation()) + parseInt(info.m_MAX_Access_num) > info.MAX_Station_num)

+                     || (ssid == "ssid2" && parseInt(target.m_selectedStation()) + parseInt(info.MAX_Access_num) > info.MAX_Station_num)) {

+                    showAlert({

+                        msg: 'multi_ssid_max_access_number_alert',

+                        params: info.MAX_Station_num

+                    });

+                    return true;

+                }

+            }

+

+            return false;

+        };

+

+        target.setMultiSSIDSwitch = function () {

+            if (target.checkSettings("switch")) {

+                return;

+            }

+

+            var setSwitch = function () {

+                showLoading('waiting');

+                var params = {};

+                params.m_ssid_enable = target.multi_ssid_enable();

+                if (config.WIFI_SWITCH_SUPPORT) {

+                    params.wifiEnabled = target.wifi_enable();

+                }

+                service.setWifiBasicMultiSSIDSwitch(params, function (result) {

+                    if (result.result == "success") {

+                        if (!viaWifi) {

+                            addInterval(function () {

+                                var info = service.getWifiBasic();

+                                if (info.wifi_enable == target.wifi_enable()) {

+                                    successOverlay();

+                                    clearTimer();

+                                    clearValidateMsg();

+                                    service.refreshAPStationStatus();

+                                    initialize();

+                                }

+                            }, 1000);

+                        } else {

+                            setTimeout(function () {

+                                successOverlay();

+                                setTimeout(function () {

+                                    window.location.reload();

+                                }, 1000);

+                                clearTimer();

+                                clearValidateMsg();

+                                service.refreshAPStationStatus();

+                                initialize();

+                            }, 15000);

+                        }

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            };

+

+            var info = service.getStatusInfo();

+            if (config.HAS_MULTI_SSID && target.wifi_enable() == "1") {

+                if (target.multi_ssid_enable() == "1" && config.AP_STATION_SUPPORT && target.origin_ap_station_enable == "1") {

+                    if (!info.wifiStatus) {

+                        showConfirm("multi_ssid_enable_confirm", function () {

+                            setSwitch();

+                        });

+                    } else {

+                        showConfirm("multi_ssid_enable_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                } else {

+                    if (!info.wifiStatus) {

+                        setSwitch();

+                    } else {

+                        showConfirm("wifi_disconnect_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                }

+            } else {

+                setSwitch();

+            }

+        };

+

+    }

+

+    function wpsIsOn() {

+        var wifi_info = service.getWpsInfo();

+        if (wifi_info.wpsFlag == '1') {

+            showAlert('wps_on_info');

+            return true;

+        }

+    }

+

+    //处理热点列表内容,以便在表格显示

+    function fixHotspotList(list) {

+        var fixedList = [];

+        for (var ii = 0; ii < list.length; ii++) {

+            list[ii].index = ii;

+            var url_image = "";

+            if (list[ii].connectStatus != "1") {

+                if (list[ii].encryptType.toLowerCase() == "none" && list[ii].authMode.toLowerCase() == "open") {

+                    url_image = "pic/wlan_signal_" + list[ii].signal + ".png";

+                } else {

+                    url_image = "pic/wlan_lock_signal_" + list[ii].signal + ".png";

+                }

+            } else {

+                if (list[ii].encryptType.toLowerCase() == "none" && list[ii].authMode.toLowerCase() == "open") {

+                    url_image = "pic/wlan_connected.png";

+                } else {

+                    url_image = "pic/wlan_lock_connected.png";

+                }

+            }

+            list[ii].imgSignal = url_image;

+            list[ii].authMode_show = $.i18n.prop("ap_station_security_mode_" + list[ii].authMode);

+        }

+        return list;

+    }

+

+    function wifiIsClosed() {

+        var wifi_info = service.getWpsInfo();

+        if (wifi_info.radioFlag == "0") {

+            showAlert('wps_wifi_off');

+            return true;

+        }

+    }

+

+    function event_bind(aps_vm) {

+        $("#showWPAPassword").change(function () {

+            aps_vm.showWPAPasswordHandler();

+        });

+        $("#showPassword").change(function () {

+            aps_vm.showPasswordHandler();

+        });

+    }

+

+    function initialize() {

+        var aps_vm = new apStationViewMode();

+        var container = $('#container')[0];

+        ko.cleanNode(container);

+        ko.applyBindings(aps_vm, container);

+        event_bind(aps_vm);

+

+        aps_refresh(true);

+        clearTimer();

+        addInterval(function () {

+            aps_refresh(false);

+            checkAccessMode();

+        }, 1000);

+

+        $('#frmWifiSwitch').validate({

+            submitHandler: function () {

+                aps_vm.setMultiSSIDSwitch();

+            }

+        });

+

+        $("#frmAPStation").validate({

+            submitHandler: function () {

+                aps_vm.addHotspot();

+            },

+            rules: {

+                txtSSID: "ssid_ap"

+            },

+            errorPlacement: function (error, element) {

+                var id = element.attr("id");

+                if (id == "txtWPAKey" || id == "codeWPAKey") {

+                    error.insertAfter("#lblshowWPAPassword");

+                } else if (id == "txtWepKey" || id == "pwdWepKey") {

+                    error.insertAfter("#lblShowPassword");

+                } else {

+                    error.insertAfter(element);

+                }

+            }

+        });

+

+        function aps_refresh(initPage) {

+            var info = service.getStatusInfo();

+            if (info.multi_ssid_enable != "1") {

+                aps_vm.isCableMode(checkCableMode(info.blc_wan_mode));

+                aps_vm.connectWifiProfile(info.connectWifiProfile);

+                aps_vm.connectWifiSSID(info.connectWifiSSID);

+                aps_vm.connectWifiStatus(info.connectWifiStatus);

+                aps_vm.networkType(info.networkType);

+                aps_vm.connectStatus(info.connectStatus);

+                aps_vm.computeConnectStatus();

+

+                service.getHotspotList({}, function (data) {

+                    var list = fixHotspotList(data.hotspotList);

+                    aps_vm.apList(list);

+                    var gripList = aps_vm.apGrid.data();

+                    if (list.length > 0 && list[0].profileName != gripList[0].profileName && list[0].connectStatus == "1") {

+                        aps_vm.apGrid.data([]);

+                        aps_vm.apGrid.data(aps_vm.apList());

+                        aps_vm.apGrid.setRadioSelect(list[0].profileName);

+                    }

+                    renderCustomElement($("#apList"));

+                    var radios = $("input[type='radio']", "#apList").each(function () {

+                        for (var i = 0, len = list.length; i < len; i++) {

+                            if (list[i].profileName == $(this).val()) {

+                                var img = $(this).parent().parent().find("img")[0];

+                                img.src = list[i].imgSignal;

+                                if (initPage) {

+                                    if (list[i].connectStatus == "1") {

+                                        aps_vm.hasSelectFromUser(false);

+                                        aps_vm.connectButtonStatus("disable");

+                                    }

+                                }

+                            }

+                        }

+                    });

+                });

+            } else {

+                //to do

+            }

+        }

+

+    }

+

+    return {

+        init: initialize

+    }

+});

+

+define("wifi_guest","underscore jquery knockout set service CryptoJS".split(" "),

+

+    function (_, $, ko, config, service, CryptoJS) {

+

+    var viaWifi = false;

+    function checkAccessMode() {

+        service.getParams({

+            nv: 'user_ip_addr'

+        }, function (dataIp) {

+            service.getParams({

+                nv: 'station_list'

+            }, function (dataList) {

+                viaWifi = isWifiConnected(dataIp.user_ip_addr, dataList.station_list);

+            });

+        });

+    }

+

+    var securityModes = _.map(config.WIFI_WEP_SUPPORT ? config.AUTH_MODES_WEP : config.AUTH_MODES, function (item) {

+        return new Option(item.name, item.value);

+    });

+

+    function maxStationAccess(max) {

+        var showOption = [];

+        for (var i = 1; i <= max; i++) {

+            showOption.push(new Option(i, i));

+        }

+        return showOption;

+    }

+

+    function wifiGuestVM() {

+        var target = this;

+        var info = service.getWifiBasic();

+

+        target.hasWifiSwitch = config.WIFI_SWITCH_SUPPORT;

+        target.hasMultiSSID = config.HAS_MULTI_SSID;

+        target.showIsolated = config.SHOW_WIFI_AP_ISOLATED;

+        target.hasAPStation = config.AP_STATION_SUPPORT;

+        target.hasWlanMacfilter = config.HAS_BLACK_AND_WHITE_FILTER;

+        target.hasWifiWep = config.WIFI_WEP_SUPPORT;

+        target.hasWifiWpa3 = config.WIFI_WAP3_SUPPORT;

+        target.hasWifiWpa23 = config.WIFI_WPA2_WAP3_SUPPORT;

+

+        var advanceInfo = service.getWifiAdvance();

+        target.adBand = ko.observable(advanceInfo.wifiBand);

+        target.adMode = ko.observable(advanceInfo.mode);

+

+        target.showQRSwitch = config.WIFI_SUPPORT_QR_CODE && config.WIFI_SUPPORT_QR_SWITCH;

+        target.showQR = ko.observable(info.m_show_qrcode_flag);

+        if (config.WIFI_SUPPORT_QR_SWITCH) {

+            target.showQRCode = ko.observable(config.WIFI_SUPPORT_QR_CODE && target.showQR());

+        } else {

+            target.showQRCode = ko.observable(config.WIFI_SUPPORT_QR_CODE);

+        }

+        target.qrcodeSrc = './pic/qrcode_multi_ssid_wifikey.png?_=' + $.now();

+

+        target.origin_ap_station_enable = info.ap_station_enable;

+        target.wifi_enable = ko.observable(info.wifi_enable);

+        target.isShowSSIDInfoDiv = ko.observable(false);

+        if (config.WIFI_SWITCH_SUPPORT) {

+            if (info.wifi_enable == "1") {

+                target.isShowSSIDInfoDiv(true);

+            } else {

+                target.isShowSSIDInfoDiv(false);

+            }

+        } else {

+            target.isShowSSIDInfoDiv(true);

+        }

+

+        target.multi_ssid_enable = ko.observable(info.multi_ssid_enable);

+        target.origin_multi_ssid_enable = info.multi_ssid_enable;

+

+        target.maxStationNumber = ko.computed(function () {

+            return config.MAX_STATION_NUMBER;

+        });

+

+        target.modes = ko.observableArray(securityModes);

+        target.selectedMode = ko.observable(info.AuthMode);

+        target.passPhrase = ko.observable(info.passPhrase);

+        target.showPassword = ko.observable(false);

+        target.ssid = ko.observable(info.SSID);

+        target.broadcast = ko.observable(info.broadcast == '1' ? '1' : '0');

+        target.apIsolation = ko.observable(info.apIsolation == '1' ? '1' : '0');

+        target.cipher = info.cipher;

+        target.selectedStation = ko.observable(info.MAX_Access_num);

+        target.maxStations = ko.observableArray(maxStationAccess(info.MAX_Station_num));

+

+        target.m_modes = ko.observableArray(securityModes);

+        target.m_selectedMode = ko.observable(info.m_AuthMode);

+        target.m_passPhrase = ko.observable(info.m_passPhrase);

+        target.m_showPassword = ko.observable(false);

+        target.m_ssid = ko.observable(info.m_SSID);

+        target.m_broadcast = ko.observable(info.m_broadcast == '1' ? '1' : '0');

+        target.m_apIsolation = ko.observable(info.m_apIsolation == '1' ? '1' : '0');

+        target.m_cipher = info.m_cipher;

+        target.m_selectedStation = ko.observable(info.m_MAX_Access_num);

+        target.m_maxStations = ko.observableArray(maxStationAccess(info.MAX_Station_num));

+        target.m_encryptType = ko.observable(info.m_encryptType);

+        target.m_keyID = ko.observable(info.m_keyID);

+        target.m_wepPassword = ko.observable("");

+

+        //刷新界面状态值显示

+        target.clear = function (option) {

+            if (option == "switch") {

+                target.multi_ssid_enable(info.multi_ssid_enable);

+                target.wifi_enable(info.wifi_enable);

+            } else if (option == "ssid1") {

+                target.selectedMode(info.AuthMode);

+                target.passPhrase(info.passPhrase);

+                target.ssid(info.SSID);

+                target.broadcast(info.broadcast == '1' ? '1' : '0');

+                target.cipher = info.cipher;

+                target.selectedStation(info.MAX_Access_num);

+                target.apIsolation(info.apIsolation == '1' ? '1' : '0');

+            } else if (option == "ssid2") {

+                target.m_selectedMode(info.m_AuthMode);

+                target.m_passPhrase(info.m_passPhrase);

+                target.m_ssid(info.m_SSID);

+                target.m_broadcast(info.m_broadcast == '1' ? '1' : '0');

+                target.m_cipher = info.m_cipher;

+                target.m_selectedStation(info.m_MAX_Access_num);

+                target.m_apIsolation(info.m_apIsolation == '1' ? '1' : '0');

+                if (config.WIFI_WEP_SUPPORT) {

+                    target.m_encryptType(info.m_encryptType);

+                    target.m_keyID(info.m_keyID);

+                    target.m_wepPassword(target.getWepPassword());

+                }

+            } else {

+                clearTimer();

+                clearValidateMsg();

+                initialize();

+                service.refreshAPStationStatus();

+            }

+        };

+

+        target.getWepPassword = function () {

+            return target.m_keyID() == '3' ? info.m_Key4Str1 : (target.m_keyID() == '2' ? info.m_Key3Str1 : target.m_keyID() == '1' ? info.m_Key2Str1 : info.m_Key1Str1);

+        }

+        target.m_wepPassword(target.getWepPassword());

+        //WEP加密模式下网络秘钥切换事件

+        target.profileChangeHandler = function (data, event) {

+            $("#pwdWepKey").parent().find("label[class='error']").hide();

+            target.m_wepPassword(target.getWepPassword());

+            return true;

+        };

+

+        target.saveSSID1 = function () {

+            if (target.checkSettings("ssid1")) {

+                return;

+            }

+            showConfirm('wifi_disconnect_confirm', function () {

+                target.saveSSID1Action();

+            });

+        };

+        target.saveSSID1Action = function () {

+            showLoading('waiting');

+            target.broadcast($("#broadcastCheckbox:checked").length > 0 ? '0' : '1');

+            target.apIsolation($("#apisolatedCheckbox:checked").length);

+            var params = {};

+            params.AuthMode = target.selectedMode();

+            params.passPhrase = target.passPhrase();

+            params.SSID = target.ssid();

+            params.broadcast = target.broadcast();

+            params.station = target.selectedStation();

+            params.cipher = target.selectedMode() == "WPA2PSK" ? 1 : 2;

+            if (params.AuthMode == "WPA3Personal" || params.AuthMode == "WPA2WPA3") {

+                params.cipher = 1;

+            }

+            params.NoForwarding = target.apIsolation();

+            params.show_qrcode_flag = target.showQR() == true ? 1 : 0;

+            service.setWifiBasic(params, function (result) {

+                if (result.result == "success") {

+                    if (viaWifi) {

+                        setTimeout(guestReloadVarWifi, 15000);

+                    } else {

+                        addInterval(guestReload, 1000);

+                    }

+                } else {

+                    errorOverlay();

+                }

+            });

+        };

+

+        target.saveSSID2 = function () {

+            if (target.checkSettings("ssid2")) {

+                return;

+            }

+            if (!config.PASSWORD_ENCODE) {

+                var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,32}');

+                if (!pwdRegex.test(target.m_passPhrase())) {

+                        showConfirm("password_note_too_low", function () {

+                            showConfirm('wifi_disconnect_confirm', function () {

+                            target.saveSSID2Action();

+                            return;

+                        });

+                        return;

+                    });

+                    return;

+                }

+            }

+            showConfirm('wifi_disconnect_confirm', function () {

+                target.saveSSID2Action();

+            });

+        };

+        target.saveSSID2Action = function () {

+            showLoading('waiting');

+            target.m_broadcast($("#mBroadcastCheckbox:checked").length > 0 ? '0' : '1');

+            target.m_apIsolation($("#mApIsolatedCheckbox:checked").length);

+            var ciphertext = "";

+            if (config.PASSWORD_ENCODE) {

+	        ciphertext = target.m_passPhrase();

+	    } else {

+                var kparam = service.getDeviceInfoLow();

+                var tkey = CryptoJS.enc.Latin1.parse(kparam.skey);

+		var tiv = CryptoJS.enc.Latin1.parse(kparam.siv);

+                ciphertext = CryptoJS.AES.encrypt(target.m_passPhrase(), tkey, {

+                    iv: tiv,

+                    mode: CryptoJS.mode.CBC,

+                    padding: CryptoJS.pad.ZeroPadding

+                    }).toString();

+	    }

+            var params = {};

+            params.m_AuthMode = target.m_selectedMode();

+            params.m_passPhrase = ciphertext;

+            params.m_SSID = target.m_ssid();

+            params.m_broadcast = target.m_broadcast();

+            params.m_station = target.m_selectedStation();

+            params.m_cipher = target.m_selectedMode() == "WPA2PSK" ? 1 : 2;

+            if (params.m_AuthMode == "WPA3Personal" || params.m_AuthMode == "WPA2WPA3") {

+                params.m_cipher = 1;

+            }

+            params.m_NoForwarding = target.m_apIsolation();

+            params.m_show_qrcode_flag = target.showQR() == true ? 1 : 0;

+

+            if (config.WIFI_WEP_SUPPORT) {

+                if (params.m_AuthMode == "SHARED") {

+                    params.m_encryptType = "WEP";

+                } else if (params.m_AuthMode == "WPAPSKWPA2PSK" || params.m_AuthMode == "WPA2PSK" || params.m_AuthMode == "WPAPSK" || params.m_AuthMode == "WPA3Personal" || params.m_AuthMode == "WPA2WPA3") {

+                    //params.m_encryptType = target.m_encryptType_WPA();

+                } else {

+                    params.m_encryptType = target.m_encryptType();

+                }

+                params.m_wep_default_key = target.m_keyID();

+                params.m_wep_key_4 = info.m_Key4Str1;

+                params.m_wep_key_3 = info.m_Key3Str1;

+                params.m_wep_key_2 = info.m_Key2Str1;

+                params.m_wep_key_1 = info.m_Key1Str1;

+                var mWEPSelect = '0';

+                if (target.m_wepPassword().length == '13' || target.m_wepPassword().length == '5') {

+                    mWEPSelect = '1';

+                } else {

+                    mWEPSelect = '0';

+                }

+                if (target.m_keyID() == '3') {

+                    params.m_wep_key_4 = target.m_wepPassword();

+                    params.m_WEP4Select = mWEPSelect;

+                } else if (target.m_keyID() == '2') {

+                    params.m_wep_key_3 = target.m_wepPassword();

+                    params.m_WEP3Select = mWEPSelect;

+                } else if (target.m_keyID() == '1') {

+                    params.m_wep_key_2 = target.m_wepPassword();

+                    params.m_WEP2Select = mWEPSelect;

+                } else {

+                    params.m_wep_key_1 = target.m_wepPassword();

+                    params.m_WEP1Select = mWEPSelect;

+                }

+            }

+

+            service.setWifiBasic4SSID2(params, function (result) {

+                if (result.result == "success") {

+                    if (viaWifi) {

+                        setTimeout(ssid2ReloadVarWifi, 15000);

+                    } else {

+                        addInterval(ssid2Reload, 1000);

+                    }

+                } else {

+                    errorOverlay();

+                }

+            });

+        };

+

+        function guestReloadVarWifi() {

+            successOverlay();

+            setTimeout(function () {

+                window.location.reload();

+            }, 1000);

+            target.clear();

+        }

+        function guestReload() {

+            var info = getWifiMain();

+            if (info.wifi_enable == "1") {

+                successOverlay();

+                target.clear();

+            }

+        }

+        function ssid2ReloadVarWifi() {

+            successOverlay();

+            setTimeout(function () {

+                window.location.reload();

+            }, 1000);

+            target.clear();

+        }

+        function ssid2Reload() {

+            var info = getWifiMain();

+            if (info.wifi_enable == "1") {

+                successOverlay();

+                target.clear();

+            }

+        }

+

+        target.checkSettings = function (ssid) {

+            var status = getWpsState();

+

+            if (config.HAS_MULTI_SSID) {

+                if (ssid == "ssid1" || ssid == "ssid2") {

+                    if (ssid == "ssid2") {

+                        var accessDevice = service.getStatusInfo().ssid2AttachedNum;

+                        if (parseInt(target.m_selectedStation()) < accessDevice) {

+                            showAlert('Extend_accessDevice');

+                            return true;

+                        }

+                    } else {

+                        var accessDevice = service.getStatusInfo().ssid1AttachedNum;

+                        if (parseInt(target.selectedStation()) < accessDevice) {

+                            showAlert('Extend_accessDevice');

+                            return true;

+                        }

+                    }

+                }

+            }

+

+            if (status.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+            if (config.HAS_MULTI_SSID && info.multi_ssid_enable == "1") {

+                if ((ssid == "ssid1" && parseInt(target.selectedStation()) + parseInt(info.m_MAX_Access_num) > info.MAX_Station_num)

+                     || (ssid == "ssid2" && parseInt(target.m_selectedStation()) + parseInt(info.MAX_Access_num) > info.MAX_Station_num)) {

+                    showAlert({

+                        msg: 'multi_ssid_max_access_number_alert',

+                        params: info.MAX_Station_num

+                    });

+                    return true;

+                }

+            }

+

+            return false;

+        };

+

+        target.setMultiSSIDSwitch = function () {

+            if (target.checkSettings("switch")) {

+                return;

+            }

+

+            var setSwitch = function () {

+                showLoading('waiting');

+                var params = {};

+                params.m_ssid_enable = target.multi_ssid_enable();

+                if (config.WIFI_SWITCH_SUPPORT) {

+                    params.wifiEnabled = target.wifi_enable();

+                }

+                service.setWifiBasicMultiSSIDSwitch(params, function (result) {

+                    if (result.result == "success") {

+                        if (viaWifi) {

+                            setTimeout(multiReloadViaWifi, 15000);

+                        } else {

+                            addInterval(multiReload, 1000);

+                        }

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            };

+            function multiReloadViaWifi() {

+                successOverlay();

+                setTimeout(function () {

+                    window.location.reload();

+                }, 1000);

+                target.clear();

+            }

+            function multiReload() {

+                var info = getWifiMain();

+                if (info.wifi_enable == target.wifi_enable()) {

+                    successOverlay();

+                    target.clear();

+                }

+            }

+            var info = service.getStatusInfo();

+            if (config.HAS_MULTI_SSID && target.wifi_enable() == "1") {

+                if (config.AP_STATION_SUPPORT && target.multi_ssid_enable() == "1" && target.origin_ap_station_enable == "1") {

+                    if (!info.wifiStatus) {

+                        showConfirm("multi_ssid_enable_confirm", function () {

+                            setSwitch();

+                        });

+                    } else {

+                        showConfirm("multi_ssid_enable_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                } else {

+                    if (!info.wifiStatus) {

+                        setSwitch();

+                    } else {

+                        showConfirm("wifi_disconnect_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                }

+            } else {

+                setSwitch();

+            }

+        };

+        target.showQRHandler = function () {

+            var checkbox = $("#showQR:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showQR(true);

+            } else {

+                target.showQR(false);

+            }

+            target.showQRCode(config.WIFI_SUPPORT_QR_CODE && target.showQR());

+        };

+

+        target.showPasswordHandler = guestShowPassword;

+

+        target.m_showPasswordHandler = m_guestShowPassword;

+

+        function guestShowPassword() {

+            $("#passShow").parent().find(".error").hide();

+            var checkbox = $("#showPassword:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showPassword(true);

+            } else {

+                target.showPassword(false);

+            }

+        }

+        function m_guestShowPassword() {

+            $("#m_passShow").parent().find(".error").hide();

+            $("#m_pwdWepKey").parent().find(".error").hide();

+            var checkbox = $("#m_showPassword:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.m_showPassword(true);

+            } else {

+                target.m_showPassword(false);

+            }

+        }

+

+    }

+

+    function getWifiMain() {

+        return service.getWifiBasic();

+    }

+

+    function initialize() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var vm = new wifiGuestVM();

+        ko.applyBindings(vm, container[0]);

+        addTimeout(function () {

+            checkAccessMode();

+        }, 600);

+

+        function checkWifiStatus() {

+            var info = service.getAPStationBasic();

+            if (info.ap_station_enable != "1") {

+                $('#frmMultiSSID :input').each(function () {

+                    $(this).attr("disabled", false);

+                });

+            } else {

+                $('#frmMultiSSID :input').each(function () {

+                    $(this).attr("disabled", true);

+                });

+            }

+        }

+

+        function checkWifiStatusAccordingToWDS() {

+            var info = service.getWdsInfo();

+            if (info.currentMode == "0") {

+                $('#frmWifiSwitch :input').each(function () {

+                    $(this).attr("disabled", false);

+                });

+                $('#frmSSID2 :input').each(function () {

+                    $(this).attr("disabled", false);

+                });

+                $('#frmSSID1 :input').each(function () {

+                    $(this).attr("disabled", false);

+                });

+            } else {

+                $('#frmWifiSwitch :input').each(function () {

+                    $(this).attr("disabled", true);

+                });

+                $('#frmSSID2 :input').each(function () {

+                    $(this).attr("disabled", true);

+                });

+                $('#frmSSID1 :input').each(function () {

+                    $(this).attr("disabled", true);

+                });

+            }

+        }

+

+        if (config.WDS_SUPPORT) {

+            checkWifiStatusAccordingToWDS();

+        } else if (config.AP_STATION_SUPPORT) {

+            checkWifiStatus();

+        }

+

+        $('#frmMultiSSID').validate({

+            submitHandler: function () {

+                vm.setMultiSSIDSwitch();

+            }

+        });

+        $('#frmWifiSwitch').validate({

+            submitHandler: function () {

+                vm.setMultiSSIDSwitch();

+            }

+        });

+        $('#frmSSID2').validate({

+            submitHandler: function () {

+                vm.saveSSID2();

+            },

+            rules: {

+                m_ssid: 'ssid',

+                m_pwdWepKey: {

+                    wifi_wep_password_check: true,

+                    wifi_password_check: true

+                },

+                m_txtWepKey: {

+                    wifi_wep_password_check: true,

+                    wifi_password_check: true

+                },

+                m_pass: 'wifi_password_check',

+                m_passShow: 'wifi_password_check'

+            },

+            errorPlacement: function (error, element) {

+                var id = element.attr("id");

+                if (id == "m_passShow" || id == "m_pass") {

+                    error.insertAfter("#m_lblShowPassword");

+                } else if (id == "m_txtWepKey" || id == "m_pwdWepKey") {

+                    error.insertAfter("#m_lblShowWepPassword");

+                } else {

+                    error.insertAfter(element);

+                }

+            }

+        });

+        $('#frmSSID1').validate({

+            submitHandler: function () {

+                vm.saveSSID1();

+            },

+            rules: {

+                pass: 'wifi_password_check',

+                ssid: 'ssid',

+                passShow: 'wifi_password_check'

+            },

+            errorPlacement: function (error, element) {

+                var id = element.attr("id");

+                if (id == "passShow" || id == "pass") {

+                    error.insertAfter("#lblShowPassword");

+                } else {

+                    error.insertAfter(element);

+                }

+            }

+        });

+

+    }

+

+    function getWpsState() {

+        return service.getWpsInfo();

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+define("wifi_mac_filter","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var viaWifi = false;

+    function checkAccessMode() {

+        service.getParams({

+            nv: 'user_ip_addr'

+        }, function (dataIp) {

+            service.getParams({

+                nv: 'station_list'

+            }, function (dataList) {

+                viaWifi = isWifiConnected(dataIp.user_ip_addr, dataList.station_list);

+            });

+        });

+    }

+

+    function macFilterViewModel() {

+        var target = this;

+        target.hasAPStation = config.AP_STATION_SUPPORT;

+        target.hasWifiSwitch = config.WIFI_SWITCH_SUPPORT;

+        target.hasMultiSSID = config.HAS_MULTI_SSID;

+        target.showIsolated = config.SHOW_WIFI_AP_ISOLATED;

+

+        var info = service.getMacFilterInfo();

+        var wifiBaseInfo = service.getWifiBasic();

+        target.multi_ssid_enable = ko.observable(wifiBaseInfo.multi_ssid_enable);

+        target.origin_ap_station_enable = wifiBaseInfo.ap_station_enable;

+        target.wifi_enable = ko.observable(wifiBaseInfo.wifi_enable);

+

+        target.isShowSSIDInfoDiv = ko.observable(false);

+        if (config.WIFI_SWITCH_SUPPORT) {

+            if (wifiBaseInfo.wifi_enable == "1") {

+                target.isShowSSIDInfoDiv(true);

+            } else {

+                target.isShowSSIDInfoDiv(false);

+            }

+        } else {

+            target.isShowSSIDInfoDiv(true);

+        }

+

+        target.selectedAction = ko.observable(info.ACL_mode);

+        target.mac1 = ko.observable("");

+        target.mac2 = ko.observable("");

+        target.mac3 = ko.observable("");

+        target.mac4 = ko.observable("");

+        target.mac5 = ko.observable("");

+        target.mac6 = ko.observable("");

+        target.mac7 = ko.observable("");

+        target.mac8 = ko.observable("");

+        target.mac9 = ko.observable("");

+        target.mac10 = ko.observable("");

+        if (info.ACL_mode == "1") {

+            macInfoWhite = info.wifi_mac_white_list.split(";");

+            target.mac1 = ko.observable(macInfoWhite[0]);

+            target.mac2 = ko.observable(macInfoWhite[1]);

+            target.mac3 = ko.observable(macInfoWhite[2]);

+            target.mac4 = ko.observable(macInfoWhite[3]);

+            target.mac5 = ko.observable(macInfoWhite[4]);

+            target.mac6 = ko.observable(macInfoWhite[5]);

+            target.mac7 = ko.observable(macInfoWhite[6]);

+            target.mac8 = ko.observable(macInfoWhite[7]);

+            target.mac9 = ko.observable(macInfoWhite[8]);

+            target.mac10 = ko.observable(macInfoWhite[9]);

+        } else if (info.ACL_mode == "2") {

+            macInfoBlack = info.wifi_mac_black_list.split(";");

+            target.mac1 = ko.observable(macInfoBlack[0]);

+            target.mac2 = ko.observable(macInfoBlack[1]);

+            target.mac3 = ko.observable(macInfoBlack[2]);

+            target.mac4 = ko.observable(macInfoBlack[3]);

+            target.mac5 = ko.observable(macInfoBlack[4]);

+            target.mac6 = ko.observable(macInfoBlack[5]);

+            target.mac7 = ko.observable(macInfoBlack[6]);

+            target.mac8 = ko.observable(macInfoBlack[7]);

+            target.mac9 = ko.observable(macInfoBlack[8]);

+            target.mac10 = ko.observable(macInfoBlack[9]);

+        }

+

+        target.save = filter_save;

+        //切换MAC过滤规则事件

+        target.ChangeHandler = function () {

+            $("#mac_filter_form").find(".error").hide();

+            $("#mac_filter_form").find("input[type=text]").show();

+            var info = service.getMacFilterInfo();

+            if (target.selectedAction() == "1") {

+                macInfoWhite = info.wifi_mac_white_list.split(";");

+                target.mac1(macInfoWhite[0]);

+                target.mac2(macInfoWhite[1]);

+                target.mac3(macInfoWhite[2]);

+                target.mac4(macInfoWhite[3]);

+                target.mac5(macInfoWhite[4]);

+                target.mac6(macInfoWhite[5]);

+                target.mac7(macInfoWhite[6]);

+                target.mac8(macInfoWhite[7]);

+                target.mac9(macInfoWhite[8]);

+                target.mac10(macInfoWhite[9]);

+            } else if (target.selectedAction() == "2") {

+                macInfoBlack = info.wifi_mac_black_list.split(";");

+                target.mac1(macInfoBlack[0]);

+                target.mac2(macInfoBlack[1]);

+                target.mac3(macInfoBlack[2]);

+                target.mac4(macInfoBlack[3]);

+                target.mac5(macInfoBlack[4]);

+                target.mac6(macInfoBlack[5]);

+                target.mac7(macInfoBlack[6]);

+                target.mac8(macInfoBlack[7]);

+                target.mac9(macInfoBlack[8]);

+                target.mac10(macInfoBlack[9]);

+            } else {

+                target.mac1("");

+                target.mac2("");

+                target.mac3("");

+                target.mac4("");

+                target.mac5("");

+                target.mac6("");

+                target.mac7("");

+                target.mac8("");

+                target.mac9("");

+                target.mac10("");

+            }

+        }

+        //检查WPS状态

+        target.checkSettings = function (ssid) {

+            var wifi_status = service.getWpsInfo();

+            if (wifi_status.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+            return false;

+        };

+

+        //设置多SSID开关

+        target.setMultiSSIDSwitch = function () {

+            if (target.checkSettings("switch")) {

+                return;

+            }

+

+            var setSwitch = setFilterSwitch;

+

+            var info = service.getStatusInfo();

+            if (config.HAS_MULTI_SSID && target.wifi_enable() == "1") {

+                if (target.multi_ssid_enable() == "1" && config.AP_STATION_SUPPORT && target.origin_ap_station_enable == "1") {

+                    if (!info.wifiStatus) {

+                        showConfirm("multi_ssid_enable_confirm", function () {

+                            setSwitch();

+                        });

+                    } else {

+                        showConfirm("multi_ssid_enable_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                } else {

+                    if (!info.wifiStatus) {

+                        setSwitch();

+                    } else {

+                        showConfirm("wifi_disconnect_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                }

+            } else {

+                setSwitch();

+            }

+			

+			function setFilterSwitch() {

+                showLoading('waiting');

+                var filter_param = {};

+                filter_param.m_ssid_enable = target.multi_ssid_enable();

+                if (config.WIFI_SWITCH_SUPPORT) {

+                    filter_param.wifiEnabled = target.wifi_enable();

+                }

+                service.setWifiBasicMultiSSIDSwitch(filter_param, function (result) {

+                    if (result.result == "success") {

+                        if (!viaWifi) {

+                            addInterval(function () {

+                                var info = service.getWifiBasic();

+                                service.refreshAPStationStatus();

+                                if (info.wifi_enable == target.wifi_enable()) {

+                                    successOverlay();

+                                    clearTimer();

+                                    clearValidateMsg();

+                                    service.refreshAPStationStatus();

+                                    initialize();

+                                }

+                            }, 1000);

+                        } else {

+                            setTimeout(function () {

+                                successOverlay();

+                                setTimeout(function () {

+                                    window.location.reload();

+                                }, 1000);

+                                clearTimer();

+                                clearValidateMsg();

+                                service.refreshAPStationStatus();

+                                initialize();

+                            }, 15000);

+                        }

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            }

+        };

+

+		function filter_save() {

+            var wifi_status = service.getWpsInfo();

+            if (wifi_status.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+

+            if (target.mac1() == undefined || target.mac1().indexOf(" ") >= 0) {

+                target.mac1("")

+            }

+            if (target.mac2() == undefined || target.mac2().indexOf(" ") >= 0) {

+                target.mac2("")

+            }

+            if (target.mac3() == undefined || target.mac3().indexOf(" ") >= 0) {

+                target.mac3("")

+            }

+            if (target.mac4() == undefined || target.mac4().indexOf(" ") >= 0) {

+                target.mac4("")

+            }

+            if (target.mac5() == undefined || target.mac5().indexOf(" ") >= 0) {

+                target.mac5("")

+            }

+            if (target.mac6() == undefined || target.mac6().indexOf(" ") >= 0) {

+                target.mac6("")

+            }

+            if (target.mac7() == undefined || target.mac7().indexOf(" ") >= 0) {

+                target.mac7("")

+            }

+            if (target.mac8() == undefined || target.mac8().indexOf(" ") >= 0) {

+                target.mac8("")

+            }

+            if (target.mac9() == undefined || target.mac9().indexOf(" ") >= 0) {

+                target.mac9("")

+            }

+            if (target.mac10() == undefined || target.mac10().indexOf(" ") >= 0) {

+                target.mac10("")

+            }

+

+            var mac_list = new Array(target.mac1(), target.mac2(), target.mac3(), target.mac4(), target.mac5(),

+                    target.mac6(), target.mac7(), target.mac8(), target.mac9(), target.mac10());

+            if (target.selectedAction() == "2" && info.client_mac_address != "" && $.inArray(info.client_mac_address, mac_list) != -1) {

+                showAlert('black_yourself_tip');

+                return false;

+            }

+            var list_sort = mac_list.sort(); //排序

+            for (var i = 0; i < list_sort.length - 1; i++) {

+                if (list_sort[i] != "" && list_sort[i] == list_sort[i + 1]) {

+                    showAlert('mac_repeat_tip');

+                    return false;

+                }

+            }

+            var string_maclist = "";

+            for (var i = 0; i < 10; i++) {

+                if (string_maclist == "") {

+                    string_maclist = mac_list[i];

+                } else {

+                    if (mac_list[i]) {

+                        string_maclist = string_maclist + ";" + mac_list[i];

+                    }

+                }

+            }

+            var filter_param = {};

+            filter_param.ACL_mode = target.selectedAction();

+            if (target.selectedAction() == "2") {

+                filter_param.wifi_mac_black_list = string_maclist;

+            } else if (target.selectedAction() == "1") {

+                filter_param.wifi_mac_white_list = string_maclist;

+            }

+            showLoading('waiting');

+            service.setMacFilter(filter_param, function (result) {

+                if (result.result == "success") {

+                    successOverlay();

+                } else {

+                    errorOverlay();

+                }

+            });

+        }

+    }

+

+    function bindContainer(filter_vm) {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(filter_vm, container[0]);

+

+        $('#frmWifiSwitch').validate({

+            submitHandler: function () {

+                filter_vm.setMultiSSIDSwitch();

+            }

+        });

+        $('#mac_filter_form').validate({

+            submitHandler: function () {

+                filter_vm.save();

+            },

+            rules: {

+                mac_1: 'mac_check',

+                mac_2: 'mac_check',

+                mac_3: 'mac_check',

+                mac_4: 'mac_check',

+                mac_5: 'mac_check',

+                mac_6: 'mac_check',

+                mac_7: 'mac_check',

+                mac_8: 'mac_check',

+                mac_9: 'mac_check',

+                mac_10: 'mac_check'

+            }

+        });

+    }

+    function initialize() {

+        var filter_vm = new macFilterViewModel();

+        bindContainer(filter_vm);

+

+        addTimeout(function () {

+            checkAccessMode();

+        }, 600);

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+define("wifi_main","underscore jquery knockout set service CryptoJS".split(" "),

+    function (_, $, ko, config, service, CryptoJS) {

+

+    var securityModes = _.map(config.WIFI_WEP_SUPPORT ? config.AUTH_MODES_WEP : config.AUTH_MODES, function (item) {

+        return new Option(item.name, item.value);

+    });

+

+    function maxStationAccess(max) {

+        var showOption = [];

+        for (var i = 1; i <= max; i++) {

+            showOption.push(new Option(i, i));

+        }

+        return showOption;

+    }

+    //是否通过wifi接入

+    var viaWifi = false;

+    function checkAccessMode() {

+        service.getParams({

+            nv: 'user_ip_addr'

+        }, function (dataIp) {

+            service.getParams({

+                nv: 'station_list'

+            }, function (dataList) {

+                viaWifi = isWifiConnected(dataIp.user_ip_addr, dataList.station_list);

+            });

+        });

+    }

+

+    function WifiMainVM() {

+        var target = this;

+        var info = getWifiMain();

+

+        target.hasWifiSwitch = config.WIFI_SWITCH_SUPPORT;

+        target.hasMultiSSID = config.HAS_MULTI_SSID;

+        target.showIsolated = config.SHOW_WIFI_AP_ISOLATED;

+        target.hasAPStation = config.AP_STATION_SUPPORT;

+        target.hasWlanMacfilter = config.HAS_BLACK_AND_WHITE_FILTER;

+        target.hasWifiWep = config.WIFI_WEP_SUPPORT;

+        target.hasWifiWpa3 = config.WIFI_WAP3_SUPPORT;

+        target.hasWifiWpa23 = config.WIFI_WPA2_WAP3_SUPPORT;

+

+        var advanceInfo = service.getWifiAdvance();

+        target.adBand = ko.observable(advanceInfo.wifiBand);

+        target.adMode = ko.observable(advanceInfo.mode);

+        target.showQRSwitch = config.WIFI_SUPPORT_QR_CODE && config.WIFI_SUPPORT_QR_SWITCH;

+        target.showQR = ko.observable(info.show_qrcode_flag);

+        if (config.WIFI_SUPPORT_QR_SWITCH) {

+            target.showQRCode = ko.observable(config.WIFI_SUPPORT_QR_CODE && target.showQR());

+        } else {

+            target.showQRCode = ko.observable(config.WIFI_SUPPORT_QR_CODE);

+        }

+        target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + $.now();

+

+        target.origin_ap_station_enable = info.ap_station_enable;

+        target.wifi_enable = ko.observable(info.wifi_enable);

+

+        target.isShowSSIDInfoDiv = ko.observable(false);

+        if (config.WIFI_SWITCH_SUPPORT) {

+            if (info.wifi_enable == "1") {

+                target.isShowSSIDInfoDiv(true);

+            } else {

+                target.isShowSSIDInfoDiv(false);

+            }

+        } else {

+            target.isShowSSIDInfoDiv(true);

+        }

+

+        target.multi_ssid_enable = ko.observable(info.multi_ssid_enable);

+        target.origin_multi_ssid_enable = info.multi_ssid_enable;

+

+        target.maxStationNumber = ko.computed(function () {

+            return config.MAX_STATION_NUMBER;

+        });

+

+        target.modes = ko.observableArray(securityModes);

+        target.selectedMode = ko.observable(info.AuthMode);

+        target.passPhrase = ko.observable(info.passPhrase);

+        target.showPassword = ko.observable(false);

+        target.ssid = ko.observable(info.SSID);

+        target.broadcast = ko.observable(info.broadcast == '1' ? '1' : '0');

+        target.apIsolation = ko.observable(info.apIsolation == '1' ? '1' : '0');

+        target.cipher = info.cipher;

+        target.selectedStation = ko.observable(info.MAX_Access_num);

+        target.maxStations = ko.observableArray(maxStationAccess(info.MAX_Station_num));

+        target.encryptType = ko.observable(info.encryptType);

+        target.keyID = ko.observable(info.keyID);

+        target.wepPassword = ko.observable("");

+

+        target.m_modes = ko.observableArray(securityModes);

+        target.m_selectedMode = ko.observable(info.m_AuthMode);

+        target.m_passPhrase = ko.observable(info.m_passPhrase);

+        target.m_showPassword = ko.observable(false);

+        target.m_ssid = ko.observable(info.m_SSID);

+        target.m_broadcast = ko.observable(info.m_broadcast == '1' ? '1' : '0');

+        target.m_apIsolation = ko.observable(info.m_apIsolation == '1' ? '1' : '0');

+        target.m_cipher = info.m_cipher;

+        target.m_selectedStation = ko.observable(info.m_MAX_Access_num);

+        target.m_maxStations = ko.observableArray(maxStationAccess(info.MAX_Station_num));

+

+        target.getWepPassword = function () {

+            return target.keyID() == '3' ? info.Key4Str1 : (target.keyID() == '2' ? info.Key3Str1 : target.keyID() == '1' ? info.Key2Str1 : info.Key1Str1);

+        }

+        target.wepPassword(target.getWepPassword());

+        target.profileChangeHandler = function (data, event) {

+            $("#pwdWepKey").parent().find("label[class='error']").hide();

+            target.wepPassword(target.getWepPassword());

+            return true;

+        };

+

+        target.clear = function (option) {

+            if (option == "switch") {

+                target.multi_ssid_enable(info.multi_ssid_enable);

+                target.wifi_enable(info.wifi_enable);

+            } else if (option == "ssid2") {

+                target.m_selectedMode(info.m_AuthMode);

+                target.m_passPhrase(info.m_passPhrase);

+                target.m_ssid(info.m_SSID);

+                target.m_broadcast(info.m_broadcast == '1' ? '1' : '0');

+                target.m_cipher = info.m_cipher;

+                target.m_selectedStation(info.m_MAX_Access_num);

+                target.m_apIsolation(info.m_apIsolation == '1' ? '1' : '0');

+            } else if (option == "ssid1") {

+                target.selectedMode(info.AuthMode);

+                target.passPhrase(info.passPhrase);

+                target.ssid(info.SSID);

+                target.broadcast(info.broadcast == '1' ? '1' : '0');

+                target.cipher = info.cipher;

+                target.selectedStation(info.MAX_Access_num);

+                target.apIsolation(info.apIsolation == '1' ? '1' : '0');

+                if (config.WIFI_WEP_SUPPORT) {

+                    target.encryptType(info.encryptType);

+                    target.keyID(info.keyID);

+                    target.wepPassword(target.getWepPassword());

+                }

+            } else {

+                clearTimer();

+                clearValidateMsg();

+                initialize();

+            }

+        };

+

+        target.saveSSID1 = function () {

+            if (target.checkSettings("ssid1")) {

+                return;

+            }

+            if (!config.PASSWORD_ENCODE) {

+                var pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,32}');

+                if (!pwdRegex.test(target.passPhrase())) {

+                        showConfirm("password_note_too_low", function () {

+                            showConfirm('wifi_disconnect_confirm', function () {

+                            target.saveSSID1Action();

+                            return;

+                        });

+                        return;

+                    });

+                    return;

+                }

+            }

+            showConfirm('wifi_disconnect_confirm', function () {

+                target.saveSSID1Action();

+            });

+        };

+

+        target.saveSSID1Action = getSSID1Action;

+

+        target.saveSSID2 = function () {

+            if (target.checkSettings("ssid2")) {

+                return;

+            }

+            showConfirm('wifi_disconnect_confirm', function () {

+                target.saveSSID2Action();

+            });

+        };

+

+        target.saveSSID2Action = getSSID2Action;

+

+        //检测wps\最大接入数

+        target.checkSettings = function (ssid) {

+            var status = getWpsState();

+            if (ssid == "ssid1" || ssid == "ssid2") {

+                if (ssid == "ssid2") {

+                    var accessDevice = service.getStatusInfo().ssid2AttachedNum;

+                    if (parseInt(target.m_selectedStation()) < accessDevice) {

+                        showAlert('Extend_accessDevice');

+                        return true;

+                    }

+                } else {

+                    var accessDevice = service.getStatusInfo().ssid1AttachedNum;

+                    if (parseInt(target.selectedStation()) < accessDevice) {

+                        showAlert('Extend_accessDevice');

+                        return true;

+                    }

+                }

+            }

+

+            if (status.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+

+            if (info.multi_ssid_enable == "1" && config.HAS_MULTI_SSID) {

+                if ((ssid == "ssid2" && parseInt(target.m_selectedStation()) + parseInt(info.MAX_Access_num) > info.MAX_Station_num)

+                     || (ssid == "ssid1" && parseInt(target.selectedStation()) + parseInt(info.m_MAX_Access_num) > info.MAX_Station_num)) {

+                    showAlert({

+                        msg: 'multi_ssid_max_access_number_alert',

+                        params: info.MAX_Station_num

+                    });

+                    return true;

+                }

+            }

+

+            return false;

+        };

+

+        target.setMultiSSIDSwitch = function () {

+            if (target.checkSettings("switch")) {

+                return;

+            }

+

+            var setSwitch = function () {

+                showLoading('waiting');

+                var params = {};

+                params.m_ssid_enable = target.multi_ssid_enable();

+                if (config.WIFI_SWITCH_SUPPORT) {

+                    params.wifiEnabled = target.wifi_enable();

+                }

+                service.setWifiBasicMultiSSIDSwitch(params, function (result) {

+                    if (result.result == "success") {

+                        if (viaWifi) {

+                            setTimeout(hasApReloadVarWifi, 15000);

+                        } else {

+                            addInterval(hasApReload, 1000);

+                        }

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            };

+

+            function hasApReloadVarWifi() {

+                successOverlay();

+                setTimeout(function () {

+                    window.location.reload();

+                }, 1000);

+                service.refreshAPStationStatus();

+                target.clear();

+            }

+            function hasApReload() {

+                var info = getWifiMain();

+                service.refreshAPStationStatus();

+                if (info.wifi_enable == target.wifi_enable()) {

+                    successOverlay();

+                    target.clear();

+                }

+            }

+

+            var info = service.getStatusInfo();

+            if (config.HAS_MULTI_SSID && target.wifi_enable() == "1") {

+                if (target.multi_ssid_enable() == "1" && config.AP_STATION_SUPPORT && target.origin_ap_station_enable == "1") {

+                    if (!info.wifiStatus) {

+                        showConfirm("multi_ssid_enable_confirm", function () {

+                            setSwitch();

+                        });

+                    } else {

+                        showConfirm("multi_ssid_enable_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                } else {

+                    if (!info.wifiStatus) {

+                        setSwitch();

+                    } else {

+                        showConfirm("wifi_disconnect_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                }

+            } else {

+                setSwitch();

+            }

+        };

+

+        //二维码显示事件

+        target.showQRHandler = function () {

+            var checkbox = $("#showQR:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showQR(true);

+            } else {

+                target.showQR(false);

+            }

+            target.showQRCode(config.WIFI_SUPPORT_QR_CODE && target.showQR());

+        };

+

+        //SSID2

+        target.m_showPasswordHandler = function () {

+            $("#m_passShow").parent().find(".error").hide();

+            var checkbox = $("#m_showPassword:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.m_showPassword(true);

+            } else {

+                target.m_showPassword(false);

+            }

+        };

+        target.showPasswordHandler = function () {

+            $("#codeWPAKey").parent().find(".error").hide();

+            $("#pwdWepKey").parent().find(".error").hide();

+            var checkbox = $("#showPassword:checked");

+            if (checkbox && checkbox.length == 0) {

+                target.showPassword(true);

+            } else {

+                target.showPassword(false);

+            }

+        };

+

+        function getSSID2Action() {

+            showLoading('waiting');

+            var params = {};

+            params.m_AuthMode = target.m_selectedMode();

+            params.m_passPhrase = target.m_passPhrase();

+            params.m_SSID = target.m_ssid();

+            params.m_broadcast = target.m_broadcast();

+            params.m_station = target.m_selectedStation();

+            params.m_cipher = target.m_selectedMode() == "WPA2PSK" ? 1 : 2;

+            if (params.m_AuthMode == "WPA3Personal" || params.m_AuthMode == "WPA2WPA3") {

+                params.m_cipher = 1;

+            }

+            params.m_NoForwarding = target.m_apIsolation();

+            params.m_show_qrcode_flag = target.showQR() == true ? 1 : 0;

+            service.setWifiBasic4SSID2(params, function (result) {

+                if (result.result == "success") {

+                    if (viaWifi) {

+                        setTimeout(ssid2ReloadVarWifi, 15000);

+                    } else {

+                        addInterval(ssid2Reload, 1000);

+                    }

+                } else {

+                    errorOverlay();

+                }

+            });

+        }

+        function ssid2ReloadVarWifi() {

+            successOverlay();

+            setTimeout(function () {

+                window.location.reload();

+            }, 1000);

+            target.clear();

+        }

+        function ssid2Reload() {

+            var info = getWifiMain();

+            if (info.wifi_enable == "1") {

+                successOverlay();

+                target.clear();

+            }

+        }

+

+        function getSSID1Action() {

+

+            showLoading('waiting');

+            target.broadcast($("#broadcastCheckbox:checked").length > 0 ? '0' : '1');

+            target.apIsolation($("#apisolatedCheckbox:checked").length);

+            var ciphertext = "";

+            if (config.PASSWORD_ENCODE) {

+	        ciphertext = target.passPhrase();

+	    } else {

+                var kparam = service.getDeviceInfoLow();

+                var tkey = CryptoJS.enc.Latin1.parse(kparam.skey);

+		var tiv = CryptoJS.enc.Latin1.parse(kparam.siv);

+                ciphertext = CryptoJS.AES.encrypt(target.passPhrase(), tkey, {

+                    iv: tiv,

+                    mode: CryptoJS.mode.CBC,

+                    padding: CryptoJS.pad.ZeroPadding

+                    }).toString();

+	    }

+            var params = {};

+            params.AuthMode = target.selectedMode();

+            params.passPhrase = ciphertext;

+            params.SSID = target.ssid();

+            params.broadcast = target.broadcast();

+            params.station = target.selectedStation();

+            params.cipher = target.selectedMode() == "WPA2PSK" ? 1 : 2;

+            if (params.AuthMode == "WPA3Personal" || params.AuthMode == "WPA2WPA3") {

+                params.cipher = 1;

+            }

+            params.NoForwarding = target.apIsolation();

+            params.show_qrcode_flag = target.showQR() == true ? 1 : 0;

+            if (config.WIFI_WEP_SUPPORT) {

+                if (params.AuthMode == "WPAPSK" || params.AuthMode == "WPA2PSK" || params.AuthMode == "WPAPSKWPA2PSK" || params.AuthMode == "WPA3Personal" || params.AuthMode == "WPA2WPA3") {}

+                else if (params.AuthMode == "SHARED") {

+                    params.encryptType = "WEP";

+                } else {

+                    params.encryptType = target.encryptType();

+                }

+                params.wep_default_key = target.keyID();

+                params.wep_key_1 = info.Key1Str1;

+                params.wep_key_2 = info.Key2Str1;

+                params.wep_key_3 = info.Key3Str1;

+                params.wep_key_4 = info.Key4Str1;

+                var WEPSelect = '0';

+                if (target.wepPassword().length == '5' || target.wepPassword().length == '13') {

+                    WEPSelect = '1';

+                } else {

+                    WEPSelect = '0';

+                }

+                if (target.keyID() == '3') {

+                    params.wep_key_4 = target.wepPassword();

+                    params.WEP4Select = WEPSelect;

+                } else if (target.keyID() == '2') {

+                    params.wep_key_3 = target.wepPassword();

+                    params.WEP3Select = WEPSelect;

+                } else if (target.keyID() == '1') {

+                    params.wep_key_2 = target.wepPassword();

+                    params.WEP2Select = WEPSelect;

+                } else {

+                    params.wep_key_1 = target.wepPassword();

+                    params.WEP1Select = WEPSelect;

+                }

+            }

+

+            service.setWifiBasic(params, function (result) {

+                if (result.result == "success") {

+                    if (viaWifi) {

+                        setTimeout(ssid1ReloadVarWifi, 15000);

+                    } else {

+                        addInterval(ssid1Reload, 1000);

+                    }

+                } else {

+                    errorOverlay();

+                }

+            });

+        }

+        function ssid1ReloadVarWifi() {

+            successOverlay();

+            setTimeout(function () {

+                window.location.reload();

+            }, 1000);

+            target.clear();

+        }

+        function ssid1Reload() {

+            var info = getWifiMain();

+            if (info.wifi_enable == "1") {

+                successOverlay();

+                target.clear();

+            }

+        }

+

+    }

+

+    function getWpsState() {

+        return service.getWpsInfo();

+    }

+

+    function getWifiMain() {

+        return service.getWifiBasic();

+    }

+

+    function initialize() {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        var vm = new WifiMainVM();

+        ko.applyBindings(vm, container[0]);

+        addTimeout(function () {

+            checkAccessMode();

+        }, 600);

+

+        if (config.WDS_SUPPORT) {

+            checkWifiStatusAccordingToWDS();

+        } else if (config.AP_STATION_SUPPORT) {

+            checkWifiStatus();

+        }

+

+        $('#frmSSID1').validate({

+            submitHandler: function () {

+                vm.saveSSID1();

+            },

+            rules: {

+                ssid: 'ssid',

+                pwdWepKey: {

+                    wifi_wep_password_check: true,

+                    wifi_password_check: true

+                },

+                txtWepKey: {

+                    wifi_wep_password_check: true,

+                    wifi_password_check: true

+                },

+                codeWPAKey: 'wifi_password_check',

+                txtWPAKey: 'wifi_password_check'

+            },

+            errorPlacement: function (error, element) {

+                var id = element.attr("id");

+                if (id == "codeWPAKey" || id == "txtWPAKey") {

+                    error.insertAfter("#lblshowWPAPassword");

+                } else if (id == "pwdWepKey" || id == "txtWepKey") {

+                    error.insertAfter("#lblShowWepPassword");

+                } else {

+                    error.insertAfter(element);

+                }

+            }

+        });

+        $('#frmSSID2').validate({

+            submitHandler: function () {

+                vm.saveSSID2();

+            },

+            rules: {

+                m_ssid: 'ssid',

+                m_pass: 'wifi_password_check',

+                m_passShow: 'wifi_password_check'

+            },

+            errorPlacement: function (error, element) {

+                var id = element.attr("id");

+                if (id == "m_pass" || id == "m_passShow") {

+                    error.insertAfter("#m_lblShowPassword");

+                } else if (id == "pass" || id == "passShow") {

+                    error.insertAfter("#lblShowPassword");

+                } else {

+                    error.insertAfter(element);

+                }

+            }

+        });

+        //表单提交函数、校验规则配置

+        $('#frmWifiSwitch').validate({

+            submitHandler: function () {

+                vm.setMultiSSIDSwitch();

+            }

+        });

+

+        $('#frmMultiSSID').validate({

+            submitHandler: function () {

+                vm.setMultiSSIDSwitch();

+            }

+        });

+

+    }

+

+    function checkWifiStatusAccordingToWDS() {

+        var info = service.getWdsInfo();

+        if (info.currentMode == "0") {

+            $('#frmWifiSwitch :input').each(function () {

+                $(this).prop("disabled", false);

+            });

+            $('#frmSSID1 :input').each(function () {

+                $(this).prop("disabled", false);

+            });

+            $('#frmSSID2 :input').each(function () {

+                $(this).prop("disabled", false);

+            });

+        } else {

+            $('#frmWifiSwitch :input').each(function () {

+                $(this).prop("disabled", true);

+            });

+            $('#frmSSID1 :input').each(function () {

+                $(this).prop("disabled", true);

+            });

+            $('#frmSSID2 :input').each(function () {

+                $(this).prop("disabled", true);

+            });

+        }

+    }

+    function checkWifiStatus() {

+        var info = service.getAPStationBasic();

+        if (info.ap_station_enable == "1") {

+            $('#frmMultiSSID :input').each(function () {

+                $(this).prop("disabled", true);

+            });

+        } else {

+            $('#frmMultiSSID :input').each(function () {

+                $(this).prop("disabled", false);

+            });

+        }

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+define("wifi_sleep_mode","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    //休眠方式

+    function getSleepMode() {

+        return service.getSleepMode();

+    }

+

+    //覆盖范围

+    function getWifiRange() {

+        return service.getWifiRange();

+    }

+

+    var sleepTime = _.map(config.SLEEP_MODES, function (item) {

+        return new Option(item.name, item.value);

+    });

+

+    function SleepModeViewMode() {

+        var target = this;

+

+        target.isCPE = config.PRODUCT_TYPE == 'CPE';

+        target.showTSWDiv = config.TSW_SUPPORT;

+        target.showSleepDiv = config.WIFI_SLEEP_SUPPORT;

+        target.hasUssd = config.HAS_USSD;

+        target.hasUpdateCheck = config.HAS_UPDATE_CHECK;

+        target.hasDdns = config.DDNS_SUPPORT;

+

+        target.modes = ko.observableArray(sleepTime);

+

+        var smInfo = getSleepMode();

+        target.selectedMode = ko.observable(smInfo.sleepMode);

+

+        var wifiRangeInfo = getWifiRange();

+        target.wifiRangeMode = ko.observable(wifiRangeInfo.wifiRangeMode);

+

+        target.setWifiRange = smSetWifiRange;

+

+        target.setWifiRangeAct = smSetWifiRangeAct;

+

+        target.setSleepMode = smSetSleepMode;

+

+        target.setSleepModeAct = smSetSleepModeAct;

+

+        var tsw = service.getTsw();

+        target.openEnable = ko.observable(tsw.openEnable == "" ? '0' : tsw.openEnable);

+        target.openH = ko.observable(tsw.openH);

+        target.openM = ko.observable(tsw.openM);

+        target.closeH = ko.observable(tsw.closeH);

+        target.closeM = ko.observable(tsw.closeM);

+        //定时休眠唤醒

+        target.saveTsw = smSaveTsw;

+

+        function smSetWifiRange() {

+            service.getWpsInfo({}, function (smInfo) {

+                if (smInfo.wpsFlag == '1') {

+                    showAlert('wps_on_info');

+                } else if (smInfo.radioFlag == '0') {

+                    showAlert('wps_wifi_off');

+                } else {

+                    showConfirm('wifi_sleep_confirm', function () {

+                        showLoading('waiting');

+                        target.setWifiRangeAct();

+                    });

+

+                }

+            });

+        }

+        function smSetSleepModeAct() {

+            var params = {};

+            params.sleepMode = target.selectedMode();

+            service.setSleepMode(params, function (result) {

+                if (result.result != "success") {

+                    errorOverlay();

+                } else {

+                    successOverlay();

+                }

+            });

+        }

+

+        function smSetWifiRangeAct() {

+            var params = {};

+            params.wifiRangeMode = target.wifiRangeMode();

+            service.setWifiRange(params, function (result) {

+                if (result.result != "success") {

+                    errorOverlay();

+                } else {

+                    successOverlay();

+                }

+            });

+        }

+

+        function smSetSleepMode() {

+            showLoading('waiting');

+            service.getWpsInfo({}, function (info) {

+                if (info.wpsFlag == '1') {

+                    showAlert('wps_on_info');

+                } else if (info.radioFlag == '0') {

+                    showAlert('wps_wifi_off');

+                } else {

+                    target.setSleepModeAct();

+                }

+            });

+        }

+        function smSaveTsw() {

+            if (target.openEnable() == '1') {

+                if (Math.abs((target.openH() * 60 + parseInt(target.openM(), 10)) - (target.closeH() * 60 + parseInt(target.closeM(), 10))) < 10) {

+                    showAlert('tsw_time_interval_alert');

+                    return false;

+                }

+                showLoading('waiting');

+                service.saveTsw({

+                    openEnable: target.openEnable(),

+                    closeEnable: target.openEnable(),

+                    openTime: leftInsert(target.openH(), 2, '0') + ':' + leftInsert(target.openM(), 2, '0'),

+                    closeTime: leftInsert(target.closeH(), 2, '0') + ':' + leftInsert(target.closeM(), 2, '0')

+                }, smShowRes, $.noop);

+            } else {

+                showLoading('waiting');

+                service.saveTsw({

+                    openEnable: target.openEnable(),

+                    closeEnable: target.openEnable()

+                }, smShowRes, $.noop);

+            }

+

+        }

+

+    }

+    function bindContainer(smVm) {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(smVm, container[0]);

+

+        $('#frmTsw').validate({

+            submitHandler: function () {

+                smVm.saveTsw();

+            },

+            errorPlacement: function (error, element) {

+                if (element.attr("name") == "closeM" || element.attr("name") == "closeH") {

+                    $("#closeErrorDiv").html(error);

+                } else if (element.attr("name") == "openM" || element.attr("name") == "openH") {

+                    $("#openErrorDiv").html(error);

+                } else {

+                    error.insertAfter(element);

+                }

+            }

+        });

+

+        $('#sleepModeForm').validate({

+            submitHandler: function () {

+                smVm.setSleepMode();

+            }

+        });

+

+        $('#wifiRangeForm').validate({

+            submitHandler: function () {

+                smVm.setWifiRange();

+            }

+        });

+

+    }

+    function initialize() {

+        var smVm = new SleepModeViewMode();

+        bindContainer(smVm);

+    }

+    function smShowRes(data) {

+        if (data && data.result == "success") {

+            successOverlay();

+        } else {

+            errorOverlay();

+        }

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+define("wifi_station_info","underscore jquery knockout set service menu".split(" "),

+    function (_, $, ko, config, service, menu) {

+

+    var stationUtil = {

+        dealElement: function (showEdit, idx) {

+            if (idx != "all") {

+                if (!showEdit) {

+                    $("#edit_btn_" + idx + ",#hostname_txt_" + idx).show();

+                    $("#save_btn_" + idx + ",#cancel_btn_" + idx + ",#hostname_input_" + idx).hide();

+                } else {

+                    $("#edit_btn_" + idx + ",#hostname_txt_" + idx).hide();

+                    $("#save_btn_" + idx + ",#cancel_btn_" + idx + ",#hostname_input_" + idx).show();

+                }

+            } else {

+                $("input[id^='hostname_txt_'],a[id^='edit_btn_']").show();

+                $("input[id^='hostname_input_'],a[id^='cancel_btn_'],a[id^='save_btn_']").hide();

+            }

+        },

+        //根据MAC匹配主机名

+        getHostName: function (hostName, mac, hostNameList) {

+            var element_data = _.find(hostNameList, function (element_data) {

+                return element_data.mac == mac;

+            });

+            return element_data ? element_data.hostname : hostName;

+        },

+        //匹配黑名单列表和主机名

+        parseBlackString: function (macStr, hostnameStr) {

+            if (macStr == "") {

+                return [];

+            }

+            var tempMac = macStr.split(';');

+            var tempHostName = hostnameStr.split(';');

+            var result = [];

+            for (var i = 0; i < tempMac.length; i++) {

+                //var obj = {};

+                //obj.hostName = tempHostName[i];

+                //obj.macAddress = tempMac[i];

+                result.push({

+                    hostName: tempHostName[i],

+                    macAddress: tempMac[i]

+                });

+            }

+            return result;

+        }

+    };

+

+    function staInfoViewMode() {

+        var target = this;

+        var originalData = {

+            user_ip: '',

+            macList: '',

+            ACL_mode: 2, //黑白名单

+            hostnameList: ''

+        };

+        target.showCableDiv = config.PRODUCT_TYPE == 'CPE' && config.RJ45_SUPPORT;

+        target.supportBlock = config.STATION_BLOCK_SUPPORT;

+        var pcMenu = menu.findMenu('#parental_control');

+        target.showPCLink = pcMenu && pcMenu.length > 0 && config.HAS_PARENTAL_CONTROL;

+

+        target.deviceInfo = ko.observableArray([]);

+        target.cableDeviceInfo = ko.observableArray([]);

+        target.blackDevices = ko.observableArray([]);

+        target.blackDevicesMac = ko.computed(function () {

+            return _.map(target.blackDevices(), function (element_data) {

+                return element_data.macAddress;

+            });

+        });

+        target.showBlackDiv = ko.observable(config.HAS_BLACK_AND_WHITE_FILTER ? (originalData.ACL_mode == '2' ? true : false) : config.STATION_BLOCK_SUPPORT);

+

+        ko.computed(function () {

+            target.deviceInfo();

+            target.cableDeviceInfo();

+            target.blackDevices();

+            $("#station_info_div").translate();

+        }).extend({

+            notify: 'always',

+            throttle: 300

+        });

+

+        var hostNameList = service.getHostNameList({}).devices;

+        //获取WiFi已连接设备

+        target.fetchAttachedDevices = function (cb) {

+            service.getCurrentlyAttachedDevicesInfo({}, function (data) {

+                if (editingHostname) {

+                    return false;

+                }

+                target.deviceInfo(_.map(data.attachedDevices, function (element_data, idx) {

+                        element_data.idx = _.uniqueId('wireless_');

+                        element_data.type = 1;

+                        element_data.inBlackGroup = config.HAS_BLACK_AND_WHITE_FILTER && originalData.ACL_mode != '2' ? false : _.contains(target.blackDevicesMac(), element_data.macAddress);

+                        element_data.hostName = stationUtil.getHostName(element_data.hostName, element_data.macAddress, hostNameList);

+                        element_data.disableFlag = (config.HAS_BLACK_AND_WHITE_FILTER && originalData.ACL_mode != '2') || element_data.inBlackGroup || editingHostname;

+                        return element_data;

+                    }));

+                if (_.isFunction(cb)) {

+                    cb.apply(this);

+                }

+            });

+        };

+        //获取RJ45已连接设备

+        target.fetchAttachedCableDevices = function (cb) {

+            service.getAttachedCableDevices({}, function (data) {

+                if (editingHostname) {

+                    return false;

+                }

+                target.cableDeviceInfo(_.map(data.attachedDevices, function (element_data, idx) {

+                        element_data.idx = _.uniqueId('cable_');

+                        element_data.hostName = stationUtil.getHostName(element_data.hostName, element_data.macAddress, hostNameList);

+                        element_data.type = 2;

+                        return element_data;

+                    }));

+                if (_.isFunction(cb)) {

+                    cb.apply(this);

+                }

+            });

+        };

+

+        target.fetchBlacklist = function (cb) {

+            service.getMacFilterInfo({}, function (data) {

+                originalData.ACL_mode = data.ACL_mode;

+                originalData.user_ip = data.user_ip_addr;

+                originalData.hostnameList = data.wifi_hostname_black_list;

+                originalData.macList = data.wifi_mac_black_list;

+                target.showBlackDiv(config.HAS_BLACK_AND_WHITE_FILTER ? (originalData.ACL_mode == '2' ? true : false) : config.STATION_BLOCK_SUPPORT);

+                var blackDevices = stationUtil.parseBlackString(data.wifi_mac_black_list, data.wifi_hostname_black_list);

+                target.blackDevices(_.map(blackDevices, function (element_data, idx) {

+                        element_data.idx = _.uniqueId('black_');

+                        element_data.type = 3;

+                        element_data.hostName = stationUtil.getHostName(element_data.hostName, element_data.macAddress, hostNameList);

+                        return element_data;

+                    }));

+                if (_.isFunction(cb)) {

+                    cb.apply(this);

+                }

+            }, $.noop);

+        };

+        target.fetchBlacklist();

+        target.fetchAttachedDevices();

+        if (target.showCableDiv) {

+            target.fetchAttachedCableDevices();

+        }

+

+        var editingHostname = 0;

+        addInterval(function () {

+            if (editingHostname == 0) {

+                target.fetchAttachedDevices();

+            }

+        }, 3000);

+

+        if (target.showCableDiv) {

+            addInterval(function () {

+                if (editingHostname == 0) {

+                    target.fetchAttachedCableDevices();

+                }

+            }, 5000);

+        }

+        //WiFi已连接设备列表中屏蔽按钮事件 入黑名单

+        target.wirelessBlockHandler = stationBlockEvent;

+        //保存主机名事件

+        target.saveHostNameHandler = saveHostNameEvent;

+        //主机名修改按钮点击事件

+        target.editHostNameHandler = function (element_data) {

+            editingHostname++;

+            $("#hostname_input_" + element_data.idx).val(element_data.hostName);

+            stationUtil.dealElement(true, element_data.idx);

+            return false;

+        };

+        //取消编辑主机名事件

+        target.cancelEditHostNameHandler = function (element_data) {

+            stationUtil.dealElement(false, element_data.idx);

+            editingHostname--;

+        };

+        target.cancelAllEditHostNameHandler = function () {

+            stationUtil.dealElement(false, "all");

+            editingHostname = 0;

+        };

+        //从黑名单列表中移除

+        target.blacklistRemoveHandler = function (element_data) {

+            if (originalData.macList.indexOf(element_data.macAddress) == -1) {

+                return false;

+            }

+            if (editingHostname) {

+                target.cancelAllEditHostNameHandler();

+            }

+            showLoading('waiting');

+            var macArr = [];

+            var hostnameArr = [];

+            $.each(target.blackDevices(), function (i, n) {

+                if (n.macAddress != element_data.macAddress) {

+                    macArr.push(n.macAddress);

+                    hostnameArr.push(n.hostName);

+                }

+            });

+            var params = {

+                ACL_mode: '2', //originalData.ACL_mode

+                macFilteringMode: '2', //originalData.ACL_mode

+                wifi_hostname_black_list: hostnameArr.join(';'),

+                wifi_mac_black_list: macArr.join(';')

+            };

+            target.updateMacFilterList(params);

+        };

+        target.updateMacFilterList = function (params) {

+            service.setMacFilter(params, function (data) {

+                if (data.result == "success") {

+                    target.blackDevices([]);

+                    target.fetchBlacklist(function () {

+                        target.fetchAttachedDevices(function () {

+                            successOverlay();

+                        });

+                    });

+                }

+            }, function () {

+                errorOverlay();

+            });

+        };

+

+        function saveHostNameEvent(element_data) {

+            var $input = $("#hostname_input_" + element_data.idx);

+            var newHostname = $input.val();

+            if (newHostname.indexOf(" ") == 0 || newHostname.lastIndexOf(" ") == (newHostname.length - 1) || /[\*\$\[&:,;<>'"\\`\]¥]{1,32}/.test(newHostname)) {

+                showAlert('device_rename');

+                return false;

+            } else if (newHostname == '') {

+                $(".promptErrorLabel", "#confirm-message-container").text($.i18n.prop("required"));

+                var $closestTD = $input.closest('td').addClass('has-error');

+                addTimeout(function () {

+                    $closestTD.removeClass('has-error');

+                }, 5000);

+                showAlert('required');

+                return false;

+            }

+            showLoading('waiting');

+            element_data.hostName = newHostname;

+            service.editHostName({

+                hostname: element_data.hostName,

+                mac: element_data.macAddress

+            }, function () {

+                editingHostname = 0;

+                service.getHostNameList({}, function (data) {

+                    hostNameList = data.devices;

+                    if (element_data.type == 3) {

+                        target.fetchBlacklist(function () {

+                            hideLoading();

+                            successOverlay();

+                        });

+                    } else if (element_data.type == 2) {

+                        target.fetchAttachedCableDevices(function () {

+                            hideLoading();

+                            successOverlay();

+                        });

+                    } else if (element_data.type == 1) {

+                        target.fetchAttachedDevices(function () {

+                            hideLoading();

+                            successOverlay();

+                        });

+                    }

+                });

+            }, function () {

+                errorOverlay();

+            });

+        }

+

+        function stationBlockEvent(element_data) {

+            if (config.HAS_BLACK_AND_WHITE_FILTER && originalData.ACL_mode != '2') {

+                return false;

+            }

+            if (originalData.macList.split(';').length == 10) {

+                showAlert('black_list_max');

+                return false;

+            }

+            if (originalData.macList.indexOf(element_data.macAddress) != -1) {

+                return false;

+            }

+            if (element_data.ipAddress == originalData.user_ip) {

+                showAlert('black_yourself_tip');

+                return false;

+            }

+            if (editingHostname) {

+                target.cancelAllEditHostNameHandler();

+            }

+            showLoading('waiting');

+            var newHostnameList = originalData.hostnameList == '' ? element_data.hostName : element_data.hostName + ';' + originalData.hostnameList;

+            var newMacList = originalData.macList == '' ? element_data.macAddress : element_data.macAddress + ';' + originalData.macList;

+            var params = {

+                ACL_mode: '2',

+                wifi_hostname_black_list: newHostnameList,

+                wifi_mac_black_list: newMacList

+            };

+            target.updateMacFilterList(params);

+        }

+

+    }

+

+    function bindContainer(ws_vm) {

+        var container = $('#container')[0];

+        ko.cleanNode(container);

+        ko.applyBindings(ws_vm, container);

+    }

+    function initialize() {

+        var ws_vm = new staInfoViewMode();

+        bindContainer(ws_vm);

+    }

+

+    return {

+        init: initialize

+    };

+});

+

+define("wifi_wps","underscore jquery knockout set service".split(" "),

+    function (_, $, ko, config, service) {

+

+    var viaWifi = false;

+

+    function WpsViewMode() {

+        var target = this;

+        target.hasMultiSSID = config.HAS_MULTI_SSID;

+        target.hasAPStation = config.AP_STATION_SUPPORT;

+        target.hasWifiSwitch = config.WIFI_SWITCH_SUPPORT;

+        target.hasWlanMacfilter = config.HAS_BLACK_AND_WHITE_FILTER;

+

+        target.wpsType = ko.observable('');

+        target.wpsPin = ko.observable('');

+

+        var state = getWpsState();

+        target.origin_ap_station_enable = state.ap_station_enable;

+

+        target.wpsFlag = ko.observable(state.wpsFlag);

+        target.authMode = ko.observable(state.authMode);

+

+        target.radioFlag = ko.observable(state.radioFlag);

+        target.encrypType = ko.observable(state.encrypType);

+

+        target.mulOption = ko.observable(paintSSIDOption(state));

+        target.wpsSSID = ko.observable(getSSIDCurrWps(state));

+

+        var infoBasic = service.getWifiBasic();

+        target.wifi_enable = ko.observable(infoBasic.wifi_enable);

+

+        target.isShowSSIDInfoDiv = ko.observable(false);

+        if (config.WIFI_SWITCH_SUPPORT) { //软开关

+            if (infoBasic.wifi_enable == "1") {

+                target.isShowSSIDInfoDiv(true);

+            } else {

+                target.isShowSSIDInfoDiv(false);

+            }

+        } else {

+            target.isShowSSIDInfoDiv(true);

+        }

+        target.multi_ssid_enable = ko.observable(infoBasic.multi_ssid_enable);

+        target.origin_multi_ssid_enable = infoBasic.multi_ssid_enable;

+

+        target.save = wpa_save;

+

+        if (state.wpsFlag != '0') {

+            target.wpsType(state.wpsType == 'PIN' ? 'PIN' : 'PBC');

+        } else {

+            target.wpsType('');

+        }

+

+        target.setMultiSSIDSwitch = function () {

+            if (target.checkSettings("switch")) {

+                return;

+            }

+

+            function wpsSetSwitch() {

+                showLoading('waiting');

+                var wps_param = {};

+                wps_param.m_ssid_enable = target.multi_ssid_enable();

+                if (config.WIFI_SWITCH_SUPPORT) {

+                    wps_param.wifiEnabled = target.wifi_enable();

+                }

+                service.setWifiBasicMultiSSIDSwitch(wps_param, function (result) {

+                    if (result.result == "success") {

+                        if (!viaWifi) {

+                            addInterval(wpsReload, 1000);

+                        } else {

+                            setTimeout(wpsReloadViaWifi, 15000);

+                        }

+                    } else {

+                        errorOverlay();

+                    }

+                });

+            }

+

+            var setSwitch = wpsSetSwitch;

+            var state = service.getStatusInfo();

+            if (target.wifi_enable() == "1" && config.HAS_MULTI_SSID) {

+                if (target.multi_ssid_enable() == "1" && config.AP_STATION_SUPPORT && target.origin_ap_station_enable == "1") {

+                    if (!state.wifiStatus) {

+                        showConfirm("multi_ssid_enable_confirm", function () {

+                            setSwitch();

+                        });

+                    } else {

+                        showConfirm("multi_ssid_enable_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                } else {

+                    if (!state.wifiStatus) {

+                        setSwitch();

+                    } else {

+                        showConfirm("wifi_disconnect_confirm2", function () {

+                            setSwitch();

+                        });

+                    }

+                }

+            } else {

+                setSwitch();

+            }

+

+            function wpsReload() {

+                var state = service.getWifiBasic();

+                if (state.wifi_enable == target.wifi_enable()) {

+                    successOverlay();

+                    clearTimer();

+                    clearValidateMsg();

+                    service.refreshAPStationStatus();

+                    initialize();

+                }

+            }

+            function wpsReloadViaWifi() {

+                successOverlay();

+                setTimeout(function () {

+                    window.location.reload();

+                }, 1000);

+                clearTimer();

+                clearValidateMsg();

+                service.refreshAPStationStatus();

+                initialize();

+            }

+

+        };

+

+        target.checkSettings = function (ssid) {

+            var state = getWpsState();

+            if (state.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+            return false;

+        };

+

+        function wpa_save() {

+            var state = getWpsState();

+

+            if (state.radioFlag == '0') {

+                showAlert('wps_wifi_off');

+                return;

+            }

+

+            if (state.wpsFlag == '1') {

+                showAlert('wps_on_info');

+                return true;

+            }

+

+            if (target.wpsSSID() == "SSID1") {

+                var res = (state.AuthMode == "OPEN" && state.encrypType == "WEP")

+                 || (state.AuthMode == "SHARED" && state.encrypType == "WEP")

+                 || (state.AuthMode == "WPAPSK" && state.encrypType == "TKIP")

+                 || (state.AuthMode == "WPAPSK" && state.encrypType == "TKIPCCMP")

+                 || (state.AuthMode == "WPAPSK" && state.encrypType == "AES")

+                 || (state.AuthMode == "WPA2PSK" && state.encrypType == "TKIP")

+                 || (state.AuthMode == "WPAPSKWPA2PSK" && state.encrypType == "TKIP")

+                 || (state.AuthMode == "WPA3Personal")

+                 || (state.AuthMode == "WPA2WPA3");

+                if (res) {

+                    showAlert('wps_auth_open');

+                    return;

+                }

+            } else {

+                var resm = (state.m_AuthMode == "OPEN" && state.m_encrypType == "WEP")

+                 || (state.m_AuthMode == "SHARED" && state.m_encrypType == "WEP")

+                 || (state.m_AuthMode == "WPAPSK" && state.m_encrypType == "TKIP")

+                 || (state.m_AuthMode == "WPAPSK" && state.m_encrypType == "TKIPCCMP")

+                 || (state.m_AuthMode == "WPAPSK" && state.m_encrypType == "AES")

+                 || (state.m_AuthMode == "WPA2PSK" && state.m_encrypType == "TKIP")

+                 || (state.m_AuthMode == "WPAPSKWPA2PSK" && state.m_encrypType == "TKIP")

+                 || (state.m_AuthMode == "WPA3Personal")

+                 || (state.m_AuthMode == "WPA2WPA3");

+                if (resm) {

+                    showAlert('wps_auth_open');

+                    return;

+                }

+            }

+

+            var wpsSSID;

+            var wpsIndex;

+            if (target.wpsSSID() != "SSID1") {

+                wpsSSID = state.multiSSID;

+                wpsIndex = 2;

+            } else {

+                wpsSSID = state.ssid;

+                wpsIndex = 1;

+            }

+

+            var basic = service.getWifiBasic();

+            if (wpsSSID == basic.m_SSID && wpsIndex == 2) {

+                if (basic.m_broadcast == '1') {

+                    showAlert('wps_ssid_broadcast_disable');

+                    return;

+                }

+            } else if (wpsSSID == basic.SSID && wpsIndex == 1) {

+                if (basic.broadcast == '1') {

+                    showAlert('wps_ssid_broadcast_disable');

+                    return;

+                }

+            }

+

+            showLoading('waiting');

+            var wps_param = {};

+            wps_param.wpsType = target.wpsType();

+            wps_param.wpsSSID = wpsSSID;

+            wps_param.wpsIndex = wpsIndex;

+            wps_param.wpsPin = getWpsPin(target.wpsPin());

+

+            service.openWps(wps_param, function (result) {

+                if (result.result != "success") {

+                    errorOverlay();

+                } else {

+                    target.wpsPin('');

+                    clearValidateMsg();

+                    successOverlay();

+                }

+            });

+        }

+

+    }

+

+    function getWpsPin(value) {

+        if (value.length != 9) {

+            return value;

+        } else {

+            return value.substring(0, 4) + value.substring(5);

+        }

+    }

+

+    function getWpsState() {

+        return service.getWpsInfo();

+    }

+

+    function paintSSIDOption(info) {

+        var show_opt = [];

+        show_opt.push(new Option(info.ssid, "SSID1"));

+        if (info.ssidEnable == "1") {

+            show_opt.push(new Option(info.multiSSID, "SSID2"));

+        }

+        return show_opt;

+    }

+

+    //检查当前是否通过wifi登录webui

+    function checkAccessMode() {

+        service.getParams({

+            nv: 'user_ip_addr'

+        }, function (dataIp) {

+            service.getParams({

+                nv: 'station_list'

+            }, function (dataList) {

+                viaWifi = isWifiConnected(dataIp.user_ip_addr, dataList.station_list);

+            });

+        });

+    }

+    function bindContainer(wpsVm) {

+        var container = $('#container');

+        ko.cleanNode(container[0]);

+        ko.applyBindings(wpsVm, container[0]);

+

+        addTimeout(function () {

+            checkAccessMode();

+        }, 600);

+

+        $('#wpsForm').validate({

+            submitHandler: function () {

+                wpsVm.save();

+            },

+            rules: {

+                txtPin: {

+                    "wps_pin_validator": true

+                }

+            }

+        });

+

+        $('#frmWifiSwitch').validate({

+            submitHandler: function () {

+                wpsVm.setMultiSSIDSwitch();

+            }

+        });

+    }

+    function getSSIDCurrWps(info) {

+        if (info.ssid != info.multiSSID) {

+            return info.wpsSSID == info.multiSSID ? "SSID2" : "SSID1";

+        } else {

+            if (info.wifi_wps_index == '2') {

+                return "SSID2";

+            } else {

+                return "SSID1";

+            }

+        }

+    }

+    //视图初始化

+    function initialize() {

+        var wpsVm = new WpsViewMode();

+        bindContainer(wpsVm);

+    }

+

+    return {

+        init: initialize

+    };

+});

+