[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_min/css/bt_strp.css b/ap/app/zte_webui_min/css/bt_strp.css
new file mode 100755
index 0000000..9bda516
--- /dev/null
+++ b/ap/app/zte_webui_min/css/bt_strp.css
@@ -0,0 +1,6196 @@
+html {
+  font-family: sans-serif;
+  -ms-text-size-adjust: 100%;
+  -webkit-text-size-adjust: 100%;
+}
+body {
+  margin: 0;
+}
+.progress {
+  overflow: hidden;
+  height: 20px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+.progress-bar {
+  float: left;
+  width: 0%;
+  height: 100%;
+  font-size: 12px;
+  line-height: 20px;
+  color: #ffffff;
+  text-align: center;
+  background-color: #428bca;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+  -webkit-transition: width 0.6s ease;
+  -o-transition: width 0.6s ease;
+  transition: width 0.6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+  -o-animation: progress-bar-stripes 2s linear infinite;
+  animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar[aria-valuenow="0"] {
+  color: #777777;
+  min-width: 30px;
+  background-color: transparent;
+  background-image: none;
+  box-shadow: none;
+}
+.progress-bar-success {
+  background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+  background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+  background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+  background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+
+* {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+html {
+  font-size: 10px;
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #333333;
+  background-color: #ffffff;
+}
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+a {
+  color: #428bca;
+  text-decoration: none;
+}
+a:hover,
+a:focus {
+  color: #2a6496;
+  text-decoration: underline;
+}
+a:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+figure {
+  margin: 0;
+}
+img {
+  vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  display: block;
+  width: 100% \9;
+  max-width: 100%;
+  height: auto;
+}
+.img-rounded {
+  border-radius: 6px;
+}
+.img-thumbnail {
+  padding: 4px;
+  line-height: 1.42857143;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+  border-radius: 4px;
+  -webkit-transition: all 0.2s ease-in-out;
+  -o-transition: all 0.2s ease-in-out;
+  transition: all 0.2s ease-in-out;
+  display: inline-block;
+  width: 100% \9;
+  max-width: 100%;
+  height: auto;
+}
+.img-circle {
+  border-radius: 50%;
+}
+hr {
+  margin-top: 20px;
+  margin-bottom: 20px;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+}
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  margin: -1px;
+  padding: 0;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+  font-weight: normal;
+  line-height: 1;
+  color: #777777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+  margin-top: 20px;
+  margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+  font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+  font-size: 75%;
+}
+h1,
+.h1 {
+  font-size: 36px;
+}
+h2,
+.h2 {
+  font-size: 30px;
+}
+h3,
+.h3 {
+  font-size: 24px;
+}
+h4,
+.h4 {
+  font-size: 18px;
+}
+h5,
+.h5 {
+  font-size: 14px;
+}
+h6,
+.h6 {
+  font-size: 12px;
+}
+p {
+  margin: 0 0 10px;
+}
+.lead {
+  margin-bottom: 20px;
+  font-size: 16px;
+  font-weight: 300;
+  line-height: 1.4;
+}
+@media (min-width: 768px) {
+  .lead {
+    font-size: 21px;
+  }
+}
+small,
+.small {
+  font-size: 85%;
+}
+mark,
+.mark {
+  background-color: #fcf8e3;
+  padding: .2em;
+}
+.text-left {
+  text-align: left;
+}
+.text-right {
+  text-align: right;
+}
+.text-center {
+  text-align: center;
+}
+.text-justify {
+  text-align: justify;
+}
+.text-nowrap {
+  white-space: nowrap;
+}
+.text-lowercase {
+  text-transform: lowercase;
+}
+.text-uppercase {
+  text-transform: uppercase;
+}
+.text-capitalize {
+  text-transform: capitalize;
+}
+.text-muted {
+  color: #777777;
+}
+.text-primary {
+  color: #428bca;
+}
+a.text-primary:hover {
+  color: #3071a9;
+}
+.text-success {
+  color: #3c763d;
+}
+a.text-success:hover {
+  color: #2b542c;
+}
+.text-info {
+  color: #31708f;
+}
+a.text-info:hover {
+  color: #245269;
+}
+.text-warning {
+  color: #8a6d3b;
+}
+a.text-warning:hover {
+  color: #66512c;
+}
+.text-danger {
+  color: #a94442;
+}
+a.text-danger:hover {
+  color: #843534;
+}
+.bg-primary {
+  color: #fff;
+  background-color: #428bca;
+}
+a.bg-primary:hover {
+  background-color: #3071a9;
+}
+.bg-success {
+  background-color: #dff0d8;
+}
+a.bg-success:hover {
+  background-color: #c1e2b3;
+}
+.bg-info {
+  background-color: #d9edf7;
+}
+a.bg-info:hover {
+  background-color: #afd9ee;
+}
+.bg-warning {
+  background-color: #fcf8e3;
+}
+a.bg-warning:hover {
+  background-color: #f7ecb5;
+}
+.bg-danger {
+  background-color: #f2dede;
+}
+a.bg-danger:hover {
+  background-color: #e4b9b9;
+}
+.page-header {
+  padding-bottom: 9px;
+  margin: 40px 0 20px;
+  border-bottom: 1px solid #eeeeee;
+}
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+  margin-bottom: 0;
+}
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
+.list-inline {
+  padding-left: 0;
+  list-style: none;
+  margin-left: -5px;
+}
+.list-inline > li {
+  display: inline-block;
+  padding-left: 5px;
+  padding-right: 5px;
+}
+dl {
+  margin-top: 0;
+  margin-bottom: 20px;
+}
+dt,
+dd {
+  line-height: 1.42857143;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: 0;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #c7254e;
+  background-color: #f9f2f4;
+  border-radius: 4px;
+}
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #ffffff;
+  background-color: #333333;
+  border-radius: 3px;
+  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+kbd kbd {
+  padding: 0;
+  font-size: 100%;
+  box-shadow: none;
+}
+pre {
+  display: block;
+  padding: 9.5px;
+  margin: 0 0 10px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  word-break: break-all;
+  word-wrap: break-word;
+  color: #333333;
+  background-color: #f5f5f5;
+  border: 1px solid #cccccc;
+  border-radius: 4px;
+  word-break: keep-all;
+  word-wrap: normal;
+}
+pre code {
+  padding: 0;
+  font-size: inherit;
+  color: inherit;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border-radius: 0;
+}
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+.container {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 15px;
+  padding-right: 15px;
+}
+
+@media (min-width: 768px) {
+  .dl-horizontal dt {
+    float: left;
+    width: 160px;
+    clear: left;
+    text-align: right;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .dl-horizontal dd {
+    margin-left: 180px;
+  }
+}
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #777777;
+}
+.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+blockquote {
+  padding: 10px 20px;
+  margin: 0 0 20px;
+  font-size: 17.5px;
+  border-left: 5px solid #eeeeee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+  margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+  display: block;
+  font-size: 80%;
+  line-height: 1.42857143;
+  color: #777777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+  content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  border-right: 5px solid #eeeeee;
+  border-left: 0;
+  text-align: right;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+  content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+  content: '\00A0 \2014';
+}
+blockquote:before,
+blockquote:after {
+  content: "";
+}
+address {
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 1.42857143;
+}
+
+@media (min-width: 768px) {
+  .container {
+    width: 750px;
+  }
+}
+@media (min-width: 992px) {
+  .container {
+    width: 970px;
+  }
+}
+@media (min-width: 1200px) {
+  .container {
+    width: 1170px;
+  }
+}
+.container-fluid {
+  margin-right: auto;
+  margin-left: auto;
+  padding-left: 15px;
+  padding-right: 15px;
+}
+.row {
+  margin-left: -15px;
+  margin-right: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {
+  position: relative;
+  min-height: 1px;
+  padding-left: 15px;
+  padding-right: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+  float: left;
+}
+.col-xs-12 {
+  width: 100%;
+}
+.col-xs-11 {
+  width: 91.66666667%;
+}
+.col-xs-10 {
+  width: 83.33333333%;
+}
+.col-xs-9 {
+  width: 75%;
+}
+.col-xs-8 {
+  width: 66.66666667%;
+}
+.col-xs-7 {
+  width: 58.33333333%;
+}
+.col-xs-6 {
+  width: 50%;
+}
+.col-xs-5 {
+  width: 41.66666667%;
+}
+.col-xs-4 {
+  width: 33.33333333%;
+}
+.col-xs-3 {
+  width: 25%;
+}
+.col-xs-2 {
+  width: 16.66666667%;
+}
+.col-xs-1 {
+  width: 8.33333333%;
+}
+.col-xs-pull-12 {
+  right: 100%;
+}
+.col-xs-pull-11 {
+  right: 91.66666667%;
+}
+.col-xs-pull-10 {
+  right: 83.33333333%;
+}
+.col-xs-pull-9 {
+  right: 75%;
+}
+.col-xs-pull-8 {
+  right: 66.66666667%;
+}
+.col-xs-pull-7 {
+  right: 58.33333333%;
+}
+.col-xs-pull-6 {
+  right: 50%;
+}
+.col-xs-pull-5 {
+  right: 41.66666667%;
+}
+.col-xs-pull-4 {
+  right: 33.33333333%;
+}
+.col-xs-pull-3 {
+  right: 25%;
+}
+.col-xs-pull-2 {
+  right: 16.66666667%;
+}
+.col-xs-pull-1 {
+  right: 8.33333333%;
+}
+.col-xs-pull-0 {
+  right: auto;
+}
+.col-xs-push-12 {
+  left: 100%;
+}
+.col-xs-push-11 {
+  left: 91.66666667%;
+}
+.col-xs-push-10 {
+  left: 83.33333333%;
+}
+.col-xs-push-9 {
+  left: 75%;
+}
+.col-xs-push-8 {
+  left: 66.66666667%;
+}
+.col-xs-push-7 {
+  left: 58.33333333%;
+}
+.col-xs-push-6 {
+  left: 50%;
+}
+.col-xs-push-5 {
+  left: 41.66666667%;
+}
+.col-xs-push-4 {
+  left: 33.33333333%;
+}
+.col-xs-push-3 {
+  left: 25%;
+}
+.col-xs-push-2 {
+  left: 16.66666667%;
+}
+.col-xs-push-1 {
+  left: 8.33333333%;
+}
+.col-xs-push-0 {
+  left: auto;
+}
+.col-xs-offset-12 {
+  margin-left: 100%;
+}
+.col-xs-offset-11 {
+  margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+  margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+  margin-left: 75%;
+}
+.col-xs-offset-8 {
+  margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+  margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+  margin-left: 50%;
+}
+.col-xs-offset-5 {
+  margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+  margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+  margin-left: 25%;
+}
+.col-xs-offset-2 {
+  margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+  margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+  margin-left: 0%;
+}
+
+@media (min-width: 1200px) {
+  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+    float: left;
+  }
+  .col-lg-12 {
+    width: 100%;
+  }
+  .col-lg-11 {
+    width: 91.66666667%;
+  }
+  .col-lg-10 {
+    width: 83.33333333%;
+  }
+  .col-lg-9 {
+    width: 75%;
+  }
+  .col-lg-8 {
+    width: 66.66666667%;
+  }
+  .col-lg-7 {
+    width: 58.33333333%;
+  }
+  .col-lg-6 {
+    width: 50%;
+  }
+  .col-lg-5 {
+    width: 41.66666667%;
+  }
+  .col-lg-4 {
+    width: 33.33333333%;
+  }
+  .col-lg-3 {
+    width: 25%;
+  }
+  .col-lg-2 {
+    width: 16.66666667%;
+  }
+  .col-lg-1 {
+    width: 8.33333333%;
+  }
+  .col-lg-pull-12 {
+    right: 100%;
+  }
+  .col-lg-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-lg-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-lg-pull-9 {
+    right: 75%;
+  }
+  .col-lg-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-lg-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-lg-pull-6 {
+    right: 50%;
+  }
+  .col-lg-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-lg-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-lg-pull-3 {
+    right: 25%;
+  }
+  .col-lg-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-lg-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-lg-pull-0 {
+    right: auto;
+  }
+  .col-lg-push-12 {
+    left: 100%;
+  }
+  .col-lg-push-11 {
+    left: 91.66666667%;
+  }
+  .col-lg-push-10 {
+    left: 83.33333333%;
+  }
+  .col-lg-push-9 {
+    left: 75%;
+  }
+  .col-lg-push-8 {
+    left: 66.66666667%;
+  }
+  .col-lg-push-7 {
+    left: 58.33333333%;
+  }
+  .col-lg-push-6 {
+    left: 50%;
+  }
+  .col-lg-push-5 {
+    left: 41.66666667%;
+  }
+  .col-lg-push-4 {
+    left: 33.33333333%;
+  }
+  .col-lg-push-3 {
+    left: 25%;
+  }
+  .col-lg-push-2 {
+    left: 16.66666667%;
+  }
+  .col-lg-push-1 {
+    left: 8.33333333%;
+  }
+  .col-lg-push-0 {
+    left: auto;
+  }
+  .col-lg-offset-12 {
+    margin-left: 100%;
+  }
+  .col-lg-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-lg-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-lg-offset-9 {
+    margin-left: 75%;
+  }
+  .col-lg-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-lg-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-lg-offset-6 {
+    margin-left: 50%;
+  }
+  .col-lg-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-lg-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-lg-offset-3 {
+    margin-left: 25%;
+  }
+  .col-lg-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-lg-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-lg-offset-0 {
+    margin-left: 0%;
+  }
+}
+
+@media (min-width: 768px) {
+  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+    float: left;
+  }
+  .col-sm-12 {
+    width: 100%;
+  }
+  .col-sm-11 {
+    width: 91.66666667%;
+  }
+  .col-sm-10 {
+    width: 83.33333333%;
+  }
+  .col-sm-9 {
+    width: 75%;
+  }
+  .col-sm-8 {
+    width: 66.66666667%;
+  }
+  .col-sm-7 {
+    width: 58.33333333%;
+  }
+  .col-sm-6 {
+    width: 50%;
+  }
+  .col-sm-5 {
+    width: 41.66666667%;
+  }
+  .col-sm-4 {
+    width: 33.33333333%;
+  }
+  .col-sm-3 {
+    width: 25%;
+  }
+  .col-sm-2 {
+    width: 16.66666667%;
+  }
+  .col-sm-1 {
+    width: 8.33333333%;
+  }
+  .col-sm-pull-12 {
+    right: 100%;
+  }
+  .col-sm-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-sm-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-sm-pull-9 {
+    right: 75%;
+  }
+  .col-sm-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-sm-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-sm-pull-6 {
+    right: 50%;
+  }
+  .col-sm-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-sm-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-sm-pull-3 {
+    right: 25%;
+  }
+  .col-sm-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-sm-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-sm-pull-0 {
+    right: auto;
+  }
+  .col-sm-push-12 {
+    left: 100%;
+  }
+  .col-sm-push-11 {
+    left: 91.66666667%;
+  }
+  .col-sm-push-10 {
+    left: 83.33333333%;
+  }
+  .col-sm-push-9 {
+    left: 75%;
+  }
+  .col-sm-push-8 {
+    left: 66.66666667%;
+  }
+  .col-sm-push-7 {
+    left: 58.33333333%;
+  }
+  .col-sm-push-6 {
+    left: 50%;
+  }
+  .col-sm-push-5 {
+    left: 41.66666667%;
+  }
+  .col-sm-push-4 {
+    left: 33.33333333%;
+  }
+  .col-sm-push-3 {
+    left: 25%;
+  }
+  .col-sm-push-2 {
+    left: 16.66666667%;
+  }
+  .col-sm-push-1 {
+    left: 8.33333333%;
+  }
+  .col-sm-push-0 {
+    left: auto;
+  }
+  .col-sm-offset-12 {
+    margin-left: 100%;
+  }
+  .col-sm-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-sm-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-sm-offset-9 {
+    margin-left: 75%;
+  }
+  .col-sm-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-sm-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-sm-offset-6 {
+    margin-left: 50%;
+  }
+  .col-sm-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-sm-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-sm-offset-3 {
+    margin-left: 25%;
+  }
+  .col-sm-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-sm-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-sm-offset-0 {
+    margin-left: 0%;
+  }
+}
+@media (min-width: 992px) {
+  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+    float: left;
+  }
+  .col-md-12 {
+    width: 100%;
+  }
+  .col-md-11 {
+    width: 91.66666667%;
+  }
+  .col-md-10 {
+    width: 83.33333333%;
+  }
+  .col-md-9 {
+    width: 75%;
+  }
+  .col-md-8 {
+    width: 66.66666667%;
+  }
+  .col-md-7 {
+    width: 58.33333333%;
+  }
+  .col-md-6 {
+    width: 50%;
+  }
+  .col-md-5 {
+    width: 41.66666667%;
+  }
+  .col-md-4 {
+    width: 33.33333333%;
+  }
+  .col-md-3 {
+    width: 25%;
+  }
+  .col-md-2 {
+    width: 16.66666667%;
+  }
+  .col-md-1 {
+    width: 8.33333333%;
+  }
+  .col-md-pull-12 {
+    right: 100%;
+  }
+  .col-md-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-md-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-md-pull-9 {
+    right: 75%;
+  }
+  .col-md-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-md-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-md-pull-6 {
+    right: 50%;
+  }
+  .col-md-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-md-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-md-pull-3 {
+    right: 25%;
+  }
+  .col-md-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-md-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-md-pull-0 {
+    right: auto;
+  }
+  .col-md-push-12 {
+    left: 100%;
+  }
+  .col-md-push-11 {
+    left: 91.66666667%;
+  }
+  .col-md-push-10 {
+    left: 83.33333333%;
+  }
+  .col-md-push-9 {
+    left: 75%;
+  }
+  .col-md-push-8 {
+    left: 66.66666667%;
+  }
+  .col-md-push-7 {
+    left: 58.33333333%;
+  }
+  .col-md-push-6 {
+    left: 50%;
+  }
+  .col-md-push-5 {
+    left: 41.66666667%;
+  }
+  .col-md-push-4 {
+    left: 33.33333333%;
+  }
+  .col-md-push-3 {
+    left: 25%;
+  }
+  .col-md-push-2 {
+    left: 16.66666667%;
+  }
+  .col-md-push-1 {
+    left: 8.33333333%;
+  }
+  .col-md-push-0 {
+    left: auto;
+  }
+  .col-md-offset-12 {
+    margin-left: 100%;
+  }
+  .col-md-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-md-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-md-offset-9 {
+    margin-left: 75%;
+  }
+  .col-md-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-md-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-md-offset-6 {
+    margin-left: 50%;
+  }
+  .col-md-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-md-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-md-offset-3 {
+    margin-left: 25%;
+  }
+  .col-md-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-md-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-md-offset-0 {
+    margin-left: 0%;
+  }
+}
+
+table {
+  background-color: transparent;
+}
+th {
+  text-align: left;
+}
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+  padding: 8px;
+  line-height: 1.42857143;
+  vertical-align: top;
+  border-top: 1px solid #dddddd;
+}
+.table > thead > tr > th {
+  vertical-align: bottom;
+  border-bottom: 2px solid #dddddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+  border-top: 0;
+}
+.table > tbody + tbody {
+  border-top: 2px solid #dddddd;
+}
+.table .table {
+  background-color: #ffffff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+  padding: 5px;
+}
+.table-bordered {
+  border: 1px solid #dddddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+  border: 1px solid #dddddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+  border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-child(odd) {
+  background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+  background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-column;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+  position: static;
+  float: none;
+  display: table-cell;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+  background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+  background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+  background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+  background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+  background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+  background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+  background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+  background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+  background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+  background-color: #ebcccc;
+}
+@media screen and (max-width: 767px) {
+  .table-responsive {
+    width: 100%;
+    margin-bottom: 15px;
+    overflow-y: hidden;
+    overflow-x: auto;
+    -ms-overflow-style: -ms-autohiding-scrollbar;
+    border: 1px solid #dddddd;
+    -webkit-overflow-scrolling: touch;
+  }
+  .table-responsive > .table {
+    margin-bottom: 0;
+  }
+  .table-responsive > .table > thead > tr > th,
+  .table-responsive > .table > tbody > tr > th,
+  .table-responsive > .table > tfoot > tr > th,
+  .table-responsive > .table > thead > tr > td,
+  .table-responsive > .table > tbody > tr > td,
+  .table-responsive > .table > tfoot > tr > td {
+    white-space: nowrap;
+  }
+  .table-responsive > .table-bordered {
+    border: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:first-child,
+  .table-responsive > .table-bordered > tbody > tr > th:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+  .table-responsive > .table-bordered > thead > tr > td:first-child,
+  .table-responsive > .table-bordered > tbody > tr > td:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+    border-left: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:last-child,
+  .table-responsive > .table-bordered > tbody > tr > th:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+  .table-responsive > .table-bordered > thead > tr > td:last-child,
+  .table-responsive > .table-bordered > tbody > tr > td:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+    border-right: 0;
+  }
+  .table-responsive > .table-bordered > tbody > tr:last-child > th,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+  .table-responsive > .table-bordered > tbody > tr:last-child > td,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+    border-bottom: 0;
+  }
+}
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+  min-width: 0;
+}
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 20px;
+  font-size: 21px;
+  line-height: inherit;
+  color: #333333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+label {
+  display: inline-block;
+  max-width: 100%;
+  margin-bottom: 5px;
+  font-weight: bold;
+}
+input[type="search"] {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  line-height: normal;
+}
+input[type="file"] {
+  display: block;
+}
+input[type="range"] {
+  display: block;
+  width: 100%;
+}
+select[multiple],
+select[size] {
+  height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+output {
+  display: block;
+  padding-top: 7px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555555;
+}
+.form-control {
+  display: block;
+  width: 100%;
+  height: 34px;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555555;
+  background-color: #ffffff;
+  background-image: none;
+  border: 1px solid #cccccc;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+.form-control::-moz-placeholder {
+  color: #777777;
+  opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+  color: #777777;
+}
+.form-control::-webkit-input-placeholder {
+  color: #777777;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+  cursor: not-allowed;
+  background-color: #eeeeee;
+  opacity: 1;
+}
+textarea.form-control {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: none;
+}
+input[type="date"],
+input[type="time"],
+input[type="datetime-local"],
+input[type="month"] {
+  line-height: 34px;
+  line-height: 1.42857143 \0;
+}
+input[type="date"].input-sm,
+input[type="time"].input-sm,
+input[type="datetime-local"].input-sm,
+input[type="month"].input-sm {
+  line-height: 30px;
+}
+input[type="date"].input-lg,
+input[type="time"].input-lg,
+input[type="datetime-local"].input-lg,
+input[type="month"].input-lg {
+  line-height: 46px;
+}
+.form-group {
+  margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+  min-height: 20px;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-left: -20px;
+  margin-top: 4px \9;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  vertical-align: middle;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+  cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+  cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+  cursor: not-allowed;
+}
+.form-control-static {
+  padding-top: 7px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+  padding-left: 0;
+  padding-right: 0;
+}
+.input-sm,
+.form-group-sm .form-control {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-sm,
+select.form-group-sm .form-control {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-sm,
+textarea.form-group-sm .form-control,
+select[multiple].input-sm,
+select[multiple].form-group-sm .form-control {
+  height: auto;
+}
+.input-lg,
+.form-group-lg .form-control {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+select.input-lg,
+select.form-group-lg .form-control {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-lg,
+textarea.form-group-lg .form-control,
+select[multiple].input-lg,
+select[multiple].form-group-lg .form-control {
+  height: auto;
+}
+.has-feedback {
+  position: relative;
+}
+.has-feedback .form-control {
+  padding-right: 42.5px;
+}
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 34px;
+  height: 34px;
+  line-height: 34px;
+  text-align: center;
+}
+.input-lg + .form-control-feedback {
+  width: 46px;
+  height: 46px;
+  line-height: 46px;
+}
+.input-sm + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+  color: #3c763d;
+}
+.has-success .form-control {
+  border-color: #3c763d;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-success .form-control:focus {
+  border-color: #2b542c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+  color: #3c763d;
+  border-color: #3c763d;
+  background-color: #dff0d8;
+}
+.has-success .form-control-feedback {
+  color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+  color: #8a6d3b;
+}
+.has-warning .form-control {
+  border-color: #8a6d3b;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-warning .form-control:focus {
+  border-color: #66512c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+  color: #8a6d3b;
+  border-color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+.has-warning .form-control-feedback {
+  color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+  color: #a94442;
+}
+.has-error .form-control {
+  border-color: #a94442;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+.has-error .form-control:focus {
+  border-color: #843534;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+  color: #a94442;
+  border-color: #a94442;
+  background-color: #f2dede;
+}
+.has-error .form-control-feedback {
+  color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+  top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+  top: 0;
+}
+.help-block {
+  display: block;
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: #737373;
+}
+@media (min-width: 768px) {
+  .form-inline .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .form-inline .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .form-inline .input-group .input-group-addon,
+  .form-inline .input-group .input-group-btn,
+  .form-inline .input-group .form-control {
+    width: auto;
+  }
+  .form-inline .input-group > .form-control {
+    width: 100%;
+  }
+  .form-inline .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio,
+  .form-inline .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio label,
+  .form-inline .checkbox label {
+    padding-left: 0;
+  }
+  .form-inline .radio input[type="radio"],
+  .form-inline .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .form-inline .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+  margin-top: 0;
+  margin-bottom: 0;
+  padding-top: 7px;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+  min-height: 27px;
+}
+.form-horizontal .form-group {
+  margin-left: -15px;
+  margin-right: -15px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .control-label {
+    text-align: right;
+    margin-bottom: 0;
+    padding-top: 7px;
+  }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 15px;
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-lg .control-label {
+    padding-top: 14.3px;
+  }
+}
+@media (min-width: 768px) {
+  .form-horizontal .form-group-sm .control-label {
+    padding-top: 6px;
+  }
+}
+
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%;
+}
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity 0.15s linear;
+  -o-transition: opacity 0.15s linear;
+  transition: opacity 0.15s linear;
+}
+.fade.in {
+  opacity: 1;
+}
+.collapse {
+  display: none;
+}
+.collapse.in {
+  display: block;
+}
+tr.collapse.in {
+  display: table-row;
+}
+tbody.collapse.in {
+  display: table-row-group;
+}
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition: height 0.35s ease;
+  -o-transition: height 0.35s ease;
+  transition: height 0.35s ease;
+}
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top: 4px solid;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+}
+.dropdown {
+  position: relative;
+}
+.dropdown-toggle:focus {
+  outline: 0;
+}
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  list-style: none;
+  font-size: 14px;
+  text-align: left;
+  background-color: #ffffff;
+  border: 1px solid #cccccc;
+  border: 1px solid rgba(0, 0, 0, 0.15);
+  border-radius: 4px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+  background-clip: padding-box;
+}
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu .divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.42857143;
+  color: #333333;
+  white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  text-decoration: none;
+  color: #262626;
+  background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: #ffffff;
+  text-decoration: none;
+  outline: 0;
+  background-color: #428bca;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: #777777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  cursor: not-allowed;
+}
+.open > .dropdown-menu {
+  display: block;
+}
+.open > a {
+  outline: 0;
+}
+.dropdown-menu-right {
+  left: auto;
+  right: 0;
+}
+.dropdown-menu-left {
+  left: 0;
+  right: auto;
+}
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  color: #777777;
+  white-space: nowrap;
+}
+.dropdown-backdrop {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  top: 0;
+  z-index: 990;
+}
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  border-top: 0;
+  border-bottom: 4px solid;
+  content: "";
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 1px;
+}
+@media (min-width: 768px) {
+  .navbar-right .dropdown-menu {
+    left: auto;
+    right: 0;
+  }
+  .navbar-right .dropdown-menu-left {
+    left: 0;
+    right: auto;
+  }
+}
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+  position: relative;
+  float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+  z-index: 2;
+}
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus {
+  outline: 0;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+  margin-left: -1px;
+}
+.btn-toolbar {
+  margin-left: -5px;
+}
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+  float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+  margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+.btn-group > .btn:first-child {
+  margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group > .btn-group {
+  float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group > .btn-group:first-child > .btn:last-child,
+.btn-group > .btn-group:first-child > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group > .btn-group:last-child > .btn:first-child {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+  padding-left: 8px;
+  padding-right: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+  padding-left: 12px;
+  padding-right: 12px;
+}
+.btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.btn .caret {
+  margin-left: 0;
+}
+.btn-lg .caret {
+  border-width: 5px 5px 0;
+  border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+  border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+  display: block;
+  float: none;
+  width: 100%;
+  max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+  float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+  margin-top: -1px;
+  margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+  border-bottom-left-radius: 4px;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+  float: none;
+  display: table-cell;
+  width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+  width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+  left: auto;
+}
+[data-toggle="buttons"] > .btn > input[type="radio"],
+[data-toggle="buttons"] > .btn > input[type="checkbox"] {
+  position: absolute;
+  z-index: -1;
+  opacity: 0;
+  filter: alpha(opacity=0);
+}
+.input-group {
+  position: relative;
+  display: table;
+  border-collapse: separate;
+}
+.input-group[class*="col-"] {
+  float: none;
+  padding-left: 0;
+  padding-right: 0;
+}
+.input-group .form-control {
+  position: relative;
+  z-index: 2;
+  float: left;
+  width: 100%;
+  margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+.input-group-addon {
+  padding: 6px 12px;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1;
+  color: #555555;
+  text-align: center;
+  background-color: #eeeeee;
+  border: 1px solid #cccccc;
+  border-radius: 4px;
+}
+.input-group-addon.input-sm {
+  padding: 5px 10px;
+  font-size: 12px;
+  border-radius: 3px;
+}
+.input-group-addon.input-lg {
+  padding: 10px 16px;
+  font-size: 18px;
+  border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+  margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-bottom-right-radius: 0;
+  border-top-right-radius: 0;
+}
+.input-group-addon:first-child {
+  border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-bottom-left-radius: 0;
+  border-top-left-radius: 0;
+}
+.input-group-addon:last-child {
+  border-left: 0;
+}
+.input-group-btn {
+  position: relative;
+  font-size: 0;
+  white-space: nowrap;
+}
+.input-group-btn > .btn {
+  position: relative;
+}
+.input-group-btn > .btn + .btn {
+  margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+  z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+  margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+  margin-left: -1px;
+}
+.nav {
+  margin-bottom: 0;
+  padding-left: 0;
+  list-style: none;
+}
+.nav > li {
+  position: relative;
+  display: block;
+}
+.nav > li > a {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+.nav > li.disabled > a {
+  color: #777777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+  color: #777777;
+  text-decoration: none;
+  background-color: transparent;
+  cursor: not-allowed;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+  background-color: #eeeeee;
+  border-color: #428bca;
+}
+.nav .nav-divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.nav > li > a > img {
+  max-width: none;
+}
+.nav-tabs {
+  border-bottom: 1px solid #dddddd;
+}
+.nav-tabs > li {
+  float: left;
+  margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+  margin-right: 2px;
+  line-height: 1.42857143;
+  border: 1px solid transparent;
+  border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+  border-color: #eeeeee #eeeeee #dddddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+  color: #555555;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+  border-bottom-color: transparent;
+  cursor: default;
+}
+.nav-tabs.nav-justified {
+  width: 100%;
+  border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+  float: none;
+}
+.nav-tabs.nav-justified > li > a {
+  text-align: center;
+  margin-bottom: 5px;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-tabs.nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs.nav-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+  border: 1px solid #dddddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs.nav-justified > li > a {
+    border-bottom: 1px solid #dddddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs.nav-justified > .active > a,
+  .nav-tabs.nav-justified > .active > a:hover,
+  .nav-tabs.nav-justified > .active > a:focus {
+    border-bottom-color: #ffffff;
+  }
+}
+.nav-pills > li {
+  float: left;
+}
+.nav-pills > li > a {
+  border-radius: 4px;
+}
+.nav-pills > li + li {
+  margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+  color: #ffffff;
+  background-color: #428bca;
+}
+.nav-stacked > li {
+  float: none;
+}
+.nav-stacked > li + li {
+  margin-top: 2px;
+  margin-left: 0;
+}
+.nav-justified {
+  width: 100%;
+}
+.nav-justified > li {
+  float: none;
+}
+.nav-justified > li > a {
+  text-align: center;
+  margin-bottom: 5px;
+}
+.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+@media (min-width: 768px) {
+  .nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs-justified {
+  border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+  border: 1px solid #dddddd;
+}
+@media (min-width: 768px) {
+  .nav-tabs-justified > li > a {
+    border-bottom: 1px solid #dddddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs-justified > .active > a,
+  .nav-tabs-justified > .active > a:hover,
+  .nav-tabs-justified > .active > a:focus {
+    border-bottom-color: #ffffff;
+  }
+}
+.tab-content > .tab-pane {
+  display: none;
+}
+.tab-content > .active {
+  display: block;
+}
+.nav-tabs .dropdown-menu {
+  margin-top: -1px;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.navbar {
+  position: relative;
+  min-height: 50px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+}
+@media (min-width: 768px) {
+  .navbar {
+    border-radius: 4px;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-header {
+    float: left;
+  }
+}
+.navbar-collapse {
+  overflow-x: visible;
+  padding-right: 15px;
+  padding-left: 15px;
+  border-top: 1px solid transparent;
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
+  -webkit-overflow-scrolling: touch;
+}
+.navbar-collapse.in {
+  overflow-y: auto;
+}
+@media (min-width: 768px) {
+  .navbar-collapse {
+    width: auto;
+    border-top: 0;
+    box-shadow: none;
+  }
+  .navbar-collapse.collapse {
+    display: block !important;
+    height: auto !important;
+    padding-bottom: 0;
+    overflow: visible !important;
+  }
+  .navbar-collapse.in {
+    overflow-y: visible;
+  }
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-static-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    padding-left: 0;
+    padding-right: 0;
+  }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+  max-height: 340px;
+}
+@media (max-device-width: 480px) and (orientation: landscape) {
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    max-height: 200px;
+  }
+}
+
+
+.tooltip {
+  position: absolute;
+  z-index: 1070;
+  display: block;
+  visibility: visible;
+  font-size: 12px;
+  line-height: 1.4;
+  opacity: 0;
+  filter: alpha(opacity=0);
+}
+.tooltip.in {
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+.tooltip.top {
+  margin-top: -3px;
+  padding: 5px 0;
+}
+.tooltip.right {
+  margin-left: 3px;
+  padding: 0 5px;
+}
+.tooltip.bottom {
+  margin-top: 3px;
+  padding: 5px 0;
+}
+.tooltip.left {
+  margin-left: -3px;
+  padding: 0 5px;
+}
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #ffffff;
+  text-align: center;
+  text-decoration: none;
+  background-color: #000000;
+  border-radius: 4px;
+}
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000000;
+}
+.tooltip.top-left .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000000;
+}
+.tooltip.top-right .tooltip-arrow {
+  bottom: 0;
+  right: 5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000000;
+}
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000000;
+}
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000000;
+}
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000000;
+}
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  text-align: left;
+  background-color: #ffffff;
+  background-clip: padding-box;
+  border: 1px solid #cccccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+  white-space: normal;
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  margin: 0;
+  padding: 8px 14px;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 18px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 5px 5px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover > .arrow {
+  border-width: 11px;
+}
+.popover > .arrow:after {
+  border-width: 10px;
+  content: "";
+}
+.popover.top > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-bottom-width: 0;
+  border-top-color: #999999;
+  border-top-color: rgba(0, 0, 0, 0.25);
+  bottom: -11px;
+}
+.popover.top > .arrow:after {
+  content: " ";
+  bottom: 1px;
+  margin-left: -10px;
+  border-bottom-width: 0;
+  border-top-color: #ffffff;
+}
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-left-width: 0;
+  border-right-color: #999999;
+  border-right-color: rgba(0, 0, 0, 0.25);
+}
+.popover.right > .arrow:after {
+  content: " ";
+  left: 1px;
+  bottom: -10px;
+  border-left-width: 0;
+  border-right-color: #ffffff;
+}
+.popover.bottom > .arrow {
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999999;
+  border-bottom-color: rgba(0, 0, 0, 0.25);
+  top: -11px;
+}
+.popover.bottom > .arrow:after {
+  content: " ";
+  top: 1px;
+  margin-left: -10px;
+  border-top-width: 0;
+  border-bottom-color: #ffffff;
+}
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999999;
+  border-left-color: rgba(0, 0, 0, 0.25);
+}
+.popover.left > .arrow:after {
+  content: " ";
+  right: 1px;
+  border-right-width: 0;
+  border-left-color: #ffffff;
+  bottom: -10px;
+}
+.carousel {
+  position: relative;
+}
+.carousel-inner {
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+}
+.carousel-inner > .item {
+  display: none;
+  position: relative;
+  -webkit-transition: 0.6s ease-in-out left;
+  -o-transition: 0.6s ease-in-out left;
+  transition: 0.6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  line-height: 1;
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  display: block;
+}
+.carousel-inner > .active {
+  left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.carousel-inner > .next {
+  left: 100%;
+}
+.carousel-inner > .prev {
+  left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+  left: 0;
+}
+.carousel-inner > .active.left {
+  left: -100%;
+}
+.carousel-inner > .active.right {
+  left: 100%;
+}
+.carousel-control {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  width: 15%;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+  font-size: 20px;
+  color: #ffffff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+}
+.carousel-control.left {
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+}
+.carousel-control.right {
+  left: auto;
+  right: 0;
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+}
+.carousel-control:hover,
+.carousel-control:focus {
+  outline: 0;
+  color: #ffffff;
+  text-decoration: none;
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+  position: absolute;
+  top: 50%;
+  z-index: 5;
+  display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+  left: 50%;
+  margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+  right: 50%;
+  margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+  width: 20px;
+  height: 20px;
+  margin-top: -10px;
+  font-family: serif;
+}
+.carousel-control .icon-prev:before {
+  content: '\2039';
+}
+.carousel-control .icon-next:before {
+  content: '\203a';
+}
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  margin-left: -30%;
+  padding-left: 0;
+  list-style: none;
+  text-align: center;
+}
+.carousel-indicators li {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  margin: 1px;
+  text-indent: -999px;
+  border: 1px solid #ffffff;
+  border-radius: 10px;
+  cursor: pointer;
+  background-color: #000 \9;
+  background-color: rgba(0, 0, 0, 0);
+}
+.carousel-indicators .active {
+  margin: 0;
+  width: 12px;
+  height: 12px;
+  background-color: #ffffff;
+}
+.carousel-caption {
+  position: absolute;
+  left: 15%;
+  right: 15%;
+  bottom: 20px;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #ffffff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
+}
+.carousel-caption .btn {
+  text-shadow: none;
+}
+@media screen and (min-width: 768px) {
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 30px;
+    height: 30px;
+    margin-top: -15px;
+    font-size: 30px;
+  }
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .icon-prev {
+    margin-left: -15px;
+  }
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-next {
+    margin-right: -15px;
+  }
+  .carousel-caption {
+    left: 20%;
+    right: 20%;
+    padding-bottom: 30px;
+  }
+  .carousel-indicators {
+    bottom: 20px;
+  }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+  content: " ";
+  display: table;
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+  clear: both;
+}
+.center-block {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.btn {
+  display: inline-block;
+  margin-bottom: 0;
+  font-weight: normal;
+  text-align: center;
+  vertical-align: middle;
+  cursor: pointer;
+  background-image: none;
+  border: 1px solid transparent;
+  white-space: nowrap;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  border-radius: 4px;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus {
+  color: #333333;
+  text-decoration: none;
+}
+.btn:active,
+.btn.active {
+  outline: 0;
+  background-image: none;
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+  cursor: not-allowed;
+  pointer-events: none;
+  opacity: 0.65;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.btn-default {
+  color: #333333;
+  background-color: #ffffff;
+  border-color: #cccccc;
+}
+.btn-default:hover,
+.btn-default:focus,
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  color: #333333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+  background-color: #ffffff;
+  border-color: #cccccc;
+}
+.btn-default .badge {
+  color: #ffffff;
+  background-color: #333333;
+}
+.btn-primary {
+  color: #ffffff;
+  background-color: #428bca;
+  border-color: #357ebd;
+}
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  color: #ffffff;
+  background-color: #3071a9;
+  border-color: #285e8e;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+  background-color: #428bca;
+  border-color: #357ebd;
+}
+.btn-primary .badge {
+  color: #428bca;
+  background-color: #ffffff;
+}
+.btn-success {
+  color: #ffffff;
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success:hover,
+.btn-success:focus,
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  color: #ffffff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success .badge {
+  color: #5cb85c;
+  background-color: #ffffff;
+}
+.btn-info {
+  color: #ffffff;
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info:hover,
+.btn-info:focus,
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  color: #ffffff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info .badge {
+  color: #5bc0de;
+  background-color: #ffffff;
+}
+.btn-warning {
+  color: #ffffff;
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning:hover,
+.btn-warning:focus,
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  color: #ffffff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning .badge {
+  color: #f0ad4e;
+  background-color: #ffffff;
+}
+.btn-danger {
+  color: #ffffff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger:hover,
+.btn-danger:focus,
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  color: #ffffff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger .badge {
+  color: #d9534f;
+  background-color: #ffffff;
+}
+.btn-link {
+  color: #428bca;
+  font-weight: normal;
+  border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+  background-color: transparent;
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+  border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+  color: #2a6496;
+  text-decoration: underline;
+  background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+  color: #777777;
+  text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-block {
+  display: block;
+  width: 100%;
+}
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+@media (min-width: 768px) {
+  .container > .navbar-header,
+  .container-fluid > .navbar-header,
+  .container > .navbar-collapse,
+  .container-fluid > .navbar-collapse {
+    margin-right: 0;
+    margin-left: 0;
+  }
+}
+.navbar-static-top {
+  z-index: 1000;
+  border-width: 0 0 1px;
+}
+@media (min-width: 768px) {
+  .navbar-static-top {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030;
+  -webkit-transform: translate3d(0, 0, 0);
+  transform: translate3d(0, 0, 0);
+}
+@media (min-width: 768px) {
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0;
+  border-width: 1px 0 0;
+}
+.navbar-brand {
+  float: left;
+  padding: 15px 15px;
+  font-size: 18px;
+  line-height: 20px;
+  height: 50px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+  text-decoration: none;
+}
+@media (min-width: 768px) {
+  .navbar > .container .navbar-brand,
+  .navbar > .container-fluid .navbar-brand {
+    margin-left: -15px;
+  }
+}
+.navbar-toggle {
+  position: relative;
+  float: right;
+  margin-right: 15px;
+  padding: 9px 10px;
+  margin-top: 8px;
+  margin-bottom: 8px;
+  background-color: transparent;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.navbar-toggle:focus {
+  outline: 0;
+}
+.navbar-toggle .icon-bar {
+  display: block;
+  width: 22px;
+  height: 2px;
+  border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+  margin-top: 4px;
+}
+@media (min-width: 768px) {
+  .navbar-toggle {
+    display: none;
+  }
+}
+.navbar-nav {
+  margin: 7.5px -15px;
+}
+.navbar-nav > li > a {
+  padding-top: 10px;
+  padding-bottom: 10px;
+  line-height: 20px;
+}
+@media (max-width: 767px) {
+  .navbar-nav .open .dropdown-menu {
+    position: static;
+    float: none;
+    width: auto;
+    margin-top: 0;
+    background-color: transparent;
+    border: 0;
+    box-shadow: none;
+  }
+  .navbar-nav .open .dropdown-menu > li > a,
+  .navbar-nav .open .dropdown-menu .dropdown-header {
+    padding: 5px 15px 5px 25px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a {
+    line-height: 20px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-nav .open .dropdown-menu > li > a:focus {
+    background-image: none;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-nav {
+    float: left;
+    margin: 0;
+  }
+  .navbar-nav > li {
+    float: left;
+  }
+  .navbar-nav > li > a {
+    padding-top: 15px;
+    padding-bottom: 15px;
+  }
+  .navbar-nav.navbar-right:first-child {
+    margin-right: -15px;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-left {
+    float: left !important;
+  }
+  .navbar-right {
+    float: right !important;
+  }
+}
+.navbar-form {
+  margin-left: -15px;
+  margin-right: -15px;
+  padding: 10px 15px;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  margin-top: 8px;
+  margin-bottom: 8px;
+}
+@media (min-width: 768px) {
+  .navbar-form .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .navbar-form .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .navbar-form .input-group .input-group-addon,
+  .navbar-form .input-group .input-group-btn,
+  .navbar-form .input-group .form-control {
+    width: auto;
+  }
+  .navbar-form .input-group > .form-control {
+    width: 100%;
+  }
+  .navbar-form .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio,
+  .navbar-form .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio label,
+  .navbar-form .checkbox label {
+    padding-left: 0;
+  }
+  .navbar-form .radio input[type="radio"],
+  .navbar-form .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .navbar-form .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+@media (max-width: 767px) {
+  .navbar-form .form-group {
+    margin-bottom: 5px;
+  }
+}
+@media (min-width: 768px) {
+  .navbar-form {
+    width: auto;
+    border: 0;
+    margin-left: 0;
+    margin-right: 0;
+    padding-top: 0;
+    padding-bottom: 0;
+    -webkit-box-shadow: none;
+    box-shadow: none;
+  }
+  .navbar-form.navbar-right:first-child {
+    margin-right: -15px;
+  }
+}
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  border-top-right-radius: 0;
+  border-top-left-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.navbar-btn {
+  margin-top: 8px;
+  margin-bottom: 8px;
+}
+.navbar-btn.btn-sm {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.navbar-btn.btn-xs {
+  margin-top: 14px;
+  margin-bottom: 14px;
+}
+.navbar-text {
+  margin-top: 15px;
+  margin-bottom: 15px;
+}
+@media (min-width: 768px) {
+  .navbar-text {
+    float: left;
+    margin-left: 15px;
+    margin-right: 15px;
+  }
+  .navbar-text.navbar-right:first-child {
+    margin-right: 0;
+  }
+}
+.navbar-default {
+  background-color: #f8f8f8;
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+  color: #777777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+  color: #5e5e5e;
+  background-color: transparent;
+}
+.navbar-default .navbar-text {
+  color: #777777;
+}
+.navbar-default .navbar-nav > li > a {
+  color: #777777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+  color: #333333;
+  background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+  color: #555555;
+  background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+  color: #cccccc;
+  background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+  border-color: #dddddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+  background-color: #dddddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+  background-color: #888888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+  background-color: #e7e7e7;
+  color: #555555;
+}
+@media (max-width: 767px) {
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+    color: #777777;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #333333;
+    background-color: transparent;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #555555;
+    background-color: #e7e7e7;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #cccccc;
+    background-color: transparent;
+  }
+}
+.navbar-default .navbar-link {
+  color: #777777;
+}
+.navbar-default .navbar-link:hover {
+  color: #333333;
+}
+.navbar-default .btn-link {
+  color: #777777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+  color: #333333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+  color: #cccccc;
+}
+.navbar-inverse {
+  background-color: #222222;
+  border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+  color: #777777;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+  color: #ffffff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+  color: #969696;
+}
+.navbar-inverse .navbar-nav > li > a {
+  color: #777777;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+  color: #ffffff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+  color: #ffffff;
+  background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+  color: #444444;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+  border-color: #333333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+  background-color: #333333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+  background-color: #ffffff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+  border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+  background-color: #080808;
+  color: #ffffff;
+}
+@media (max-width: 767px) {
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+    border-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+    color: #777777;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #ffffff;
+    background-color: transparent;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #ffffff;
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #444444;
+    background-color: transparent;
+  }
+}
+.navbar-inverse .navbar-link {
+  color: #777777;
+}
+.navbar-inverse .navbar-link:hover {
+  color: #ffffff;
+}
+.navbar-inverse .btn-link {
+  color: #777777;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+  color: #ffffff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+  color: #444444;
+}
+.breadcrumb {
+  padding: 8px 15px;
+  margin-bottom: 20px;
+  list-style: none;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+}
+.breadcrumb > li {
+  display: inline-block;
+}
+.breadcrumb > li + li:before {
+  content: "/\00a0";
+  padding: 0 5px;
+  color: #cccccc;
+}
+.breadcrumb > .active {
+  color: #777777;
+}
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: 20px 0;
+  border-radius: 4px;
+}
+.pagination > li {
+  display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+  position: relative;
+  float: left;
+  padding: 6px 12px;
+  line-height: 1.42857143;
+  text-decoration: none;
+  color: #428bca;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+  margin-left: -1px;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+  margin-left: 0;
+  border-bottom-left-radius: 4px;
+  border-top-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+  border-bottom-right-radius: 4px;
+  border-top-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+  color: #2a6496;
+  background-color: #eeeeee;
+  border-color: #dddddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+  z-index: 2;
+  color: #ffffff;
+  background-color: #428bca;
+  border-color: #428bca;
+  cursor: default;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+  color: #777777;
+  background-color: #ffffff;
+  border-color: #dddddd;
+  cursor: not-allowed;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+  padding: 10px 16px;
+  font-size: 18px;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+  border-bottom-left-radius: 6px;
+  border-top-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+  border-bottom-right-radius: 6px;
+  border-top-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+  padding: 5px 10px;
+  font-size: 12px;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.pager {
+  padding-left: 0;
+  margin: 20px 0;
+  list-style: none;
+  text-align: center;
+}
+.pager li {
+  display: inline;
+}
+.pager li > a,
+.pager li > span {
+  display: inline-block;
+  padding: 5px 14px;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+  border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+.pager .next > a,
+.pager .next > span {
+  float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+  float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+  color: #777777;
+  background-color: #ffffff;
+  cursor: not-allowed;
+}
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #ffffff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+  color: #ffffff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.label:empty {
+  display: none;
+}
+.btn .label {
+  position: relative;
+  top: -1px;
+}
+.label-default {
+  background-color: #777777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+  background-color: #5e5e5e;
+}
+.label-primary {
+  background-color: #428bca;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+  background-color: #3071a9;
+}
+.label-success {
+  background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+  background-color: #449d44;
+}
+.label-info {
+  background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+  background-color: #31b0d5;
+}
+.label-warning {
+  background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+  background-color: #ec971f;
+}
+.label-danger {
+  background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+  background-color: #c9302c;
+}
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  color: #ffffff;
+  line-height: 1;
+  vertical-align: baseline;
+  white-space: nowrap;
+  text-align: center;
+  background-color: #777777;
+  border-radius: 10px;
+}
+.badge:empty {
+  display: none;
+}
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+.btn-xs .badge {
+  top: 0;
+  padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+  color: #ffffff;
+  text-decoration: none;
+  cursor: pointer;
+}
+a.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+  color: #428bca;
+  background-color: #ffffff;
+}
+.nav-pills > li > a > .badge {
+  margin-left: 3px;
+}
+.jumbotron {
+  padding: 30px;
+  margin-bottom: 30px;
+  color: inherit;
+  background-color: #eeeeee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+  color: inherit;
+}
+.jumbotron p {
+  margin-bottom: 15px;
+  font-size: 21px;
+  font-weight: 200;
+}
+.jumbotron > hr {
+  border-top-color: #d5d5d5;
+}
+.container .jumbotron {
+  border-radius: 6px;
+}
+.jumbotron .container {
+  max-width: 100%;
+}
+@media screen and (min-width: 768px) {
+  .jumbotron {
+    padding-top: 48px;
+    padding-bottom: 48px;
+  }
+  .container .jumbotron {
+    padding-left: 60px;
+    padding-right: 60px;
+  }
+  .jumbotron h1,
+  .jumbotron .h1 {
+    font-size: 63px;
+  }
+}
+
+
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  height: 100%;
+  width: 100%;
+  border: 0;
+}
+.embed-responsive.embed-responsive-16by9 {
+  padding-bottom: 56.25%;
+}
+.embed-responsive.embed-responsive-4by3 {
+  padding-bottom: 75%;
+}
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, 0.15);
+}
+.well-lg {
+  padding: 24px;
+  border-radius: 6px;
+}
+.well-sm {
+  padding: 9px;
+  border-radius: 3px;
+}
+.close {
+  float: right;
+  font-size: 21px;
+  font-weight: bold;
+  line-height: 1;
+  color: #000000;
+  text-shadow: 0 1px 0 #ffffff;
+  opacity: 0.2;
+  filter: alpha(opacity=20);
+}
+.close:hover,
+.close:focus {
+  color: #000000;
+  text-decoration: none;
+  cursor: pointer;
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
+.modal-open {
+  overflow: hidden;
+}
+.modal {
+  display: none;
+  overflow: hidden;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1050;
+  -webkit-overflow-scrolling: touch;
+  outline: 0;
+}
+.modal.fade .modal-dialog {
+  -webkit-transform: translate3d(0, -25%, 0);
+  transform: translate3d(0, -25%, 0);
+  -webkit-transition: -webkit-transform 0.3s ease-out;
+  -moz-transition: -moz-transform 0.3s ease-out;
+  -o-transition: -o-transform 0.3s ease-out;
+  transition: transform 0.3s ease-out;
+}
+.modal.in .modal-dialog {
+  -webkit-transform: translate3d(0, 0, 0);
+  transform: translate3d(0, 0, 0);
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px;
+}
+.modal-content {
+  position: relative;
+  background-color: #ffffff;
+  border: 1px solid #999999;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+  background-clip: padding-box;
+  outline: 0;
+}
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  background-color: #000000;
+}
+.modal-backdrop.fade {
+  opacity: 0;
+  filter: alpha(opacity=0);
+}
+.modal-backdrop.in {
+  opacity: 0.5;
+  filter: alpha(opacity=50);
+}
+.modal-header {
+  padding: 15px;
+  border-bottom: 1px solid #e5e5e5;
+  min-height: 16.42857143px;
+}
+.modal-header .close {
+  margin-top: -2px;
+}
+.modal-title {
+  margin: 0;
+  line-height: 1.42857143;
+}
+.modal-body {
+  position: relative;
+  padding: 15px;
+}
+.modal-footer {
+  padding: 15px;
+  text-align: right;
+  border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+  margin-left: 5px;
+  margin-bottom: 0;
+}
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+  margin-left: 0;
+}
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+@media (min-width: 768px) {
+  .modal-dialog {
+    width: 600px;
+    margin: 30px auto;
+  }
+  .modal-content {
+    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
+  }
+  .modal-sm {
+    width: 300px;
+  }
+}
+@media (min-width: 992px) {
+  .modal-lg {
+    width: 900px;
+  }
+}
+
+.thumbnail {
+  display: block;
+  padding: 4px;
+  margin-bottom: 20px;
+  line-height: 1.42857143;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+  border-radius: 4px;
+  -webkit-transition: all 0.2s ease-in-out;
+  -o-transition: all 0.2s ease-in-out;
+  transition: all 0.2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+  margin-left: auto;
+  margin-right: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: #428bca;
+}
+.thumbnail .caption {
+  padding: 9px;
+  color: #333333;
+}
+.alert {
+  padding: 15px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.alert h4 {
+  margin-top: 0;
+  color: inherit;
+}
+.alert .alert-link {
+  font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+  margin-bottom: 0;
+}
+.alert > p + p {
+  margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+  padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  color: inherit;
+}
+.alert-success {
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+  color: #3c763d;
+}
+.alert-success hr {
+  border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+  color: #2b542c;
+}
+.alert-info {
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+  color: #31708f;
+}
+.alert-info hr {
+  border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+  color: #245269;
+}
+.alert-warning {
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+  color: #8a6d3b;
+}
+.alert-warning hr {
+  border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+  color: #66512c;
+}
+.alert-danger {
+  background-color: #f2dede;
+  border-color: #ebccd1;
+  color: #a94442;
+}
+.alert-danger hr {
+  border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+  color: #843534;
+}
+@-webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+.media,
+.media-body {
+  overflow: hidden;
+  zoom: 1;
+}
+.media,
+.media .media {
+  margin-top: 15px;
+}
+.media:first-child {
+  margin-top: 0;
+}
+.media-object {
+  display: block;
+}
+.media-heading {
+  margin: 0 0 5px;
+}
+.media > .pull-left {
+  margin-right: 10px;
+}
+.media > .pull-right {
+  margin-left: 10px;
+}
+.media-list {
+  padding-left: 0;
+  list-style: none;
+}
+.list-group {
+  margin-bottom: 20px;
+  padding-left: 0;
+}
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  margin-bottom: -1px;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+}
+.list-group-item:first-child {
+  border-top-right-radius: 4px;
+  border-top-left-radius: 4px;
+}
+.list-group-item:last-child {
+  margin-bottom: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+.list-group-item > .badge {
+  float: right;
+}
+.list-group-item > .badge + .badge {
+  margin-right: 5px;
+}
+a.list-group-item {
+  color: #555555;
+}
+a.list-group-item .list-group-item-heading {
+  color: #333333;
+}
+a.list-group-item:hover,
+a.list-group-item:focus {
+  text-decoration: none;
+  color: #555555;
+  background-color: #f5f5f5;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+  background-color: #eeeeee;
+  color: #777777;
+  cursor: not-allowed;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+  color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+  color: #777777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  z-index: 2;
+  color: #ffffff;
+  background-color: #428bca;
+  border-color: #428bca;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+  color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+  color: #e1edf7;
+}
+.list-group-item-success {
+  color: #3c763d;
+  background-color: #dff0d8;
+}
+a.list-group-item-success {
+  color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-success:hover,
+a.list-group-item-success:focus {
+  color: #3c763d;
+  background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus {
+  color: #fff;
+  background-color: #3c763d;
+  border-color: #3c763d;
+}
+.list-group-item-info {
+  color: #31708f;
+  background-color: #d9edf7;
+}
+a.list-group-item-info {
+  color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-info:hover,
+a.list-group-item-info:focus {
+  color: #31708f;
+  background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus {
+  color: #fff;
+  background-color: #31708f;
+  border-color: #31708f;
+}
+.list-group-item-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+a.list-group-item-warning {
+  color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-warning:hover,
+a.list-group-item-warning:focus {
+  color: #8a6d3b;
+  background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus {
+  color: #fff;
+  background-color: #8a6d3b;
+  border-color: #8a6d3b;
+}
+.list-group-item-danger {
+  color: #a94442;
+  background-color: #f2dede;
+}
+a.list-group-item-danger {
+  color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-danger:hover,
+a.list-group-item-danger:focus {
+  color: #a94442;
+  background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus {
+  color: #fff;
+  background-color: #a94442;
+  border-color: #a94442;
+}
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3;
+}
+.panel {
+  margin-bottom: 20px;
+  background-color: #ffffff;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.panel-body {
+  padding: 15px;
+}
+.panel-heading {
+  padding: 10px 15px;
+  border-bottom: 1px solid transparent;
+  border-top-right-radius: 3px;
+  border-top-left-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+  color: inherit;
+}
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: 16px;
+  color: inherit;
+}
+.panel-title > a {
+  color: inherit;
+}
+.panel-footer {
+  padding: 10px 15px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #dddddd;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .list-group {
+  margin-bottom: 0;
+}
+.panel > .list-group .list-group-item {
+  border-width: 1px 0;
+  border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child {
+  border-top: 0;
+  border-top-right-radius: 3px;
+  border-top-left-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child {
+  border-bottom: 0;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+  border-top-width: 0;
+}
+.list-group + .panel-footer {
+  border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+  margin-bottom: 0;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+  border-top-right-radius: 3px;
+  border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+  border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+  border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+  border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive {
+  border-top: 1px solid #dddddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+  border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+  border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+  border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+  border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+  border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+  border-bottom: 0;
+}
+.panel > .table-responsive {
+  border: 0;
+  margin-bottom: 0;
+}
+.panel-group {
+  margin-bottom: 20px;
+}
+.panel-group .panel {
+  margin-bottom: 0;
+  border-radius: 4px;
+}
+.panel-group .panel + .panel {
+  margin-top: 5px;
+}
+.panel-group .panel-heading {
+  border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body {
+  border-top: 1px solid #dddddd;
+}
+.panel-group .panel-footer {
+  border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+  border-bottom: 1px solid #dddddd;
+}
+.panel-default {
+  border-color: #dddddd;
+}
+.panel-default > .panel-heading {
+  color: #333333;
+  background-color: #f5f5f5;
+  border-color: #dddddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #dddddd;
+}
+.panel-default > .panel-heading .badge {
+  color: #f5f5f5;
+  background-color: #333333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #dddddd;
+}
+.panel-primary {
+  border-color: #428bca;
+}
+.panel-primary > .panel-heading {
+  color: #ffffff;
+  background-color: #428bca;
+  border-color: #428bca;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #428bca;
+}
+.panel-primary > .panel-heading .badge {
+  color: #428bca;
+  background-color: #ffffff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #428bca;
+}
+.panel-success {
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+  color: #dff0d8;
+  background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #d6e9c6;
+}
+.panel-info {
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+  color: #d9edf7;
+  background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #bce8f1;
+}
+.panel-warning {
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+  color: #fcf8e3;
+  background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #faebcc;
+}
+.panel-danger {
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+  color: #f2dede;
+  background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ebccd1;
+}
+
+
+.pull-right {
+  float: right !important;
+}
+.pull-left {
+  float: left !important;
+}
+.hide {
+  display: none !important;
+}
+.show {
+  display: block !important;
+}
+.invisible {
+  visibility: hidden;
+}
+.text-hide {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+.hidden {
+  display: none !important;
+  visibility: hidden !important;
+}
+.affix {
+  position: fixed;
+  -webkit-transform: translate3d(0, 0, 0);
+  transform: translate3d(0, 0, 0);
+}
+@-ms-viewport {
+  width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+  display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important;
+}
+@media (max-width: 767px) {
+  .visible-xs {
+    display: block !important;
+  }
+  table.visible-xs {
+    display: table;
+  }
+  tr.visible-xs {
+    display: table-row !important;
+  }
+  th.visible-xs,
+  td.visible-xs {
+    display: table-cell !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-block {
+    display: block !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline {
+    display: inline !important;
+  }
+}
+@media (max-width: 767px) {
+  .visible-xs-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm {
+    display: block !important;
+  }
+  table.visible-sm {
+    display: table;
+  }
+  tr.visible-sm {
+    display: table-row !important;
+  }
+  th.visible-sm,
+  td.visible-sm {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-block {
+    display: block !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md {
+    display: block !important;
+  }
+  table.visible-md {
+    display: table;
+  }
+  tr.visible-md {
+    display: table-row !important;
+  }
+  th.visible-md,
+  td.visible-md {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-block {
+    display: block !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg {
+    display: block !important;
+  }
+  table.visible-lg {
+    display: table;
+  }
+  tr.visible-lg {
+    display: table-row !important;
+  }
+  th.visible-lg,
+  td.visible-lg {
+    display: table-cell !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-block {
+    display: block !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline {
+    display: inline !important;
+  }
+}
+@media (min-width: 1200px) {
+  .visible-lg-inline-block {
+    display: inline-block !important;
+  }
+}
+@media (max-width: 767px) {
+  .hidden-xs {
+    display: none !important;
+  }
+}
+@media (min-width: 768px) and (max-width: 991px) {
+  .hidden-sm {
+    display: none !important;
+  }
+}
+@media (min-width: 992px) and (max-width: 1199px) {
+  .hidden-md {
+    display: none !important;
+  }
+}
+@media (min-width: 1200px) {
+  .hidden-lg {
+    display: none !important;
+  }
+}
+.visible-print {
+  display: none !important;
+}
+@media print {
+  .visible-print {
+    display: block !important;
+  }
+  table.visible-print {
+    display: table;
+  }
+  tr.visible-print {
+    display: table-row !important;
+  }
+  th.visible-print,
+  td.visible-print {
+    display: table-cell !important;
+  }
+}
+.visible-print-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-block {
+    display: block !important;
+  }
+}
+.visible-print-inline {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline {
+    display: inline !important;
+  }
+}
+.visible-print-inline-block {
+  display: none !important;
+}
+@media print {
+  .visible-print-inline-block {
+    display: inline-block !important;
+  }
+}
+@media print {
+  .hidden-print {
+    display: none !important;
+  }
+}
+
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+  content: "\2a";
+}
+.glyphicon-plus:before {
+  content: "\2b";
+}
+.glyphicon-euro:before {
+  content: "\20ac";
+}
+.glyphicon-minus:before {
+  content: "\2212";
+}
+.glyphicon-cloud:before {
+  content: "\2601";
+}
+.glyphicon-envelope:before {
+  content: "\2709";
+}
+.glyphicon-pencil:before {
+  content: "\270f";
+}
+.glyphicon-glass:before {
+  content: "\e001";
+}
+.glyphicon-music:before {
+  content: "\e002";
+}
+.glyphicon-search:before {
+  content: "\e003";
+}
+.glyphicon-heart:before {
+  content: "\e005";
+}
+.glyphicon-star:before {
+  content: "\e006";
+}
+.glyphicon-star-empty:before {
+  content: "\e007";
+}
+.glyphicon-user:before {
+  content: "\e008";
+}
+.glyphicon-film:before {
+  content: "\e009";
+}
+.glyphicon-th-large:before {
+  content: "\e010";
+}
+.glyphicon-th:before {
+  content: "\e011";
+}
+.glyphicon-th-list:before {
+  content: "\e012";
+}
+.glyphicon-ok:before {
+  content: "\e013";
+}
+.glyphicon-remove:before {
+  content: "\e014";
+}
+.glyphicon-zoom-in:before {
+  content: "\e015";
+}
+.glyphicon-zoom-out:before {
+  content: "\e016";
+}
+.glyphicon-off:before {
+  content: "\e017";
+}
+.glyphicon-signal:before {
+  content: "\e018";
+}
+.glyphicon-cog:before {
+  content: "\e019";
+}
+.glyphicon-trash:before {
+  content: "\e020";
+}
+.glyphicon-home:before {
+  content: "\e021";
+}
+.glyphicon-file:before {
+  content: "\e022";
+}
+.glyphicon-time:before {
+  content: "\e023";
+}
+.glyphicon-road:before {
+  content: "\e024";
+}
+.glyphicon-download-alt:before {
+  content: "\e025";
+}
+.glyphicon-download:before {
+  content: "\e026";
+}
+.glyphicon-upload:before {
+  content: "\e027";
+}
+.glyphicon-inbox:before {
+  content: "\e028";
+}
+.glyphicon-play-circle:before {
+  content: "\e029";
+}
+.glyphicon-repeat:before {
+  content: "\e030";
+}
+.glyphicon-refresh:before {
+  content: "\e031";
+}
+.glyphicon-list-alt:before {
+  content: "\e032";
+}
+.glyphicon-lock:before {
+  content: "\e033";
+}
+.glyphicon-flag:before {
+  content: "\e034";
+}
+.glyphicon-headphones:before {
+  content: "\e035";
+}
+.glyphicon-volume-off:before {
+  content: "\e036";
+}
+.glyphicon-volume-down:before {
+  content: "\e037";
+}
+.glyphicon-volume-up:before {
+  content: "\e038";
+}
+.glyphicon-qrcode:before {
+  content: "\e039";
+}
+.glyphicon-barcode:before {
+  content: "\e040";
+}
+.glyphicon-tag:before {
+  content: "\e041";
+}
+.glyphicon-tags:before {
+  content: "\e042";
+}
+.glyphicon-book:before {
+  content: "\e043";
+}
+.glyphicon-bookmark:before {
+  content: "\e044";
+}
+.glyphicon-print:before {
+  content: "\e045";
+}
+.glyphicon-camera:before {
+  content: "\e046";
+}
+.glyphicon-font:before {
+  content: "\e047";
+}
+.glyphicon-bold:before {
+  content: "\e048";
+}
+.glyphicon-italic:before {
+  content: "\e049";
+}
+.glyphicon-text-height:before {
+  content: "\e050";
+}
+.glyphicon-text-width:before {
+  content: "\e051";
+}
+.glyphicon-align-left:before {
+  content: "\e052";
+}
+.glyphicon-align-center:before {
+  content: "\e053";
+}
+.glyphicon-align-right:before {
+  content: "\e054";
+}
+.glyphicon-align-justify:before {
+  content: "\e055";
+}
+.glyphicon-list:before {
+  content: "\e056";
+}
+.glyphicon-indent-left:before {
+  content: "\e057";
+}
+.glyphicon-indent-right:before {
+  content: "\e058";
+}
+.glyphicon-facetime-video:before {
+  content: "\e059";
+}
+.glyphicon-picture:before {
+  content: "\e060";
+}
+.glyphicon-map-marker:before {
+  content: "\e062";
+}
+.glyphicon-adjust:before {
+  content: "\e063";
+}
+.glyphicon-tint:before {
+  content: "\e064";
+}
+.glyphicon-edit:before {
+  content: "\e065";
+}
+.glyphicon-share:before {
+  content: "\e066";
+}
+.glyphicon-check:before {
+  content: "\e067";
+}
+.glyphicon-move:before {
+  content: "\e068";
+}
+.glyphicon-step-backward:before {
+  content: "\e069";
+}
+.glyphicon-fast-backward:before {
+  content: "\e070";
+}
+.glyphicon-backward:before {
+  content: "\e071";
+}
+.glyphicon-play:before {
+  content: "\e072";
+}
+.glyphicon-pause:before {
+  content: "\e073";
+}
+.glyphicon-stop:before {
+  content: "\e074";
+}
+.glyphicon-forward:before {
+  content: "\e075";
+}
+.glyphicon-fast-forward:before {
+  content: "\e076";
+}
+.glyphicon-step-forward:before {
+  content: "\e077";
+}
+.glyphicon-eject:before {
+  content: "\e078";
+}
+.glyphicon-chevron-left:before {
+  content: "\e079";
+}
+.glyphicon-chevron-right:before {
+  content: "\e080";
+}
+.glyphicon-plus-sign:before {
+  content: "\e081";
+}
+.glyphicon-minus-sign:before {
+  content: "\e082";
+}
+.glyphicon-remove-sign:before {
+  content: "\e083";
+}
+.glyphicon-ok-sign:before {
+  content: "\e084";
+}
+.glyphicon-question-sign:before {
+  content: "\e085";
+}
+.glyphicon-info-sign:before {
+  content: "\e086";
+}
+.glyphicon-screenshot:before {
+  content: "\e087";
+}
+.glyphicon-remove-circle:before {
+  content: "\e088";
+}
+.glyphicon-ok-circle:before {
+  content: "\e089";
+}
+.glyphicon-ban-circle:before {
+  content: "\e090";
+}
+.glyphicon-arrow-left:before {
+  content: "\e091";
+}
+.glyphicon-arrow-right:before {
+  content: "\e092";
+}
+.glyphicon-arrow-up:before {
+  content: "\e093";
+}
+.glyphicon-arrow-down:before {
+  content: "\e094";
+}
+.glyphicon-share-alt:before {
+  content: "\e095";
+}
+.glyphicon-resize-full:before {
+  content: "\e096";
+}
+.glyphicon-resize-small:before {
+  content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+  content: "\e101";
+}
+.glyphicon-gift:before {
+  content: "\e102";
+}
+.glyphicon-leaf:before {
+  content: "\e103";
+}
+.glyphicon-fire:before {
+  content: "\e104";
+}
+.glyphicon-eye-open:before {
+  content: "\e105";
+}
+.glyphicon-eye-close:before {
+  content: "\e106";
+}
+.glyphicon-warning-sign:before {
+  content: "\e107";
+}
+.glyphicon-plane:before {
+  content: "\e108";
+}
+.glyphicon-calendar:before {
+  content: "\e109";
+}
+.glyphicon-random:before {
+  content: "\e110";
+}
+.glyphicon-comment:before {
+  content: "\e111";
+}
+.glyphicon-magnet:before {
+  content: "\e112";
+}
+.glyphicon-chevron-up:before {
+  content: "\e113";
+}
+.glyphicon-chevron-down:before {
+  content: "\e114";
+}
+.glyphicon-retweet:before {
+  content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+  content: "\e116";
+}
+.glyphicon-folder-close:before {
+  content: "\e117";
+}
+.glyphicon-folder-open:before {
+  content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+  content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+  content: "\e120";
+}
+.glyphicon-hdd:before {
+  content: "\e121";
+}
+.glyphicon-bullhorn:before {
+  content: "\e122";
+}
+.glyphicon-bell:before {
+  content: "\e123";
+}
+.glyphicon-certificate:before {
+  content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+  content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+  content: "\e126";
+}
+.glyphicon-hand-right:before {
+  content: "\e127";
+}
+.glyphicon-hand-left:before {
+  content: "\e128";
+}
+.glyphicon-hand-up:before {
+  content: "\e129";
+}
+.glyphicon-hand-down:before {
+  content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+  content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+  content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+  content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+  content: "\e134";
+}
+.glyphicon-globe:before {
+  content: "\e135";
+}
+.glyphicon-wrench:before {
+  content: "\e136";
+}
+.glyphicon-tasks:before {
+  content: "\e137";
+}
+.glyphicon-filter:before {
+  content: "\e138";
+}
+.glyphicon-briefcase:before {
+  content: "\e139";
+}
+.glyphicon-fullscreen:before {
+  content: "\e140";
+}
+.glyphicon-dashboard:before {
+  content: "\e141";
+}
+.glyphicon-paperclip:before {
+  content: "\e142";
+}
+.glyphicon-heart-empty:before {
+  content: "\e143";
+}
+.glyphicon-link:before {
+  content: "\e144";
+}
+.glyphicon-phone:before {
+  content: "\e145";
+}
+.glyphicon-pushpin:before {
+  content: "\e146";
+}
+.glyphicon-usd:before {
+  content: "\e148";
+}
+.glyphicon-gbp:before {
+  content: "\e149";
+}
+.glyphicon-sort:before {
+  content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+  content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+  content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+  content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+  content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+  content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+  content: "\e156";
+}
+.glyphicon-unchecked:before {
+  content: "\e157";
+}
+.glyphicon-expand:before {
+  content: "\e158";
+}
+.glyphicon-collapse-down:before {
+  content: "\e159";
+}
+.glyphicon-collapse-up:before {
+  content: "\e160";
+}
+.glyphicon-log-in:before {
+  content: "\e161";
+}
+.glyphicon-flash:before {
+  content: "\e162";
+}
+.glyphicon-log-out:before {
+  content: "\e163";
+}
+.glyphicon-new-window:before {
+  content: "\e164";
+}
+.glyphicon-record:before {
+  content: "\e165";
+}
+.glyphicon-save:before {
+  content: "\e166";
+}
+.glyphicon-open:before {
+  content: "\e167";
+}
+.glyphicon-saved:before {
+  content: "\e168";
+}
+.glyphicon-import:before {
+  content: "\e169";
+}
+.glyphicon-export:before {
+  content: "\e170";
+}
+.glyphicon-send:before {
+  content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+  content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+  content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+  content: "\e174";
+}
+.glyphicon-floppy-save:before {
+  content: "\e175";
+}
+.glyphicon-floppy-open:before {
+  content: "\e176";
+}
+.glyphicon-credit-card:before {
+  content: "\e177";
+}
+.glyphicon-transfer:before {
+  content: "\e178";
+}
+.glyphicon-cutlery:before {
+  content: "\e179";
+}
+.glyphicon-header:before {
+  content: "\e180";
+}
+.glyphicon-compressed:before {
+  content: "\e181";
+}
+.glyphicon-earphone:before {
+  content: "\e182";
+}
+.glyphicon-phone-alt:before {
+  content: "\e183";
+}
+.glyphicon-tower:before {
+  content: "\e184";
+}
+.glyphicon-stats:before {
+  content: "\e185";
+}
+.glyphicon-sd-video:before {
+  content: "\e186";
+}
+.glyphicon-hd-video:before {
+  content: "\e187";
+}
+.glyphicon-subtitles:before {
+  content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+  content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+  content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+  content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+  content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+  content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+  content: "\e194";
+}
+.glyphicon-registration-mark:before {
+  content: "\e195";
+}
+.glyphicon-cloud-download:before {
+  content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+  content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+  content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+  content: "\e200";
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+  display: block;
+}
+audio,
+canvas,
+progress,
+video {
+  display: inline-block;
+  vertical-align: baseline;
+}
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+[hidden],
+template {
+  display: none;
+}
+a {
+  background: transparent;
+}
+a:active,
+a:hover {
+  outline: 0;
+}
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+b,
+strong {
+  font-weight: bold;
+}
+dfn {
+  font-style: italic;
+}
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+mark {
+  background: #ff0;
+  color: #000;
+}
+small {
+  font-size: 80%;
+}
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+sup {
+  top: -0.5em;
+}
+sub {
+  bottom: -0.25em;
+}
+img {
+  border: 0;
+}
+svg:not(:root) {
+  overflow: hidden;
+}
+figure {
+  margin: 1em 40px;
+}
+hr {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+  height: 0;
+}
+pre {
+  overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit;
+  font: inherit;
+  margin: 0;
+}
+button {
+  overflow: visible;
+}
+button,
+select {
+  text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+input {
+  line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box;
+  padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: textfield;
+  -moz-box-sizing: content-box;
+  -webkit-box-sizing: content-box;
+  box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+legend {
+  border: 0;
+  padding: 0;
+}
+textarea {
+  overflow: auto;
+}
+optgroup {
+  font-weight: bold;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+td,
+th {
+  padding: 0;
+}
+@media print {
+  * {
+    text-shadow: none !important;
+    color: #000 !important;
+    background: transparent !important;
+    box-shadow: none !important;
+  }
+  a,
+  a:visited {
+    text-decoration: underline;
+  }
+  a[href]:after {
+    content: " (" attr(href) ")";
+  }
+  abbr[title]:after {
+    content: " (" attr(title) ")";
+  }
+  a[href^="javascript:"]:after,
+  a[href^="#"]:after {
+    content: "";
+  }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+  select {
+    background: #fff !important;
+  }
+  .navbar {
+    display: none;
+  }
+  .table td,
+  .table th {
+    background-color: #fff !important;
+  }
+  .btn > .caret,
+  .dropup > .btn > .caret {
+    border-top-color: #000 !important;
+  }
+  .label {
+    border: 1px solid #000;
+  }
+  .table {
+    border-collapse: collapse !important;
+  }
+  .table-bordered th,
+  .table-bordered td {
+    border: 1px solid #ddd !important;
+  }
+}
+@font-face {
+  font-family: 'Glyphicons Halflings';
+  src: url('../fonts/glyphicons-halflings-regular.eot');
+  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/css/com.css b/ap/app/zte_webui_min/css/com.css
new file mode 100755
index 0000000..9ac8585
--- /dev/null
+++ b/ap/app/zte_webui_min/css/com.css
@@ -0,0 +1,2602 @@
+/* Reset the container */
+.container {
+  width: 970px !important;
+  max-width: none !important;
+}
+
+.container .navbar-header,
+.container .navbar-collapse {
+  margin-right: 0;
+  margin-left: 0;
+}
+
+/* Always float the navbar header */
+.navbar-header {
+  float: left;
+}
+
+/* Undo the collapsing navbar */
+.navbar-collapse {
+  display: block !important;
+  height: auto !important;
+  padding-bottom: 0;
+  overflow: visible !important;
+}
+
+.navbar-toggle {
+  display: none;
+}
+.navbar-collapse {
+  border-top: 0;
+}
+
+.navbar-brand {
+  margin-left: -15px;
+}
+
+/* Always apply the floated nav */
+.navbar-nav {
+  float: left;
+  margin: 0;
+}
+.navbar-nav > li {
+  float: left;
+}
+.navbar-nav > li > a {
+  padding: 15px;
+}
+
+/* Redeclare since we override the float above */
+.navbar-nav.navbar-right {
+  float: right;
+}
+
+/* Undo custom dropdowns */
+.navbar .navbar-nav .open .dropdown-menu {
+  position: absolute;
+  float: left;
+  background-color: #fff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .15);
+  border-width: 0 1px 1px;
+  border-radius: 0 0 4px 4px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+.navbar-default .navbar-nav .open .dropdown-menu > li > a {
+  color: #333;
+}
+.navbar .navbar-nav .open .dropdown-menu > li > a:hover,
+.navbar .navbar-nav .open .dropdown-menu > li > a:focus,
+.navbar .navbar-nav .open .dropdown-menu > .active > a,
+.navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+.navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+  color: #fff !important;
+  background-color: #008AD7 !important;
+}
+.navbar .navbar-nav .open .dropdown-menu > .disabled > a,
+.navbar .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+.navbar .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+  color: #999 !important;
+  background-color: transparent !important;
+}
+
+body {
+    min-width: 970px;
+    padding-bottom: 30px;
+}
+
+.lead {
+  font-size: 16px;
+}
+
+.page-header {
+  margin-bottom: 30px;
+}
+.page-header .lead {
+  margin-bottom: 10px;
+}
+h1, .h1 {
+    font-size: 20px;
+}
+h2, .h2 {
+    font-size: 18px;
+}
+h3, .h3 {
+    font-size: 18px;
+}
+label{
+    font-weight: normal;
+}
+h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6{
+    font-weight: bold;
+}
+
+.label-primary {
+    background-color: #018AD8;
+}
+
+.arrow-down {
+    bottom:0;
+    border-width: 8px 4px 0;
+	width: 0;
+    height: 0;
+    border-color: #018AD8 transparent transparent;
+    border-style: solid;
+}
+
+.absolute-center {
+    position: absolute;
+    left: 49%;
+}
+
+.info-title.label {
+    padding: 0.3em 0.7em 0.3em;
+}
+
+.margin-top-10 {margin-top: 10px;}
+.margin-top-15 {margin-top: 15px;}
+.margin-top-20 {margin-top: 20px;}
+.margin-top-50 {margin-top: 50px;}
+.margin-top-80 {margin-top: 80px;}
+.margin-top-160 {margin-top: 160px;}
+
+.margin-bottom-10{margin-bottom: 10px;}
+.margin-bottom-20{margin-bottom: 20px;}
+.margin-bottom-50{margin-bottom: 50px;}
+
+.margin-left-10{margin-left: 10px;}
+.margin-left-15{margin-left: 15px;}
+.margin-left-3em{margin-left: 3em;}
+
+.margin-right-20{margin-right: 20px;}
+
+.padding-top-10{padding-top: 10px;}
+
+.padding-right-10{padding-right: 10px;}
+.padding-right-15{padding-right: 15px;}
+.padding-right-90 {
+    padding-right: 90px;
+}
+
+.line-height-20{line-height: 20px;}
+.line-height-30{line-height: 30px;}
+.line-height-40{line-height: 40px;}
+.line-height-60{line-height: 60px;}
+
+.width-60{width: 60px;}
+
+.font-weight-bold{
+    font-weight: bold;
+}
+
+.smsUnreadCount {
+    width: 30px;
+    height: 20px;
+    line-height: 20px;
+    padding: 2px;
+    top: -13px;
+    left: 20px;
+    position: absolute;
+    text-align: center;
+    z-index: 10;
+    background: url("../pic/png_new_sms_bg.png") no-repeat scroll 0 -5px transparent;
+    color: white;
+}
+
+.tooltip {
+    width: auto;
+    min-width: 5px;
+    position: absolute;
+    padding: 6px;
+    display: none;
+    color: #fff;
+    background-color: #4B4B4B;
+    border-radius: 4px;
+    -moz-border-radius: 4px;
+    -webkit-border-radius: 4px;
+    box-shadow: 0 3px 5px #999;
+    -moz-box-shadow: 0 3px 5px #999;
+    -webkit-box-shadow: 0 3px 5px #999;
+    margin-top: 5px;
+    *+margin-top:0px;
+}
+
+#statusBar span{
+    margin-right: 10px;
+}
+
+#statusBar span.smsUnreadCount{
+    margin-left: 0;
+}
+
+#statusBar .statusItem{
+    color: #696E72;
+    font-weight: bold;
+    line-height: 35px;
+    vertical-align: middle;
+}
+
+#statusBar #wifi_status{
+    width: 36px;
+    display: inline-block;
+}
+
+#statusBar #wifi_status i{
+    width: 36px;
+    height: 24px;
+    line-height: 24px;
+    display: inline-block;
+}
+
+#statusBar .icon_connection{
+    width: 50px;
+    display: inline-block;
+}
+
+#statusBar .wifi_connected{
+    width: 42px;
+    height: 30px;
+    background:url("../pic/pic_wifi_connect.png") no-repeat scroll center 2px transparent;
+}
+
+#statusBar .rj45_connected{
+    width: 42px;
+    height: 30px;
+    background:url("../pic/pic_rj45_connect.png") no-repeat scroll center 2px transparent;
+}
+
+#statusBar .connecting{
+    width: 36px;
+    height: 30px;
+    background:url("../pic/pic_connecting.gif") no-repeat scroll center 3px transparent;
+}
+
+#statusBar .disconnect{
+    width: 42px;
+    height: 30px;
+    background:url("../pic/pic_disconnect.png") no-repeat scroll center 3px transparent;
+}
+
+#statusBar .connectionNone{
+    height: 30px;
+    background:url("../pic/pic_connection.png") no-repeat scroll center 3px transparent;
+}
+
+#statusBar .connectionUp{
+    height: 30px;
+    background:url("../pic/pic_connection.png") no-repeat scroll center -27px transparent;
+}
+
+#statusBar .connectionDown{
+    height: 30px;
+    background:url("../pic/pic_connection.png") no-repeat scroll center -57px transparent;
+}
+
+#statusBar .connectionBoth{
+    height: 30px;
+    background:url("../pic/pic_connection.png") no-repeat scroll center -87px transparent;
+}
+
+#statusBar .signal{
+    width: 40px;
+    height: 30px;
+    display: inline-block;
+}
+
+#statusBar .signal_none{
+    width: 30px;
+    height: 30px;
+    background:url("../pic/res_signal.png") no-repeat scroll 6px -268px transparent;
+}
+
+#statusBar .signal0{
+    height: 30px;
+    background:url("../pic/res_signal.png") no-repeat scroll center -3px transparent;
+}
+
+#statusBar .signal1{
+    height: 30px;
+    background:url("../pic/res_signal.png") no-repeat scroll center -45px transparent;
+}
+
+#statusBar .signal2{
+    height: 30px;
+    background:url("../pic/res_signal.png") no-repeat scroll center -92px transparent;
+}
+
+#statusBar .signal3{
+    height: 30px;
+    background:url("../pic/res_signal.png") no-repeat scroll center -140px transparent;
+}
+
+#statusBar .signal4{
+    height: 30px;
+    background:url("../pic/res_signal.png") no-repeat scroll center -185px transparent;
+}
+
+#statusBar .signal5{
+    height: 30px;
+    background:url("../pic/res_signal.png") no-repeat scroll center -227px transparent;
+}
+
+#statusBar .wifi_status0{
+    background: url("../pic/wlan.png") no-repeat scroll 0 4px transparent;
+}
+
+#statusBar .wifi_status1{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -20px transparent;
+}
+
+#statusBar .wifi_status2{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -45px transparent;
+}
+
+#statusBar .wifi_status3{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -70px transparent;
+}
+
+#statusBar .wifi_status4{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -95px transparent;
+}
+
+#statusBar .wifi_status5{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -120px transparent;
+}
+
+#statusBar .wifi_status6{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -145px transparent;
+}
+
+#statusBar .wifi_status7{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -170px transparent;
+}
+
+#statusBar .wifi_status8{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -195px transparent;
+}
+
+#statusBar .wifi_status9{
+    background: url("../pic/wlan.png") no-repeat scroll 0 -220px transparent;
+}
+
+#statusBar .wifi_status10{
+    background: url("../pic/wlan.png") no-repeat scroll -40px 4px transparent;
+}
+
+#statusBar .wifi_status11{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -20px transparent;
+}
+
+#statusBar .wifi_status12{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -45px transparent;
+}
+
+#statusBar .wifi_status13{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -70px transparent;
+}
+
+#statusBar .wifi_status14{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -95px transparent;
+}
+
+#statusBar .wifi_status15{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -120px transparent;
+}
+
+#statusBar .wifi_status16{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -145px transparent;
+}
+
+#statusBar .wifi_status17{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -170px transparent;
+}
+
+#statusBar .wifi_status18{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -195px transparent;
+}
+
+#statusBar .wifi_status19{
+    background: url("../pic/wlan.png") no-repeat scroll -40px -220px transparent;
+}
+
+#statusBar .wifi_status20{
+    background: url("../pic/wlan.png") no-repeat scroll -78px 5px transparent;
+}
+
+#statusBar .wifi_status21{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -20px transparent;
+}
+
+#statusBar .wifi_status22{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -45px transparent;
+}
+
+#statusBar .wifi_status23{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -70px transparent;
+}
+
+#statusBar .wifi_status24{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -95px transparent;
+}
+
+#statusBar .wifi_status25{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -120px transparent;
+}
+
+#statusBar .wifi_status26{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -145px transparent;
+}
+
+#statusBar .wifi_status27{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -170px transparent;
+}
+
+#statusBar .wifi_status28{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -195px transparent;
+}
+
+#statusBar .wifi_status29{
+    background: url("../pic/wlan.png") no-repeat scroll -78px -220px transparent;
+}
+
+#statusBar .wifi_status30{
+    background: url("../pic/wlan.png") no-repeat scroll -116px 5px transparent;
+}
+
+#statusBar .wifi_status31{
+    background: url("../pic/wlan.png") no-repeat scroll -116px -20px transparent;
+}
+
+#statusBar .wifi_status32{
+    background: url("../pic/wlan.png") no-repeat scroll -116px -45px transparent;
+}
+
+#statusBar .wifi_status_off{
+    background:url('../pic/wlan_off.png') no-repeat;
+}
+
+/* Overlay */
+#loading {
+    display: none;
+}
+
+#result-overlay {
+    display: none;
+}
+
+#result_wording h2{
+    font-size: 20px;
+    margin-top: 5px;
+    margin-bottom: 8px;
+}
+
+#result-overlay #result-image {
+    height: 75px;
+    margin: 0 auto;
+    width: 75px;
+}
+
+#result-overlay .overlay-success {
+    background: url("../pic/res_succ.png") no-repeat scroll 0 0 transparent;
+}
+
+#result-overlay .overlay-error {
+    background: url("../pic/res_failure.png") no-repeat scroll 0 0 transparent;
+}
+
+#loading_container{padding-bottom: 15px;}
+
+#loading_container a {
+    outline: none;
+}
+
+#progress {
+    display: none;
+}
+
+
+.ko-grid-search{
+    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-top: 3px;
+    margin-right: 15px;
+    width: 155px;
+    height: 30px;
+    line-height: 30px;
+    padding-right: 5px;
+    display: inline-block;
+    border: 1px solid #a1a1a1 ;
+    border-radius: 5px;
+    -moz-border-radius: 5px;
+    -webkit-border-radius: 5px;
+    -khtml-border-radius: 5px;
+    -ms-border-radius: 5px;
+    -o-border-radius: 5px;
+}
+
+.ko-grid-search input{
+    border: 0;
+    -webkit-box-shadow: none;
+    box-shadow: none;
+    border: none;
+    height: 20px;
+    line-height: 20px;
+    padding: 5px 0;
+    background: none;
+    outline: none;
+    display: inline;
+}
+
+.ko-grid-search input.focusIn[type="text"]{
+    width: 100px;
+    padding: 2px 0;
+    margin: 0;
+    color: #767676;
+    background: none;
+    border: none;
+    box-shadow: none;
+}
+
+#frmPhoneBook #ko_grid_search_txt{
+    width: 100px;
+    padding: 2px 0;
+    color: #767676;
+    font-style:italic;
+}
+
+#smsListForm #searchInput{
+    width: 100px;
+    padding: 2px 0;
+    color: #767676;
+    font-style:italic;
+}
+
+#ko_grid_search_txt::-ms-clear {
+    display: none;
+}
+
+.ko-grid-search input.focusIn[type="text"], input.focusIn[type="password"] ,textarea:focus{
+    border-color:none;
+    outline: 0;
+    /* IE6-9 */
+    -webkit-box-shadow:none;
+    -moz-box-shadow: none;
+    box-shadow: none;
+}
+
+.checkbox {
+    width: 16px;
+    height: 16px;
+    margin-top: 0;
+    margin-bottom: 0;
+    cursor: pointer;
+    vertical-align: middle;
+    display: inline-block;
+    background:url("../pic/tickbox.png") no-repeat;
+}
+
+.checkbox:hover {
+    display: inline-block;
+}
+
+.checkbox input {
+    display: none;
+}
+
+.checkbox_selected {
+    background:url("../pic/tickbox_in.png") no-repeat;
+}
+
+p.checkbox.disable{
+    background:url("../pic/tickbox_disable.png") no-repeat;
+}
+
+p.checkbox.checked_disable{
+    background:url("../pic/tickbox_in_disable.png") no-repeat;
+}
+
+.header-bottom {
+    padding-bottom: 10px;
+    border-bottom: 1px solid #d3d3d3;
+}
+
+.popover_title{
+    font-size: 14px;
+    font-weight: normal;
+    line-height: 18px;
+    margin: 0;
+    padding: 8px 14px;
+    border-bottom: 1px solid #ebebeb;
+    border-radius: 5px 5px 0 0;
+    background-color: #f7f7f7;
+}
+
+.popover_content{
+    margin-top: 1em;
+    padding: 0 8px 8px 8px;
+}
+
+.popover_row label.error{
+    width: 100%;
+    text-align: left;
+}
+
+.form-title{
+    margin-bottom: 20px;
+    border-bottom: 1px solid #eee;
+}
+
+#footer{
+    /*margin-top: 40px;
+    background: #eeeeee;*/
+    height: 60px;
+    line-height: 60px;
+    text-align: center;
+}
+
+#smsChatRoom {
+    width: 100%;
+    font-size: 12px;
+    padding-left: 0;
+    float: left;
+    display: none;
+}
+
+#smsChatRoom #chosenUserSelect{
+    width: 690px;
+}
+
+#chosenUser {
+    padding: 10px;
+    background-color: #D4DAE2;
+    box-shadow: 0 -3px 8px #ddd;
+}
+
+#chosenUser1{
+    margin-top: 0;
+}
+
+#chatlist {
+    padding-left: 10px;
+    padding-top: 10px;
+    background-color: white;
+    position: relative;
+    min-height: 240px;
+    box-shadow: 0 -3px 8px #D4DAE2;
+    *display: inline;
+}
+
+#chatlist a{
+    text-decoration: underline;
+    color: blue;
+}
+
+#chatpanel {
+    height: 250px;
+    border: 1px solid #e1e1e1;
+    overflow-x: hidden;
+    overflow-y: hidden;
+    background-color: white;
+}
+
+#chatpanel .clear-container {
+    width: 100%;
+    height: 250px;
+    border: 1px solid #e1e1e1;
+    border-top: none;
+    border-left: none;
+    position: relative;
+    overflow-x: hidden;
+    overflow-y: auto;
+}
+
+#inputpanel {
+    height: 142px;
+    padding: 10px 0;
+    position: relative;
+}
+
+.chatform {
+    margin: 0;
+    height: 120px;
+}
+
+textarea {
+	resize: none;
+}
+
+.chatform .chattextinput textarea {
+    height: 110px;
+    line-height:normal;
+    font-size: 14px;
+    color: #696e72;
+    overflow: auto;
+}
+
+#sendSmsErrorLi{
+    color: #CC0000;
+}
+
+.chatfun {
+    padding-top: 8px;
+}
+
+.chatfun ul.ext {
+    float: left;
+}
+
+.chatfun ul.ext li {
+    float: left;
+    padding-left: 10px;
+    margin-right: 20px;
+}
+
+.chatfun ul.btn {
+    float: right;
+}
+
+.chatfun ul.btn li {
+    float: left;
+    margin-right: 10px;
+}
+
+.chatfun ul.btn li button {
+    padding: 1px 0;
+}
+
+.grid-talk .main-wrap {
+    margin-right: 36px;
+    _margin-right: 18px;
+}
+
+.grid-talkf .main-wrap {
+    margin-left: 36px;
+    _margin-left: 18px;
+}
+
+.col-main {
+    float: left;
+    width: 100%;
+    min-height: 1px;
+}
+
+
+.progress-content{
+    text-align: center
+}
+
+.progress-bar-container{
+    width:400px; height:32px;
+    margin:0 auto;
+    padding:1px;
+    border:1px #CCC solid;
+    text-align: left;
+    position:relative;
+}
+
+.progress-bar{
+    width:200px;
+    height:28px;
+    background:#429aff;
+}
+
+.progress-bar-value{
+    top:7px;
+    width:400px;
+    position:absolute;
+    text-align:center;
+    overflow:hidden;
+    font-weight:bold;
+}
+
+.progress-prompt{
+    font-size:small;
+    font-weight:bold;
+    padding-bottom: 15px;
+}
+
+#simplemodal-overlay {
+    cursor: wait;
+    background-color: #000;
+}
+
+#confirm,#popupSettingWindow{
+    display: none;
+}
+
+/* Overlay */
+#confirm-overlay {
+    cursor: wait;
+    background-color: #000;
+}
+
+/* Container */
+#confirm-container {
+    width: 420px;
+    border: 2px solid #dddddd;
+    border-radius: 6px;
+    -webkit-border-radius: 6px;
+    -moz-border-radius: 6px;
+    text-align: left;
+    background: none repeat scroll 0 0 #fff;
+}
+
+#confirm-container .header {
+    width: 100%;
+    height: 30px;
+    line-height: 30px;
+    color: #000;
+    font-weight: bold;
+    background-color: #eaeaea;
+    border-bottom: 1px solid #cbcbcb;
+}
+
+#confirm-container .header span {
+    padding-left: 8px;
+}
+
+#confirm-container .buttons {
+    padding: 10px 8px;
+    text-align: right;
+}
+
+#confirm-container .message {
+    color: #000;
+    font-size: 14px;
+}
+
+#confirm .message > i {
+    font-size: 0.9em;
+}
+
+#confirm-message-container{
+    margin: 10px 5px;
+}
+
+#confirm .icon {
+    width: 50px;
+    margin: 0 0 0 10px;
+    vertical-align: top;
+    display: inline-block;
+}
+
+#confirm .confirm-message {
+    width: 310px;
+    margin: 10px 10px 10px 0;
+    vertical-align: top;
+    display: inline-block;
+}
+
+.simplemodal-wrap .form-title{
+    font-size: 16px;
+    font-weight: bold;
+}
+
+.cursorhand{
+    cursor: pointer;
+}
+
+.device-block{
+    width: 100px;
+    margin: 0 24px 5px 0;
+    text-align: center;
+    text-decoration: none;
+    display: inline-block;
+}
+
+.device-block-desc{
+    padding-top: 100px;
+    width: 100px;
+    display: inline-block;
+    overflow: hidden;
+    vertical-align: middle;
+    text-align: center;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    background: url("../pic/mobile.png") no-repeat scroll 0 0 transparent;
+}
+
+.expend-desc{
+    padding-left: 2em;
+}
+
+.arrow-right{
+    padding-right: 30px;
+    background: url("../pic/direct-right.png") no-repeat scroll right center transparent;
+}
+
+#pc_main_form .content {
+    padding-left: 2em;
+}
+
+table.colorHoverTable thead tr {
+    height: 27px;
+}
+
+.header-center th{
+    text-align: center;
+}
+
+#pc_time_limited_form table thead tr{
+    background: none;
+}
+
+#pc_time_limited_form table thead td{
+    min-width: 4%;
+}
+
+#pc_time_limited_form table tbody td{
+    border: 1px solid #ccc;
+    height: 40px;
+    vertical-align: middle;
+	/*line-height: 40px;*/
+    padding: 0;
+    border-collapse: collapse;
+}
+
+#pc_time_limited_form table tbody td.active{
+    background-color: red;
+}
+
+#pc_time_limited_form table tbody td:first-child{
+    width: 50px;
+    border-width: 0 1px 0 0;
+}
+
+#pc_time_limited_form .pc_time_block{
+    width: 20px;
+    height: 20px;
+    display: inline-block;
+    border: 1px solid #ccc;
+}
+
+#pc_time_limited_form .time_td_hover{
+    background: #eee;
+}
+
+#pc_time_limited_form .forbid_time{
+    background-color: red;
+}
+
+#pc_children_group_form table td{
+    line-height: 32px;
+}
+
+.layout:after,.main-wrap:after,.col-sub:after,.col-extra:after {
+    content: '\20';
+    display: block;
+    height: 0;
+    clear: both;
+}
+
+.talk-item {
+    margin: 10px 0 5px 0;
+}
+
+.talk-item .info-user {
+    width: 30px;
+    padding: 2px;
+    border: 1px solid #335A8B;
+    -webkit-border-radius: 5px;
+    -moz-border-radius: 5px;
+    border-radius: 5px;
+    background-color: #fff;
+}
+
+.talk-item .info-user img {
+    width: 30px;
+    display: block;
+}
+
+.talk-item .time {
+    height: 20px;
+    line-height: 20px;
+    clear: both;
+}
+
+.talk-item .msg {
+    padding: 10px;
+    max-width: 560px;
+    line-height: 180%;
+    position: relative;
+    -webkit-border-radius: 5px;
+    -moz-border-radius: 5px;
+    border-radius: 5px;
+    word-break: break-all;
+    word-wrap: break-word;
+    color: #000;
+}
+
+.talk-item .msg s.arrow {
+    width: 7px;
+    height: 13px;
+    bottom: 10px;
+    display: block;
+    position: absolute;
+    background: url(../pic/a-direct.png) no-repeat;
+}
+
+.talk-b .msg_fail s.arrow{
+    bottom: 10px;
+    display: block;
+    width: 7px;
+    height: 13px;
+    left: 100%;
+    position: absolute;
+    background: url(../pic/c-direct.png) no-repeat;
+}
+
+.talk-item .msg_fail {
+    padding: 10px;
+    line-height: 180%;
+    max-width: 560px;
+    position: relative;
+    -webkit-border-radius: 5px;
+    -moz-border-radius: 5px;
+    border-radius: 5px;
+    word-break: break-all;
+    word-wrap: break-word;
+    color: #000;
+}
+
+.talk-b .msg_fail{
+    float: right;
+    min-width: 70px;
+    padding: 10px 10px 15px 10px;
+    background: #ffdbdb;
+    border: 1px solid #f46c6c;
+    min-width: 350px;
+}
+
+.msg_fail pre{
+    border: medium none;
+    line-height: 17px;
+    margin: 0;
+    overflow-x: auto;
+    padding: 0;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+    color: #696e72;
+    background: none repeat scroll 0 0 transparent;
+}
+
+#smsChatRoom .error {
+    color: #CC0000;
+}
+
+.info-talk{
+    color: #87acd6;
+}
+
+.talk-a .info-talk {
+    float: left;
+    padding: 0 20% 10px 10px;
+    min-width: 420px;
+    _float: none;
+    _padding-left: 26px;
+}
+
+.talk-a .msg {
+    min-width: 350px;
+    min-height: 20px;
+    border: 1px solid #ccc;
+    background: #eef2f4;
+}
+
+.talk-a .msg s.arrow {
+    left: -7px;
+    _left: -17px;
+}
+
+.talk-b {
+    margin-right: 10px;
+    _margin-right: 20px;
+}
+
+.talk-b .info-talk {
+    float: right;
+    min-width: 420px;
+    padding: 0 10px 10px 20%;
+}
+
+.talk-b .msg {
+    float: right;
+    min-width: 350px;
+    min-height: 20px;
+    border: 1px solid #ADCAE3;
+    padding: 10px 10px 10px 10px;
+    background: #bce3f4;
+}
+
+.talk-c {
+    margin-right: 20px;
+    _margin-right: 30px;
+}
+
+.talk-b .info-talk {
+    float: right;
+    min-width: 420px;
+    padding: 0 10px 10px 20%;
+}
+
+.talk-c .msg {
+    float: right;
+    min-width: 70px;
+    padding: 10px 10px 15px 10px;
+    border: 1px solid #ADCAE3;
+    background: #bce3f4;
+}
+
+.talk-b .msg s.arrow {
+    left: 100%;
+    background: url("../pic/b-direct.png") no-repeat;
+}
+
+#smslist-main .smslist-btns.smsListFloatButs{
+    position: fixed;
+    top: 0;
+    width: 770px;
+    height: 50px;
+    padding: 6px 0 0 0;
+    border: 1px solid #018AD8;
+    display: block;
+    z-index: 9999;
+    background: #F5F9FE;
+    background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F5F9FE), to(#018AD8) );
+    background: -ms-linear-gradient(top, #F5F9FE, #018AD8);
+    background: -moz-linear-gradient(top, #F5F9FE, #018AD8);
+    background: -o-linear-gradient(top, #F5F9FE, #018AD8);
+    filter: progid:dximagetransform.microsoft.gradient(enabled='true', startColorstr='#FFF5F9FE', endColorstr='#FF018AD8', GradientType=0);
+}
+
+#popupSettingWindow .tag-popup-close{
+    height: 0;
+    position: relative;
+    z-index: 2000;
+}
+
+#popupSettingWindow .tag-popup-close a {
+    float: right;
+    display: block;
+    top: 15px;
+    right: 15px;
+    width: 12px;
+    height: 13px;
+    font-size: 1px;
+    background: url("../pic/select-sprite.png") no-repeat scroll right -11px transparent;
+    position: absolute;
+}
+
+#innerTagPopup{
+    z-index: 250;
+    width: 185px;
+    line-height: 130%;
+    border: 1px solid #D4DAE2;
+    border-radius: 5px;
+    position: absolute;
+    background-color: #D4DAE2;
+    box-shadow: 0 -3px 8px #DDDDDD;
+}
+
+#innerTagPopup label.error{
+    color: #CC0000;
+    display: block;
+}
+
+#innerTagPopup .popup-wrapper {
+    background: #fff;
+    border: 2px solid #76b2de;
+    padding: 5px;
+}
+
+#innerTagPopup .tag-popup-close a {
+    float: right;
+    display: block;
+    width: 12px;
+    height: 13px;
+    font-size: 1px;
+    background: url("../pic/select-sprite.png") no-repeat scroll right -11px transparent;
+}
+
+
+#home_control{
+    color: #fff;
+    margin: 4px 0 0;
+}
+
+#home_control #change{
+    color: #ffffff;
+    font-weight: bold;
+    padding: 3px 15px;
+    background-color: transparent;
+}
+
+#home_image{
+    height: 400px;
+    color: #fff;
+}
+
+.label-font-normal label{
+    font-weight: normal;
+}
+
+#showDetailInfo ~ .popover{
+    min-width: 400px;
+}
+
+#showDetailInfo ~ .popover label{
+    font-size: 12px;
+    line-height: 1.5em;
+    word-wrap: break-word;
+}
+
+#h_qrcode {
+    width: 115px;
+    height: 115px;
+    background-color: #ffffff;
+    border: 1px solid #ffffff;
+}
+
+#h_wire_device {
+    top: 38px;
+    left: 130px;
+	display:inline;
+	margin-right:25px;
+    font-size: 30px;
+	display:inline-block;
+}
+
+#h_wireless_device {
+    font-size: 30px;
+    top: 105px;
+    left: 60px;
+	display:inline-block;
+}
+
+#h_network_type{
+    height: 30px;
+    top: 183px;
+    left: 415px;
+    line-height: 30px;
+    text-align: center;
+    font-size: 18px;
+}
+
+.data-card #h_network_type{
+    top: 156px;
+    left: 218px;
+}
+
+#h_network_type.no-btn {
+}
+
+#h_connect_btn{
+    width: 72px;
+    height: 35px;
+    display:inline-block;
+}
+
+.data-card #h_connect_btn{
+    top: 153px;
+    left: 323px;
+}
+
+.h_connect_on{
+    background: url('../pic/dial-on.png') no-repeat scroll 0 0 transparent;
+}
+
+.h_connect_off{
+    background: url('../pic/dial-off.png') no-repeat scroll 0 0 transparent;
+}
+
+#h_internet_setting_div{
+    top: 222px;
+    left: 418px;
+    width: 170px;
+    height: 35px;
+	margin-top:20px;
+    line-height: 35px;
+    text-align: center;
+}
+
+.data-card #h_internet_setting_div{
+    top: 205px;
+    left: 221px;
+}
+
+#h_internet_setting_btn{
+    width: 170px;
+    height: 35px;
+    line-height: 35px;
+    padding-right: 25px;
+    color: #fff;
+    display: block;
+    font-weight: bold;
+}
+
+#h_wifi_setting_div{
+    top: 318px;
+    left: 418px;
+    width: 170px;
+    height: 35px;
+    line-height: 35px;
+    text-align: center;
+}
+
+#h_wifi_setting_btn{
+    width: 170px;
+    height: 35px;
+    line-height: 35px;
+    padding-right: 25px;
+    color: #fff;
+    display: block;
+    font-weight: bold;
+}
+
+#h_connect_status{
+    top: 272px;
+    left: 670px;
+    width: 25px;
+    height: 25px;
+    position: absolute;
+}
+
+.h_status_connected{
+    background: url('../pic/local-connected.png') no-repeat scroll 0 0 transparent;
+}
+
+.h_status_disconnected{
+    background: url('../pic/local-disconnected.png') no-repeat scroll 0 0 transparent;
+}
+
+.h_status_connecting{
+    background: url('../pic/local-connecting.png') no-repeat scroll 0 0 transparent;
+}
+
+.h_status_disconnecting{
+    background: url('../pic/local-disconnecting.png') no-repeat scroll 0 0 transparent;
+}
+
+.color_block{
+    width: 20px;
+    height: 20px;
+    line-height: 20px;
+    border: 1px solid #ccc;
+    vertical-align: middle;
+    display: inline-block;
+}
+
+.color_block_desc{
+    line-height: 20px;
+    vertical-align: middle;
+    margin-left: 8px;
+    display: inline-block;
+}
+
+.colorRed{
+    color: #CC0000;
+}
+
+.msg pre{
+    line-height: 17px;
+    border: none;
+    margin: 0;
+    padding: 0;
+    overflow-x: hidden;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+    color: #696e72;
+    background: none;
+}
+
+.smslist-item-icon {
+    width: 80px;
+    height: 80px;
+    margin-left: 10px;
+    margin-top: -6px;
+}
+
+.smslist-item-name {
+    max-width: 550px;
+    color: #000;
+    display: inline-block;
+    overflow: hidden;
+}
+
+.smslist-item-name2 {
+    color: #000;
+}
+
+.smslist-item-name-draftShowName{
+    display:inline;
+}
+
+.smslist-item-total-count-style{
+    float:left;
+    width:50px;
+    display:inline-block;
+    color:#696e72;
+}
+
+.smslist-item-repeat {
+    font-weight: bold;
+    line-height: 18px;
+    text-indent: 3px;
+    color: #7D8DA3;
+}
+
+.smslist-item-repeat:hover {
+    color: #207DDD;
+}
+
+.smslist-item{
+    border-bottom: 1px solid #e1e1e1;
+    margin-bottom: 10px;
+}
+
+.repeat-icon {
+    width: 18px;
+    height: 18px;
+    display: block;
+    background: url("../pic/png_forward.png") no-repeat;
+}
+
+.repeat-icon:hover {
+    width: 18px;
+    height: 18px;
+    display: block;
+    background: url("../pic/png_forward_hover.png") no-repeat;
+}
+
+.sms-forward-icon {
+    width: 18px;
+    height: 18px;
+    display: block;
+    background: url("../pic/png_forward.png") no-repeat scroll;
+}
+
+.sms-forward-icon:hover {
+    width: 18px;
+    height: 18px;
+    display: block;
+    background: url("../pic/png_forward_hover.png") no-repeat scroll;
+}
+
+.smslist-item-delete {
+    width: 18px;
+    height: 18px;
+    display: block;
+}
+
+.smslist-item-delete:hover {
+    width: 18px;
+    height: 18px;
+    display: block;
+}
+
+.sms-add-contact-icon {
+    width: 13px;
+    height: 13px;
+    display: inline-block;
+    background: url("../pic/png_add_contact.png") no-repeat scroll 0 0 transparent;
+}
+
+.sms-add-contact-icon:hover {
+    width: 13px;
+    height: 13px;
+    display: inline-block;
+    background: url("../pic/png_add_contact_hover.png") no-repeat scroll 0 0 transparent;
+}
+
+.smslist-item-delete:hover .trash-icon {
+    width: 18px;
+    height: 18px;
+    display: block;
+    background: url("../pic/png_delete_hover.png") no-repeat;
+}
+
+.trash-icon {
+    width: 18px;
+    height: 18px;
+    display: block;
+    background: url("../pic/png_delete.png") no-repeat;
+}
+
+.smslist-item-resend {
+    font-weight: bold;
+    line-height: 22px;
+    text-indent: 3px;
+    color: #7D8DA3;
+}
+
+.sms-resend-icon {
+    width: 18px;
+    height: 18px;
+    display: block;
+    background: transparent url("../pic/png_resend1.png") no-repeat;
+}
+
+.smslist-item-resend:hover {
+    color: #207DDD;
+}
+
+.smslist-item-resend:hover .sms-resend-icon{
+    background: transparent url("../pic/png_resend_hover.png") no-repeat;
+}
+
+.clock-icon {
+    width: 18px;
+    height: 30px;
+    line-height: 30px;
+    display: block;
+    background: url("../pic/png_time.png") no-repeat;
+}
+
+.clock-icon:hover {
+    width: 18px;
+    height: 30px;
+    line-height: 30px;
+    display: block;
+    background: url("../pic/png_time.png") no-repeat;
+}
+
+.smslist-item-new-count {
+    width: 29px;
+    height: 35px;
+    line-height: 35px;
+    margin-right: 5px;
+    text-align: center;
+    font-weight: bold;
+    color: #ffffff;
+    background: url("../pic/png_new_sms_bg.png") no-repeat scroll 0 0 transparent;
+}
+
+#mainContainer .width100p {
+    width: 100%;
+}
+
+.height15 {
+    height: 15px;
+    line-height: 15px;
+}
+
+
+label.error{
+    color: #a94442;
+}
+
+#frmPassword label.error {
+    white-space: nowrap;
+}
+
+.form-information{
+    margin-top: 10px;
+}
+
+.form-information p{
+    padding: 15px;
+}
+
+body[lang=en] .label-absolute{
+    height: 40px;
+}
+
+body[lang=en] .label-absolute > label{
+    top: 0;
+    left: 40px;
+    position: absolute;
+}
+
+.ko-grid-pageLinks {
+
+    padding-left: 0;
+    margin: 20px 0;
+    border-radius: 4px;
+    width: 100%;
+    display: inline-block;
+}
+
+.ko-grid-pageLinks > a,
+.ko-grid-pageLinks > span {
+    display: inline;
+    position: relative;
+    float: left;
+    padding: 6px 12px;
+    line-height: 1.42857143;
+    text-decoration: none;
+    color: #008AD7;
+    background-color: #ffffff;
+    border: 1px solid #dddddd;
+    margin-left: -1px;
+}
+
+.ko-grid-pageLinks > a:first-child,
+.ko-grid-pageLinks > span:first-child {
+    margin-left: 0;
+    border-radius: 4px 0 0 4px;
+}
+
+.ko-grid-pageLinks > a:last-child,
+.ko-grid-pageLinks > span:last-child {
+    margin-left: 0;
+    border-radius: 0 4px 4px 0;
+}
+
+.ko-grid-pageLinks > a.ko-grid-pager-selected,
+.ko-grid-pageLinks > span.ko-grid-pager-selected,
+.ko-grid-pageLinks > a.ko-grid-pager-selected:hover,
+.ko-grid-pageLinks > span.ko-grid-pager-selected:hover {
+    z-index: 2;
+    cursor: default;
+    color: #ffffff;
+    background-color: #008AD7;
+    border-color: #008AD7;
+}
+
+.ko-grid-pageLinks > a:hover,
+.ko-grid-pageLinks > span:hover {
+    z-index: 2;
+    background-color: #EEEEEE;
+    border-color: #DDDDDD;
+}
+
+.ko-grid-pageLinks > span.ko-grid-pager-disabled,
+.ko-grid-pageLinks > span.ko-grid-pager-disabled:hover,
+.ko-grid-pageLinks > span.ko-grid-pager-disabled:focus,
+.ko-grid-pageLinks > a.ko-grid-pager-disabled,
+.ko-grid-pageLinks > a.ko-grid-pager-disabled:hover,
+.ko-grid-pageLinks > a.ko-grid-pager-disabled:focus {
+    color: #777777;
+    background-color: #ffffff;
+    border-color: #dddddd;
+    cursor: not-allowed;
+}
+
+.nav-tabs > li > a, .nav-tabs.nav-justified > li > a{
+    -webkit-border-radius: 0;
+    -moz-border-radius: 0;
+    border-radius: 0;
+}
+.nav-tabs > li > a, .nav-tabs > li > a:hover, .nav-tabs > li > a:focus{
+    color: #333333;
+    text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+    background-color: #f5f5f5;
+    *background-color: #e6e6e6;
+    background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+    background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+    background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+    background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+    background-repeat: repeat-x;
+    border: 1px solid #cccccc;
+    *border: 0;
+    border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+    border-bottom-color: #b3b3b3;
+    filter: progid:DXImageTransform.Microsoft.gradient(enabled='true', startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
+    *zoom: 1;
+    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+    -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.nav-tabs > li:first-child > a, .nav-tabs > li:first-child > a:hover, .nav-tabs > li:first-child > a:focus{
+    -webkit-border-radius: 4px 0 0 4px;
+    -moz-border-radius: 4px 0 0 4px;
+    border-radius: 4px 0 0 4px;
+}
+
+.nav-tabs > li:last-child > a, .nav-tabs > li:last-child > a:hover, .nav-tabs > li:last-child > a:focus{
+    -webkit-border-radius: 0 4px 4px 0;
+    -moz-border-radius: 0 4px 4px 0;
+    border-radius: 0 4px 4px 0;
+}
+
+.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus,
+.nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus{
+    color: #ffffff;
+    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+    background-color: #006dcc;
+    *background-color: #0044cc;
+    border-color: #0044cc #0044cc #002a80;
+    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+    background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
+    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
+    background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
+    background-image: -o-linear-gradient(top, #0088cc, #0044cc);
+    background-image: linear-gradient(to bottom, #0088cc, #0044cc);
+    background-repeat: repeat-x;
+    filter: progid:DXImageTransform.Microsoft.gradient(enabled='true', startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
+}
+
+#result-overlay .simplemodal-data, #result-overlay .simplemodal-wrap, #result-overlay .alert{
+    border-radius: 8px;
+    -moz-border-radius: 8px;
+    -webkit-border-radius: 8px;
+    box-shadow: 0 3px 5px #999;
+    -moz-box-shadow: 0 3px 5px #999;
+    -webkit-box-shadow: 0 3px 5px #999;
+}
+
+.form-note .notes-title {
+    height: 30px;
+    cursor: pointer;
+    padding-bottom: 5px;
+    background: url("../pic/res_help.png") no-repeat scroll left center transparent;
+}
+
+.form-note .notes-content {
+    display: none;
+}
+
+.form-note .notes-dot {
+    border-bottom: 1px solid #ffffff;
+}
+
+.form-body .form-note {
+    border-radius: 4px;
+    font-size: 12px;
+    margin-bottom: 10px;
+    margin-top: 20px;
+    padding: 10px;
+    background-color: #ededed;
+}
+
+.form-body .form-note li {
+    line-height: 30px;
+    list-style: none outside none;
+    padding-left: 15px;
+    background: url("../pic/res_point.png") no-repeat scroll 0 12px transparent;
+}
+
+.form-body .form-note li.no-style {
+    background: none;
+}
+
+.border-color-transition {;
+    -moz-transition: border-color .5s ease-in;
+    -webkit-transition: border-color .5s ease-in;
+    -o-transition: border-color .5s ease-in;
+    -ms-transition: border-color .5s ease-in;
+    transition: border-color .5s ease-in;
+}
+
+.attention-focus{
+    border-color: red;
+}
+
+.popover-title{
+    background-color: #eaeaea;
+    border-bottom: 1px solid #cbcbcb;
+}
+
+.fixTableScroll {
+    width:100%;
+    overflow-x:auto;
+    overflow-y:hidden;
+    height:100%;
+    overflow-scrolling: touch;
+}
+
+.fixTableScroll:hover {
+    height:100%;
+}
+
+#h_internet_setting_btn:hover {
+    background-image: url("../pic/internet_setting_hover.png");
+}
+
+#h_wifi_setting_btn:hover {
+    background-image: url("../pic/wlan_setting_hover.jpg");
+}
+
+.connected_devices_container {    
+    float:left;
+    width: 280px;
+	height: 400px;
+	margin-left:20px;
+    text-align: center;
+    border-radius:10px;
+    cursor: pointer;
+	filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr = #70EBE6, endColorstr = #059EC4); 
+	background: -webkit-linear-gradient(left top, #70EBE6 , #059EC4); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom right, #70EBE6 , #059EC4); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom right, #70EBE6 , #059EC4); /* Firefox 3.6 - 15 */
+    background: linear-gradient(to bottom right, #70EBE6 , #059EC4); /* 标准的语法(必须放在最后)*/
+}
+
+.connected_devices_container .item_icon{
+	height: 45%;
+    background: url(../pic/new/device.png) center center no-repeat;
+}
+
+.home_h3{
+    font-size: 25px;
+    -webkit-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    -moz-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    -ms-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);	
+	text-align: center;
+}
+
+.network_control_container {
+    float:left;
+    width: 280px;
+    height: 400px;
+	margin-left:20px;
+	border-radius:10px;
+	filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr = #36A4FF, endColorstr = #0877D4); 
+	background: -webkit-linear-gradient(left top, #36A4FF , #0877D4); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom right, #36A4FF , #0877D4); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom right, #36A4FF , #0877D4); /* Firefox 3.6 - 15 */
+    background: linear-gradient(to bottom right, #36A4FF , #0877D4); /* 标准的语法(必须放在最后)*/
+}
+
+.network_control_container .item_icon{
+	height: 45%;
+    background: url(../pic/new/router.png) center center no-repeat;
+}
+
+.internet_status_container{	
+	float:left;
+    width: 280px;
+    height: 400px;
+	margin-left:60px;
+	border-radius:10px;
+	filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr = #D014FE, endColorstr = #7109D5); 
+	background: -webkit-linear-gradient(left top, #D014FE , #7109D5); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom right, #D014FE , #7109D5); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom right, #D014FE , #7109D5); /* Firefox 3.6 - 15 */
+    background: linear-gradient(to bottom right, #D014FE , #7109D5); /* 标准的语法(必须放在最后)*/	
+	text-align: center;
+}
+
+.internet_status_container .item_icon_connect{
+	height: 45%;
+    background: url(../pic/new/surfing1.png) center center no-repeat;
+}
+
+.internet_status_container .item_icon_disconnect{
+	height: 45%;
+    background: url(../pic/new/surfing2.png) center center no-repeat;
+}
+
+.internet_status_container .data-card{
+    top: 180px;
+    left: 636px;
+}
+
+.traffic_control_container{
+    float:left;
+    width: 280px;
+    height: 280px;
+	margin-left:45px;
+	border-radius:10px;
+	color:#fff;
+	filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr = #FCCA53, endColorstr = #F45406); 
+	background: -webkit-gradient(linear, 0 0, 0 100%, from(#FCCA53), to(#F45406));
+	background: -webkit-linear-gradient(left top, #FCCA53 , #F45406); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom right, #FCCA53 , #F45406); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom right, #FCCA53 , #F45406); /* Firefox 3.6 - 15 */
+	background: -ms-linear-gradient(left, #FCCA53, #F45406);   
+    background: linear-gradient(to bottom right, #FCCA53 , #F45406); /* 标准的语法(必须放在最后)*/
+	
+}
+.device_info_container{
+    float:left;
+    width: 580px;
+    height: 280px;
+	border-radius:10px;
+	filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr = #B454F6, endColorstr = #0096D7); 
+	background: -webkit-linear-gradient(left top, #B454F6 , #0096D7); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom right, #B454F6 , #0096D7); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom right, #B454F6 , #0096D7); /* Firefox 3.6 - 15 */
+    background: linear-gradient(to bottom right, #B454F6 , #0096D7); /* 标准的语法(必须放在最后)*/
+}
+
+.device_info_container_hastraffic{
+    margin-left:20px;
+}
+
+.device_info_container_notraffic{
+    margin-left:210px;
+}
+
+.device_info_container a{
+    padding-right: 2em;
+	margin-right:1em;
+    color: #FFF;
+    background: url(../pic/new/direct.png) right center no-repeat;
+}
+
+
+#smslist-table td{
+    vertical-align: middle;
+    line-height: 1.2;
+}
+
+#simMsgList_container td{
+    vertical-align: middle;
+    line-height: 1.2;
+}
+
+.smslist-item-msg pre{
+    overflow: hidden;
+    text-overflow: ellipsis;
+    border: none;
+    padding: 0;
+    margin:0;
+    font-size: 14px;
+    line-height: 1.2;
+    white-space: nowrap;
+    background-color: transparent;
+    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
+.smslist-btns {
+}
+
+#smsScrollLoading {
+    margin: 25px auto;
+    font-size: 22px;
+    font-weight: bold;
+    text-align: center;
+    color: #7D8DA3;
+}
+
+#smsScrollLoadingBtn {
+    margin: 25px auto;
+    font-size: 22px;
+    font-weight: bold;
+    text-align: center;
+    color: #7D8DA3;
+    cursor: pointer;
+}
+
+#smslist_container{
+    position: relative;
+}
+
+#smslist_container table,#smslist_container table td,#smslist_container table th {
+    padding: 0;
+    margin: 0;
+    border: none;
+}
+
+.smslist-item-checkbox{float: left; width: 20px;}
+.chosen-container-multi .chosen-choices li.search-field input[type="text"]{
+    height: auto;
+}
+
+.sms-table-content{
+    width: 450px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.showFullHeight{
+    white-space: normal;
+}
+
+#buttom-bubble{
+    width: 230px;
+    height: auto;
+    right: 0;
+    bottom: 0;
+    margin-right: 10px;
+    position: fixed;
+    z-index: 100;
+}
+
+#buttom-bubble .bubbleItem{
+    margin-top: 8px;
+    border-radius: 10px 10px 0 0;
+    position: relative;
+}
+
+#buttom-bubble h3{
+    padding: 8px 30px 8px 8px;
+    background-color: #eaeaea;
+    border: 2px solid #eaeaea;
+    border-bottom: 0;
+    border-radius: 8px 8px 0 0;
+    margin-bottom: 0;
+    font-size: 14px;
+}
+
+#buttom-bubble .bubbleItem.report h3{
+    color: #E47602;
+}
+
+#buttom-bubble h3 a.bubbleCloseBtn{
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    border: 1px solid #E2E2E2;
+    -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
+    -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
+    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
+}
+
+#buttom-bubble h3 a.bubbleCloseBtn:hover{
+    border: 1px solid #2063AB;
+}
+
+#buttom-bubble .bubbleCloseBtn{
+    width: 16px;
+    height: 14px;
+    display: block;
+    background: url("../pic/res_delete.png");
+}
+
+#buttom-bubble .bubbleContainer{
+    border: 2px solid #E2E2E2;
+    padding: 2px 8px 8px 8px;
+    line-height: 150%;
+    overflow: hidden;
+    border-top: 0;
+    font-size: 12px;
+    background: #F2F2F2;
+    background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(white), to(#eaeaea) );
+    background: -ms-linear-gradient(top, white, #eaeaea);
+    background: -moz-linear-gradient(top, white, #eaeaea);
+    background: -o-linear-gradient(top, white,#eaeaea);
+    filter: progid:dximagetransform.microsoft.gradient(enabled='true', startColorstr='#FFFFFFFF', endColorstr='#ffeaeaea', GradientType=0);
+}
+
+#buttom-bubble .bubbleContent{
+    max-height: 55px;
+    overflow: hidden;
+    line-height: 18px;
+    word-break: break-all;
+    word-wrap: break-word;
+}
+
+#buttom-bubble .bubbleDatetime{
+    padding-right: 10px;
+    text-align: right;
+    font-size: 10px;
+}
+
+#topContainer{
+    padding-top: 10px;
+    padding-bottom: 10px;
+    background-color: #EAEAEA;
+}
+
+.login-page-bg{
+    background: url("../pic/res_login-bg.png") repeat-x scroll 0 0 transparent;
+}
+
+#login-form-container{
+    border: 1px solid gray;
+    border-radius: 8px;
+    -moz-border-radius: 8px;
+    -webkit-border-radius: 8px;
+    background-color: white;
+    box-shadow: 0 3px 5px #053984;
+    -moz-box-shadow: 0 3px 5px #053984;
+    -webkit-box-shadow: 0 3px 5px #053984;
+}
+
+#htmlContainer{
+    padding: 0;
+}
+
+#htmlContainer .form-title{
+    padding: 10px 15px 10px 15px;
+    margin-bottom: 0;
+    border-bottom: 1px solid #cbcbcb;
+    background-color: #eaeaea;
+}
+
+#htmlContainer .content{
+    padding: 15px;
+}
+
+#simplemodal-data .alert{
+    border: 1px solid gray;
+    border-radius: 8px;
+    box-shadow: 0 6px 10px #053984;
+    width: 400px;
+    height: 150px;
+    background-color: white;
+}
+
+.btn-primary{
+    background-color: #008AD7;
+}
+
+#pblist tr td {
+    cursor: pointer;
+}
+
+#pblist tr td:first-child {
+    cursor: default;
+}
+
+.form-buttons {
+    margin-right: 20px;
+    margin-bottom: 5px;
+    text-align: right;
+}
+
+.align-right {
+    text-align: right;
+}
+
+.margin-right-10 {
+    margin-right: 10px;
+}
+
+.beautiful_bg #indexContainer{
+}
+
+.header-row {
+    background-color: #018ad8;
+    border-left-width: 0;
+    border-radius: 10px 10px 0 0;
+    margin: -1px 0 30px -11px;
+    width: 940px;
+    color: white;
+	filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr = #B454F6, endColorstr = #0096D7); 
+	background: -webkit-gradient(linear, 0 0, 0 100%, from(#B454F6), to(#0096D7));
+	background: -webkit-linear-gradient(left top, #B454F6 , #0096D7); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom right, #B454F6 , #0096D7); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom right, #B454F6 , #0096D7); /* Firefox 3.6 - 15 */	
+	background: -ms-linear-gradient(left, #B454F6, #0096D7);
+    background: linear-gradient(to bottom right, #B454F6  , #0096D7); /* 标准的语法(必须放在最后)*/
+}
+
+.header-row .form-title {
+    border: none;
+    margin-bottom: 0;
+	text-align:center;
+}
+
+#innerContainer {
+    width: 100%;
+    margin: 35px auto;
+    padding: 0 10px 20px 10px;
+    border: 1px solid #fff;
+	border-bottom:0px;
+    border-radius: 10px;
+	background: -webkit-linear-gradient(top, #F1F9FC , #fff); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom, #F1F9FC , #fff); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom, #F1F9FC , #fff); /* Firefox 3.6 - 15 */
+    background: linear-gradient(to bottom, #F1F9FC , #fff); /* 标准的语法(必须放在最后)*/
+	}
+
+.form-title-multi h1 {
+    margin-top: 10px;
+    margin-bottom: 5px;
+}
+
+.form-title-multi p {
+    margin-bottom: 0;
+}
+.mobile_version_link{
+    color: #A0AFCB;
+}
+
+#opmode_form .content {
+    background-color: #FFFFFF;
+}
+
+#sms_unread_count a:hover {
+    text-decoration: none;
+}
+
+.customfile-input {
+    outline: none;
+    position: absolute;
+    height: 100px;
+    cursor: pointer;
+    background: transparent;
+    border: 0;
+    z-index: 999;
+    opacity: 0;
+    -moz-opacity: 0;
+    filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0 );
+}
+
+.customfile {
+    width: 400px;
+    padding: 2px;
+    border: 1px solid #444;
+    line-height: 30px;
+    background: #FAFAFA;
+    background: -ms-linear-gradient(#FAFAFA, #CACACA);
+    background: -moz-linear-gradient(#FAFAFA, #CACACA);
+    background : -webkit-linear-gradient( #FAFAFA, #EAEAEA);
+    cursor: pointer;
+    overflow: hidden;
+    -moz-border-radius: 7px;
+    -webkit-border-radius: 7px;
+    border-radius: 7px;
+    position: relative;
+    float: left;
+}
+
+.customfile-disabled {
+    opacity: .5;
+    filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0 );
+    cursor: default;
+}
+
+.customfile-feedback {
+    display: block;
+    margin: 1px 1px 1px 5px;
+    font-size: 1.2em;
+    color: #767676;
+    font-style: italic;
+}
+
+.customfile-feedback-populated {
+    color: #111;
+    padding-left: 20px;
+    line-height: 24px;
+    margin-top: 6px;
+    width:290px;
+    font-style: normal;
+    font-weight: bold;
+    background: url(../pic/pic-file.png) left 0px no-repeat;
+    white-space:nowrap;
+    display: block;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.customfile-button {
+    border: 1px solid #999;
+    background-color: #008AD7;
+    color: #fff;
+    float: right;
+    padding: 0px 10px;
+    text-align: center;
+    text-decoration: none;
+    font-size: 1em;
+    -moz-border-radius: 5px;
+    -webkit-border-radius: 5px;
+    border-radius: 5px;
+}
+
+.customfile-hover .customfile-button,.customfile-focus .customfile-button {
+    background-color: #3071A9;
+    border-color: #285E8E;
+    padding: 0px 10px;
+    color: #fff;
+}
+
+.customfile-focus .customfile-button {
+    outline: 1px dotted #ccc;
+}
+
+/*file type icons*/
+.customfile-ext-jpg, .customfile-ext-gif, .customfile-ext-png, .customfile-ext-jpeg, .customfile-ext-bmp { background-image: url(../pic/pic-picture.png);}
+.customfile-ext-mp4, .customfile-ext-mov, .customfile-ext-swf, .customfile-ext-m4v { background-image: url(../pic/pic-film.png);}
+.customfile-ext-mp3, .customfile-ext-wav { background-image: url(../pic/pic-mp3.png);}
+.customfile-ext-zip, .customfile-ext-tar, .customfile-ext-sit { background-image: url(../pic/pic-rar.png);}
+
+input[type='file']:focus{
+    outline: none;
+}
+
+#smslist-checkAll, #simMsgList-checkAll {
+    margin-left: -4px;
+}
+
+.not-allowed {
+    color: #D1D1D1 !important;
+    cursor: not-allowed;
+}
+
+.not-allowed:hover {
+    outline: 0;
+    text-decoration: none;
+}
+
+.not-allowed:focus {
+    outline: 0;
+    text-decoration: none;
+}
+
+.margin-top-5 {
+    margin-top: 5px;
+}
+
+.colorLightBlue{
+    color: #09F;
+}
+
+.sd_invalid_notes ul li{
+    height: 2em;
+    line-height: 2em;
+}
+
+.sd_invalid_notes .notes-content{
+    display: block;
+}
+
+#fileControlSection li {
+    list-style: outside none none;
+    display: inline;
+}
+
+
+.my_router_list,.net_surfing_list{
+    margin-top: 20px;
+}
+
+.my_router_list ul,.net_surfing_list ul,.statistics_list ul,.nav_right ul{
+    -webkit-padding-start: 0px;
+	margin:0px;
+	padding:0px;
+}
+
+.my_router_list li,.net_surfing_list li,.statistics_list li{
+    padding: 0 1em;
+	list-style:none;
+}
+
+.my_router_list li,.my_router_list li a,.net_surfing_list li{
+    text-align: left;
+    line-height: 2em;
+    font-size: 18px;
+
+}
+
+.my_router_list li a{
+    display: block;
+    color: #FFF;
+    background: url(../pic/new/direct.png) right center no-repeat;
+    -webkit-transition: all ease-in .3s;
+    -moz-transition: all ease-in .3s;
+    -ms-transition: all ease-in .3s;
+    transition: all ease-in .3s;
+}
+
+.my_router_list li a:hover{
+    color: #FAFAFA;
+    -webkit-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    -moz-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    -ms-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+}
+
+.net_surfing_list li{
+    text-align: center;
+}
+
+.net_surfing_list i{
+    display: inline-block;
+    width: 17px;
+    height: 24px;
+    margin-right: 15px;
+    vertical-align: middle;
+}
+
+.net_surfing_list i.up{
+    background: url(../pic/new/direct_top.png);
+}
+
+.net_surfing_list i.down{
+    background: url(../pic/new/direct_down.png);
+}
+
+.statistics_list ul li{
+    padding: 0 20px;
+    text-align: left;
+    margin-top: 15px;
+	font-size:18px;
+}
+
+.statistics_list ul li a{
+    color: #FFF;
+    display: block;
+    background: url(../pic/new/direct.png) right center no-repeat;
+    -webkit-transition: all ease-in .3s;
+    -moz-transition: all ease-in .3s;
+    -ms-transition: all ease-in .3s;
+    transition: all ease-in .3s;
+}
+
+.statistics_list ul li a:hover{
+    -webkit-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    -moz-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    -ms-text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+    text-shadow: 0px 1px 2px rgba(100, 100, 10, 0.5);
+}
+
+.type_items{
+	width:880px;
+    height: 100px;
+    text-align: center;
+	margin:0 0 0 45px;
+    -webkit-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -moz-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -ms-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -webkit-border-radius: 8px;
+    -moz-border-radius: 8px;
+    -ms-border-radius: 8px;
+    border-radius: 10px;	
+	filter: progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr = #B454F6, endColorstr = #0096D7); 
+	background: -webkit-linear-gradient(left top, #B454F6 , #0096D7); /* Safari 5.1 - 6.0 */
+    background: -o-linear-gradient(bottom right, #B454F6 , #0096D7); /* Opera 11.1 - 12.0 */
+    background: -moz-linear-gradient(bottom right, #B454F6 , #0096D7); /* Firefox 3.6 - 15 */
+    background: linear-gradient(to bottom right, #B454F6 , #0096D7); /* 标准的语法(必须放在最后)*/
+}
+
+.type_items ul{
+    width: auto;
+	-webkit-padding-start: 0px;
+	margin:0px;
+	padding:0px;
+}
+
+.type_items ul li{
+    display: inline-block;
+	float:left;
+	list-style:none;
+}
+
+.type_items a{
+    display: table-cell;
+    width: 125px;
+    height: 100px;
+    color: #FFF;
+    vertical-align: middle;
+    -webkit-transition: all ease-in .3s;
+    -moz-transition: all ease-in .3s;
+    -ms-transition: all ease-in .3s;
+    transition: all ease-in .3s;
+    border-left: 1px solid;
+}
+
+.type_items a,.nav_right a:hover{
+    -webkit-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -moz-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -ms-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+}
+
+.nav_right{
+    margin: 0 auto 0px -10px;
+    text-align: center;	
+    
+}
+
+.nav_right ul{
+    width: auto;
+    margin: 0 auto;
+}
+
+.nav_right ul li{
+    margin: 15px 20px 0 0;
+	width:100%;
+	list-style:none;
+}
+
+.nav_right .active a{
+    display: table-cell;
+    width: 138px;
+    height: 50px;
+    color: #fff;
+	font-weight:bold;
+    vertical-align: middle;
+    -webkit-transition: all ease-in .3s;
+    -moz-transition: all ease-in .3s;
+    -ms-transition: all ease-in .3s;
+    transition: all ease-in .3s;
+	-webkit-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -moz-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -ms-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    box-shadow: 0px 8px 10px rgba(172, 172, 172, 0.5);
+    background-color:rgb(66, 153, 237);	
+}
+
+.nav_right a{
+    width: 138px;
+    height: 50px;
+    display: table-cell;
+    color: #000;
+    vertical-align: middle;
+    -webkit-transition: all ease-in .3s;
+    -moz-transition: all ease-in .3s;
+    -ms-transition: all ease-in .3s;
+    transition: all ease-in .3s;
+	-webkit-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -moz-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    -ms-box-shadow: 0px 2px 4px rgba(172, 172, 172, 0.5);
+    box-shadow: 0px 8px 10px rgba(172, 172, 172, 0.5);
+    background-color:rgb(182, 214, 232);	
+}
+
+.sd-total {
+    text-align: right;
+    padding-right: 20px;
+}
+
+.icon-folder{
+    background: url("../pic/pic-folder.png") no-repeat;
+}
+
+.icon-pdf{
+    background: url("../pic/pic-pdf.png") no-repeat;
+}
+
+.icon-rar{
+    background: url("../pic/pic-rar.png") no-repeat;
+}
+
+.icon-mp3{
+    background: url("../pic/pic-mp3.png") no-repeat;
+}
+
+.icon-file{
+    background: url("../pic/pic-file.png") no-repeat;
+}
+
+.icon-film{
+    background: url("../pic/pic-film.png") no-repeat;
+}
+
+.icon-picture{
+    background: url("../pic/pic-picture.png") no-repeat;
+}
+
+.icon-doc{
+    background: url("../pic/pic-doc.png") no-repeat;
+}
+
+.icon-ppt{
+    background: url("../pic/pic-ppt.png") no-repeat;
+}
+
+.icon-xls{
+    background: url("../pic/pic-xls.png") no-repeat;
+}
+
+.icon-xml{
+    background: url("../pic/pic-xml.png") no-repeat;
+}
+
+.icon-download{
+    background: url("../pic/pic-download.png") no-repeat;
+}
+
+.mini-icon{
+    width: 20px;
+    height: 20px;
+    font-size: 16px;
+    display: block;
+}
+
+.cursor-pointer {
+    cursor: pointer;
+}
+
+#fileListSection th {
+    text-align: center;
+}
+
+.margin-left-5 {
+    margin-left: 5px;
+}
+
+.margin-top-2 {
+    margin-top: 2px;
+}
+
+.push-right {
+    text-align: right;
+}
+
+.data-card-language {
+    top: -25px;
+    right: 10px;
+    position: absolute;
+    display: block;
+}
diff --git a/ap/app/zte_webui_min/css/csn.css b/ap/app/zte_webui_min/css/csn.css
new file mode 100755
index 0000000..6b46b0a
--- /dev/null
+++ b/ap/app/zte_webui_min/css/csn.css
@@ -0,0 +1,482 @@
+/* @group Multi Chosen */
+.chosen-container-multi .chosen-choices li {
+  float: left;
+  list-style: none;
+}
+
+.chosen-container-multi .chosen-choices {
+  position: relative;
+  overflow: hidden;
+  margin: 0;
+  padding: 0 5px;
+  width: 100%;
+  height: auto;
+  border: 1px solid #aaa;
+  background-color: #fff;
+  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
+  background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
+  background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
+  background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
+  background-image: linear-gradient(#eeeeee 1%, #ffffff 15%);
+  cursor: text;
+}
+
+.chosen-container-multi .chosen-choices li.search-field {
+  margin: 0;
+  padding: 0;
+  white-space: nowrap;
+}
+
+.chosen-container-multi .chosen-choices li.search-choice {
+  position: relative;
+  margin: 3px 5px 3px 0;
+  padding: 3px 20px 3px 5px;
+  border: 1px solid #aaa;
+  max-width: 100%;
+  border-radius: 3px;
+  background-color: #eeeeee;
+  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
+  background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  background-size: 100% 19px;
+  background-repeat: repeat-x;
+  background-clip: padding-box;
+  box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+  color: #333;
+  line-height: 13px;
+  cursor: default;
+}
+
+.chosen-container-multi .chosen-choices li.search-field input[type="text"] {
+  margin: 1px 0;
+  padding: 5px;
+  height: 25px;
+  outline: 0;
+  border: 0 !important;
+  background: transparent !important;
+  box-shadow: none;
+  color: #999;
+  font-size: 100%;
+  font-family: sans-serif;
+  line-height: normal;
+  border-radius: 0;
+}
+
+.chosen-container-multi .chosen-choices li.search-choice span {
+  word-wrap: break-word;
+}
+
+.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
+  background-position: -42px -10px;
+}
+
+.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
+  position: absolute;
+  top: 4px;
+  right: 3px;
+  display: block;
+  width: 12px;
+  height: 12px;
+  background: url('../pic/select-sprite.png') -42px 1px no-repeat;
+  font-size: 1px;
+}
+
+.chosen-container-multi .chosen-choices li.search-choice-focus {
+  background: #d4d4d4;
+}
+
+.chosen-container-multi .chosen-choices li.search-choice-disabled {
+  padding-right: 5px;
+  border: 1px solid #ccc;
+  background-color: #e4e4e4;
+  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
+  background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
+  color: #666;
+}
+
+.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close {
+  background-position: -42px -10px;
+}
+
+.chosen-container-multi .chosen-drop .result-selected {
+  display: list-item;
+  color: #ccc;
+  cursor: default;
+}
+
+.chosen-container-multi .chosen-results {
+  margin: 0;
+  padding: 0;
+}
+/* @end */
+
+/* @group Single Chosen */
+.chosen-container-single .chosen-default {
+  color: #999;
+}
+
+.chosen-container-single .chosen-single {
+  position: relative;
+  display: block;
+  overflow: hidden;
+  padding: 0 0 0 8px;
+  height: 25px;
+  border: 1px solid #aaa;
+  border-radius: 5px;
+  background-color: #fff;
+  background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4));
+  background: -webkit-linear-gradient(#ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+  background: -moz-linear-gradient(#ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+  background: -o-linear-gradient(#ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+  background: linear-gradient(#ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
+  background-clip: padding-box;
+  box-shadow: 0 0 3px white inset, 0 1px 1px rgba(0, 0, 0, 0.1);
+  color: #444;
+  text-decoration: none;
+  white-space: nowrap;
+  line-height: 24px;
+}
+
+.chosen-container-single .chosen-single span {
+  display: block;
+  overflow: hidden;
+  margin-right: 26px;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.chosen-container-single .chosen-single abbr {
+  position: absolute;
+  top: 6px;
+  right: 26px;
+  display: block;
+  width: 12px;
+  height: 12px;
+  background: url('../pic/select-sprite.png') -42px 1px no-repeat;
+  font-size: 1px;
+}
+
+.chosen-container-single .chosen-single-with-deselect span {
+  margin-right: 38px;
+}
+
+.chosen-container-single.chosen-disabled .chosen-single abbr:hover {
+  background-position: -42px -10px;
+}
+
+.chosen-container-single .chosen-single abbr:hover {
+  background-position: -42px -10px;
+}
+
+.chosen-container-single .chosen-single div b {
+  display: block;
+  width: 100%;
+  height: 100%;
+  background: url('../pic/select-sprite.png') no-repeat 0px 2px;
+}
+
+.chosen-container-single .chosen-single div {
+  position: absolute;
+  top: 0;
+  right: 0;
+  display: block;
+  width: 18px;
+  height: 100%;
+}
+
+.chosen-container-single .chosen-search input[type="text"] {
+  margin: 1px 0;
+  padding: 4px 20px 4px 5px;
+  width: 100%;
+  height: auto;
+  outline: 0;
+  border: 1px solid #aaa;
+  background: white url('../pic/select-sprite.png') no-repeat 100% -20px;
+  background: url('../pic/select-sprite.png') no-repeat 100% -20px;
+  font-size: 1em;
+  font-family: sans-serif;
+  line-height: normal;
+  border-radius: 0;
+}
+
+.chosen-container-single .chosen-search {
+  position: relative;
+  z-index: 1010;
+  margin: 0;
+  padding: 3px 4px;
+  white-space: nowrap;
+}
+
+.chosen-container-single.chosen-container-single-nosearch .chosen-search {
+  position: absolute;
+  left: -9999px;
+}
+
+.chosen-container-single .chosen-drop {
+  margin-top: -1px;
+  border-radius: 0 0 4px 4px;
+  background-clip: padding-box;
+}
+/* @end */
+
+/* @group Active  */
+.chosen-container-active.chosen-with-drop .chosen-single div {
+  border-left: none;
+  background: transparent;
+}
+.chosen-container-active.chosen-with-drop .chosen-single div b {
+  background-position: -18px 2px;
+}
+
+.chosen-container-active .chosen-single {
+  border: 1px solid #5897fb;
+  box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+}
+
+.chosen-container-active.chosen-with-drop .chosen-single {
+  border: 1px solid #aaa;
+  -moz-border-radius-bottomright: 0;
+  border-bottom-right-radius: 0;
+  -moz-border-radius-bottomleft: 0;
+  border-bottom-left-radius: 0;
+  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
+  background-image: -webkit-linear-gradient(#eeeeee 20%, #ffffff 80%);
+  background-image: -moz-linear-gradient(#eeeeee 20%, #ffffff 80%);
+  background-image: -o-linear-gradient(#eeeeee 20%, #ffffff 80%);
+  background-image: linear-gradient(#eeeeee 20%, #ffffff 80%);
+  box-shadow: 0 1px 0 #fff inset;
+}
+
+.chosen-container-active .chosen-choices li.search-field input[type="text"] {
+  color: #222 !important;
+}
+
+.chosen-container-active .chosen-choices {
+  border: 1px solid #5897fb;
+  box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+}
+/* @end */
+
+/* @group Right to Left */
+.chosen-rtl .chosen-single-with-deselect span {
+  margin-left: 38px;
+}
+.chosen-rtl .chosen-single div {
+  right: auto;
+  left: 3px;
+}
+.chosen-rtl .chosen-single abbr {
+  right: auto;
+  left: 26px;
+}
+.chosen-rtl .chosen-choices li {
+  float: right;
+}
+.chosen-rtl .chosen-choices li.search-field input[type="text"] {
+  direction: rtl;
+}
+.chosen-rtl .chosen-choices li.search-choice {
+  margin: 3px 5px 3px 0;
+  padding: 3px 5px 3px 19px;
+}
+.chosen-rtl .chosen-choices li.search-choice .search-choice-close {
+  right: auto;
+  left: 4px;
+}
+
+.chosen-rtl {
+  text-align: right;
+}
+
+.chosen-rtl .chosen-single {
+  overflow: visible;
+  padding: 0 8px 0 0;
+}
+
+.chosen-rtl .chosen-single span {
+  margin-right: 0;
+  margin-left: 26px;
+  direction: rtl;
+}
+
+.chosen-rtl.chosen-container-single-nosearch .chosen-search,
+.chosen-rtl .chosen-drop {
+  left: 9999px;
+}
+.chosen-rtl.chosen-container-single .chosen-results {
+  margin: 0 0 4px 4px;
+  padding: 0 4px 0 0;
+}
+.chosen-rtl .chosen-results li.group-option {
+  padding-right: 15px;
+  padding-left: 0;
+}
+.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div {
+  border-right: none;
+}
+.chosen-rtl .chosen-search input[type="text"] {
+  padding: 4px 5px 4px 20px;
+  background: white url('../pic/select-sprite.png') no-repeat -30px -20px;
+  background: url('../pic/select-sprite.png') no-repeat -30px -20px;
+  direction: rtl;
+}
+.chosen-rtl.chosen-container-single .chosen-single div b {
+  background-position: 6px 2px;
+}
+.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b {
+  background-position: -12px 2px;
+}
+/* @end */
+
+/* @group Results */
+.chosen-container .chosen-results li {
+  display: none;
+  margin: 0;
+  padding: 5px 6px;
+  list-style: none;
+  line-height: 15px;
+  word-wrap: break-word;
+  -webkit-touch-callout: none;
+}
+.chosen-container .chosen-results li.active-result {
+  display: list-item;
+  cursor: pointer;
+}
+
+.chosen-container .chosen-results li.highlighted {
+  background-color: #3875d7;
+  background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
+  background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%);
+  background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%);
+  background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%);
+  background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
+  color: #fff;
+}
+
+.chosen-container .chosen-results li.disabled-result {
+  display: list-item;
+  color: #ccc;
+  cursor: default;
+}
+
+.chosen-container .chosen-results li.group-result {
+  display: list-item;
+  font-weight: bold;
+  cursor: default;
+}
+
+.chosen-container .chosen-results li.group-option {
+  padding-left: 15px;
+}
+
+.chosen-container .chosen-results li.no-results {
+  color: #777;
+  display: list-item;
+  background: #f4f4f4;
+}
+
+.chosen-container .chosen-results li em {
+  font-style: normal;
+  text-decoration: underline;
+}
+
+.chosen-container .chosen-results {
+  color: #444;
+  position: relative;
+  overflow-x: hidden;
+  overflow-y: auto;
+  margin: 0 4px 4px 0;
+  padding: 0 0 0 4px;
+  max-height: 240px;
+  -webkit-overflow-scrolling: touch;
+}
+/* @end */
+
+/* @group Disabled Support */
+.chosen-disabled .chosen-choices .search-choice .search-choice-close {
+  cursor: default;
+}
+
+.chosen-disabled .chosen-single {
+  cursor: default;
+}
+
+.chosen-disabled {
+  opacity: 0.5 !important;
+  cursor: default;
+}
+/* @end */
+
+/* @group Base */
+.chosen-container * {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+
+.chosen-container.chosen-with-drop .chosen-drop {
+  left: 0;
+}
+
+.chosen-container {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle;
+  font-size: 13px;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.chosen-container .search-choice .group-name:after, .chosen-container .chosen-single .group-name:after {
+  content: ":";
+  padding-left: 2px;
+  vertical-align: top;
+}
+
+.chosen-container .chosen-drop {
+  position: absolute;
+  top: 100%;
+  left: -9999px;
+  z-index: 1010;
+  width: 100%;
+  border: 1px solid #aaa;
+  border-top: 0;
+  background: #fff;
+  box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
+}
+
+.chosen-container a {
+  cursor: pointer;
+}
+
+.chosen-container .search-choice .group-name, .chosen-container .chosen-single .group-name {
+  margin-right: 4px;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  font-weight: normal;
+  color: #999999;
+}
+/* @end */
+
+/* @group Retina compatibility */
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) {
+  .chosen-rtl .chosen-search input[type="text"],
+  .chosen-container-single .chosen-single abbr,
+  .chosen-container-single .chosen-single div b,
+  .chosen-container-single .chosen-search input[type="text"],
+  .chosen-container-multi .chosen-choices .search-choice .search-choice-close,
+  .chosen-container .chosen-results-scroll-down span,
+  .chosen-container .chosen-results-scroll-up span {
+    background-image: url('../pic/select-sprite@2x.png') !important;
+    background-size: 52px 37px !important;
+    background-repeat: no-repeat !important;
+  }
+}
+/* @end */
diff --git a/ap/app/zte_webui_min/css/jqui.css b/ap/app/zte_webui_min/css/jqui.css
new file mode 100755
index 0000000..dbdbc96
--- /dev/null
+++ b/ap/app/zte_webui_min/css/jqui.css
@@ -0,0 +1,7 @@
+/* jQuery UI - v1.11.1 - 2014-09-03
+* http://jqueryui.com
+* Includes: core.css, slider.css, theme.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=%22Helvetica%20Neue%22%2CHelvetica%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=%230073ea&bgTextureHeader=highlight_soft&bgImgOpacityHeader=50&borderColorHeader=%23dddddd&fcHeader=%23FFFFFF&iconColorHeader=%23FFF&bgColorContent=%23ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=%23dddddd&fcContent=%23444444&iconColorContent=%23ff0084&bgColorDefault=%23f6f6f6&bgTextureDefault=highlight_soft&bgImgOpacityDefault=100&borderColorDefault=%23dddddd&fcDefault=%230073ea&iconColorDefault=%23666666&bgColorHover=%230073ea&bgTextureHover=highlight_soft&bgImgOpacityHover=25&borderColorHover=%230073ea&fcHover=%23ffffff&iconColorHover=%23ffffff&bgColorActive=%23ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=%23dddddd&fcActive=%23000&iconColorActive=%23454545&bgColorHighlight=%23ffffff&bgTextureHighlight=flat&bgImgOpacityHighlight=55&borderColorHighlight=%23cccccc&fcHighlight=%23444444&iconColorHighlight=%230073ea&bgColorError=%23ffffff&bgTextureError=flat&bgImgOpacityError=55&borderColorError=%23ff0084&fcError=%23222222&iconColorError=%23ff0084&bgColorOverlay=%23eeeeee&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=80&bgColorShadow=%23aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=60&thicknessShadow=4px&offsetTopShadow=-4px&offsetLeftShadow=-4px&cornerRadiusShadow=0px
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-widget{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#fff url("images/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x;color:#444}.ui-widget-content a{color:#444}.ui-widget-header{border:1px solid #ddd;background:#0073ea url("images/ui-bg_highlight-soft_50_0073ea_1x100.png") 50% 50% repeat-x;color:#FFF;font-weight:bold}.ui-widget-header a{color:#FFF}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ddd;background:#f6f6f6 url("images/ui-bg_highlight-soft_100_f6f6f6_1x100.png") 50% 50% repeat-x;font-weight:bold;color:#0073ea}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#0073ea;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #0073ea;background:#0073ea url("images/ui-bg_highlight-soft_25_0073ea_1x100.png") 50% 50% repeat-x;font-weight:bold;color:#fff}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#fff;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #ddd;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#000}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#000;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #ccc;background:#fff url("images/ui-bg_flat_55_ffffff_40x100.png") 50% 50% repeat-x;color:#444}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#444}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #ff0084;background:#fff url("images/ui-bg_flat_55_ffffff_40x100.png") 50% 50% repeat-x;color:#222}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#222}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#222}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_ff0084_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_FFF_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_666666_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_454545_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_0073ea_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ff0084_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#eee url("images/ui-bg_flat_0_eeeeee_40x100.png") 50% 50% repeat-x;opacity:.8;filter:Alpha(Opacity=80)}.ui-widget-shadow{margin:-4px 0 0 -4px;padding:4px;background:#aaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;opacity:.6;filter:Alpha(Opacity=60);border-radius:0}
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/favicon.ico b/ap/app/zte_webui_min/favicon.ico
new file mode 100755
index 0000000..6f48c63
--- /dev/null
+++ b/ap/app/zte_webui_min/favicon.ico
Binary files differ
diff --git a/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.eot b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.eot
new file mode 100755
index 0000000..4a4ca86
--- /dev/null
+++ b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.svg b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.svg
new file mode 100755
index 0000000..e3e2dc7
--- /dev/null
+++ b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph />
+<glyph />
+<glyph unicode="&#xd;" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#x2000;" horiz-adv-x="652" />
+<glyph unicode="&#x2001;" horiz-adv-x="1304" />
+<glyph unicode="&#x2002;" horiz-adv-x="652" />
+<glyph unicode="&#x2003;" horiz-adv-x="1304" />
+<glyph unicode="&#x2004;" horiz-adv-x="434" />
+<glyph unicode="&#x2005;" horiz-adv-x="326" />
+<glyph unicode="&#x2006;" horiz-adv-x="217" />
+<glyph unicode="&#x2007;" horiz-adv-x="217" />
+<glyph unicode="&#x2008;" horiz-adv-x="163" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="326" />
+<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
+<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
+<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
+<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
+<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
+<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
+<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
+<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
+<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
+<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
+<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
+<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
+<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
+<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
+<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
+<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
+<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
+<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
+<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
+<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
+<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
+<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
+<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
+<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
+<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
+<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
+<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
+<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
+<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
+<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
+<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
+<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
+<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
+<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
+<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
+<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
+<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
+<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
+<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
+<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
+<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
+<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
+<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
+<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
+<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
+<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
+<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
+<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
+<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
+<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
+<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
+<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
+<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
+<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
+<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
+<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
+<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
+<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
+<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
+<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
+<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
+<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
+<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
+<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
+<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
+<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
+<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
+<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
+<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
+<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
+<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
+<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
+<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
+<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
+<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
+<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
+<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
+<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
+<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
+<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
+<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
+<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
+<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
+<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
+<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
+<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
+<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
+<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
+<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
+<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
+<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
+<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
+<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
+<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
+<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
+<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
+<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
+<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
+<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
+<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
+<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
+<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
+<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
+<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
+<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
+<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
+<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
+<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
+<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
+<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
+<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
+<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
+<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
+<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
+<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
+<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
+<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
+<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
+<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
+<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
+<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
+<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
+<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
+<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
+<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
+<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
+<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
+<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
+<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
+<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
+<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
+<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
+<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
+<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
+<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
+<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
+<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
+<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
+<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
+<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
+<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
+<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
+<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
+<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
+<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
+<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
+<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
+<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
+<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
+<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
+<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
+<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
+<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
+<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
+<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
+<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
+<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
+<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
+<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
+<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
+<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
+<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
+<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
+<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
+<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
+<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
+<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.ttf b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.ttf
new file mode 100755
index 0000000..67fa00b
--- /dev/null
+++ b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.woff b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.woff
new file mode 100755
index 0000000..8c54182
--- /dev/null
+++ b/ap/app/zte_webui_min/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/ap/app/zte_webui_min/i18n/Messages_en.properties b/ap/app/zte_webui_min/i18n/Messages_en.properties
new file mode 100755
index 0000000..2a581dc
--- /dev/null
+++ b/ap/app/zte_webui_min/i18n/Messages_en.properties
@@ -0,0 +1,1691 @@
+#menu 英文

+pc_version = PC

+mobile_version = Mobile

+home = Home

+phonebook = Phonebook

+sms = SMS

+sd = SD Card

+setting = Settings

+status = Information

+net_select = Network Selection

+dial_setting = Dial-up Settings

+apn_setting = APN

+wifi_advance = Advanced Settings

+management = Management

+net_setting = Connection Settings

+quick_setting = Quick Settings

+

+device_info = Status Information

+traffic_statistics = Statistics

+traffic_alert = Data Management

+

+wifi = Wi-Fi Settings

+wifi_basic = Basic Settings

+device_setting = Device Settings

+sim = SIM Card

+device = Device

+router_setting = Router

+mac_filter = WLAN MAC Filter

+

+wps = WPS

+sleep_mode = Power-save

+lan = LAN

+

+firewall = Firewall

+system_security = System Security

+port_forward = Port Forwarding

+port_filter = Port Filtering

+fastboot = Fast Boot

+display_password = Display Password

+display_QR = Display QR Code

+cable = cable

+wireless = wireless

+

+my_router = Network Settings

+net_surfing = Connect Status

+

+#validate

+phonenumbers_check = Input 5 phone numbers at most, and separate them by ';'

+required = Required

+remote = Please fix this field

+url = Please input a valid URL

+siteLink_check = Please input a valid URL

+siteName_check = Please input a valid name

+date = Please input a valid date

+dateISO = Please input a valid date (ISO)

+number = Please input a valid digit

+digits = Please input integer only

+decimalRange = Please enter a positive number and decimal places a maximum of 2

+any_digits = Please input integer only

+creditcard = Please input a valid credit card number

+equalTo = Please input the same value again

+accept = Please input a value with a valid extension

+maxlength = Please input no more than {0} characters

+minlength = Please input at least {0} characters

+rangelength = Please input a value between {0} and {1} characters in length

+range = Please input a value between {0} and {1}

+max = Please input a value less than or equal to {0}

+min = Please input a value greater than or equal to {0}

+ssid = Please input a valid SSID

+ssid_ap = Please input a valid SSID(, ; " \ are invalid characters)

+email_check = Please input a valid email

+ipv4 = Please input a valid IP address

+ipv6 = Please enter a valid IPv6 address

+name_check = Please input a valid name

+phonenumber_check = Please input a valid phone number

+sms_service_center_check = Please enter a valid center number

+pin_check = Please input 4 to 8 digits

+puk_check = Please input 8 digits.

+password_check = Please input a valid password

+subnetmask_check = Invalid subnet mask

+dhcp_check = DHCP {0} IP is not in the range of LAN subnet

+dns_check = Invalid DNS. DNS can''t be 255.255.255.255 or 0.0.0.0

+start = start

+end = end

+dhcpCompare = Invalid IP address. Start IP shouldn't be greater than end IP

+ipRange = IP pool can't contain LAN IP address (DHCP start IP should be greater than LAN IP address)

+lanip_check = Please input a valid IP address

+ip_check = Please input a full and valid IP address

+dmz_ip_check = Please input a valid IP address

+wps_pin_check = Invalid PIN number

+wps_pin_length_check = Please enter 4 or 8 digits

+browse_sdcard = View SD card

+portCompare = Invalid port range

+comment_check = Invalid character

+check_file_path = The folder name contains invalid characters

+check_filefold_name = The folder name contains invalid characters: ` ~ # & * + | \ : ? / < > . " '

+apn_check = Please input a valid APN

+ppp_username_check = Please input a valid username

+ppp_password_check = Please input a valid password

+unlock_code_check =  Please input a valid unlock code. The code must be 0-9, a-f or A-F, and its length must be 16 characters.

+apn_profile_name_check = The APN profile name contains invalid characters

+dlna_name_check = The Device Name must be 0-9, a-z, A-Z or _

+wifi_password_check = Please input a valid password

+wifi_wep_password_check = Please input 5 or 13 ASCII characters or input 10 or 26 Hex characters.

+range_except = Input a value between {0} and {1}, except for that between 32000 and 32007

+

+#common

+copyright = Copyright &copy; 2010-2022 demo Corporation. All rights reserved

+enable = Enable

+disable = Disable

+apply = Apply

+cancel = Cancel

+clear = Clear

+reset = Reset

+add = Add

+add_new = Add New

+save = Save

+new = New

+view = View

+select = Select

+edit = Edit

+delete = Delete

+delete_all = Delete All

+success_info = Success

+error_info = Failure

+connect = Connect

+disconnect = Disconnect

+connected = Connected

+disconnected = Disconnected

+connecting = Connecting…

+disconnecting = Disconnecting…

+cancelconnect = Cancel Connect

+confirm = Confirm

+prompt = Prompt

+info = Information

+alert = Alert

+yes = Yes

+no = No

+ok = OK

+back = Back

+exit = Exit

+next_step = Next

+prev_step = Previous

+next_page = &gt;&gt;

+prev_page = &lt;&lt;

+root = Root

+create = Create

+speed = Speed

+upload = Upload

+download = Download

+uploaded = Uploaded

+downloaded = Downloaded

+on = On

+off = Off

+need_login_again = You''re logged out of your account. Please login again.

+modify = Change

+content = Content

+time = Time

+processing = Processing...

+saving = Saving...

+deleting = Deleting...

+scanning = State: scanning...

+dlna_scanning = DLNA state: rescanning...

+scanned = DLNA state: rescan complete.

+need_rescan = DLNA state: need rescan.

+sending = Sending...

+creating = Creating...

+uploading = Uploading...

+waiting = Waiting...

+leave_page_info = You have unsaved changes. Are you sure you want to continue?

+colon = :

+page = Page:

+go = GO

+ALL = ALL

+open_source_licenses = Open Source Licenses

+vertical_bar = |

+#security

+security_policy = Security Policy

+security_mode = Security Mode

+security_mode_OPEN = OPEN

+security_mode_SHARED = SHARED

+security_mode_WPA2PSK = WPA2(AES)-PSK

+security_mode_WPAPSKWPA2PSK = WPA-PSK/WPA2-PSK

+security_mode_WPA3Personal = WPA3-Personal

+security_mode_WPA2WPA3 = WPA2(AES)/WPA3-Personal

+wpa = WPA

+pass_phrase = Pass Phrase

+

+#station

+station_info = Connected Devices

+station_number = No.

+host_name = Host Name

+

+#Wifi Basic

+multi_ssid_enable = Multi SSID Switch

+multi_ssid_1 = Main SSID

+multi_ssid_2 = Guest SSID

+multi_ssid_enable_confirm = If enable multi-SSID, Internet Wi-Fi will be disabled. Continue?

+multi_ssid_enable_confirm2 = If enable multi-SSID, Internet Wi-Fi will be disabled. And all connected Wi-Fi devices will probably need to reconnect. Continue?

+multi_ssid_max_access_number_alert = The combined max access number of Main SSID and Guest SSID can''t be more than {0}!

+network_band_selection = Band Selection 

+network_mode = Network Mode

+network_name = Network Name(SSID)

+broadcast_network_name = SSID Broadcast

+country_region_code = Country/Region Code

+frequency_channel = Frequency (Channel)

+rate = Rate

+max_station_number = Max Station Number

+wifi_basic_note = When clicking Apply, any connected Wi-Fi devices will need to reconnect.

+wifi_disconnect_confirm = All connected Wi-Fi devices will need to reconnect. <br/>Do you want to continue?

+wifi_disconnect_confirm2 = All connected Wi-Fi devices will probably need to reconnect. <br/>Do you want to continue?

+network_mode_2 = 802.11 n only

+network_mode_4 = 802.11 b/g/n

+network_mode_5 = 802.11 a only

+network_mode_6 = 802.11 b/g/n/ax

+frequency_channel_0 = Auto

+frequency_channel_1 = (Channel 1)

+frequency_channel_2 = (Channel 2)

+frequency_channel_3 = (Channel 3)

+frequency_channel_4 = (Channel 4)

+frequency_channel_5 = (Channel 5)

+frequency_channel_6 = (Channel 6)

+frequency_channel_7 = (Channel 7)

+frequency_channel_8 = (Channel 8)

+frequency_channel_9 = (Channel 9)

+frequency_channel_10 = (Channel 10)

+frequency_channel_11 = (Channel 11)

+frequency_channel_12 = (Channel 12)

+frequency_channel_13 = (Channel 13)

+frequency_channel_14 = (Channel 14)

+frequency_channel_15 = (Channel 15)

+frequency_channel_16 = (Channel 16)

+frequency_channel_17 = (Channel 17)

+frequency_channel_18 = (Channel 18)

+frequency_channel_19 = (Channel 19)

+frequency_channel_20 = (Channel 20)

+frequency_channel_21 = (Channel 21)

+frequency_channel_22 = (Channel 22)

+frequency_channel_23 = (Channel 23)

+frequency_channel_24 = (Channel 24)

+frequency_channel_25 = (Channel 25)

+frequency_channel_26 = (Channel 26)

+frequency_channel_36 = (Channel 36)

+frequency_channel_40 = (Channel 40)

+frequency_channel_44 = (Channel 44)

+frequency_channel_48 = (Channel 48)

+frequency_channel_149 = (Channel 149)

+frequency_channel_153 = (Channel 153)

+frequency_channel_157 = (Channel 157)

+frequency_channel_161 = (Channel 161)

+frequency_channel_165 = (Channel 165)

+rate_0 = Auto

+rate_1 = 1 Mbps

+rate_2 = 2 Mbps

+rate_3 = 5.5 Mbps

+rate_4 = 6 Mbps

+rate_5 = 6.5 Mbps

+rate_6 = 9 Mbps

+rate_7 = 11 Mbps

+rate_8 = 12 Mbps

+rate_9 = 13 Mbps

+rate_10 = 18 Mbps

+rate_11 = 19.5 Mbps

+rate_12 = 24 Mbps

+rate_13 = 26 Mbps

+rate_14 = 36 Mbps

+rate_15 = 39 Mbps

+rate_16 = 48 Mbps

+rate_17 = 52 Mbps

+rate_18 = 54 Mbps

+rate_19 = 58.5 Mbps

+rate_20 = 65 Mbps

+cannot_operate_when_wifi_connected = You can''t operate when Wi-Fi is connected!

+network_mode_select_2 = 802.11 n only

+network_mode_select_4 = 802.11 b/g/n

+network_mode_select_6 = 802.11 b/g/n/ax

+network_modes_band_select_2 = 802.11 n only

+network_modes_band_select_4 = 802.11 a/n

+network_modes_band_select_5 = 802.11 a only

+

+#net select

+auto_select = Automatic

+manual_select = Manual

+auto_select_type_WCDMA_preferred = Automatic

+auto_select_type_LTE_preferred = Automatic

+auto_select_type_NETWORK_auto = Automatic

+auto_select_type_Only_LTE = 4G Only

+auto_select_type_WCDMA_AND_LTE = 4G/3G Only

+auto_select_type_Only_WCDMA = 3G Only

+auto_select_type_TD_W = 3G Only

+auto_select_type_Only_GSM = 2G Only

+

+search = Search

+searching_net = Searching, please wait...

+registering_net = Registering, please wait...

+network_list = Network List

+register = Register

+auto = Auto

+unknown = Unknown

+available = Available

+current = Current

+forbidden = Forbidden

+net_select_note_automatic = Automatic: The device will search available network automatically.

+net_select_note_manual = Manual: The device will search available network manually.

+net_status = Status

+mccmnc = MCCMNC

+option = Option

+networktype = Network Type

+subnet = Act

+

+#home

+ap_station_clear = Clear all

+current_flux = Current Data

+total_flux = Total Used Data

+connected_time = Duration

+flux_up = Upload

+flux_down = Download

+traffic_current_connection = Current Connection

+traffic_current_month_data = Current Month

+traffic_total_traffic = Total Used Data

+traffic_used_data_month = Data usage of this month:

+traffic_used_time_month = The online time of this month:

+traffic_data_approximated = Data usage is approximate only. For actual usage, please refer to your network operator.

+traffic_used_month = Used:

+traffic_left_month = Left:

+traffic_exceeded_month = Exceeded:

+traffic_total_month = Limit:

+traffic_apply_volume_limit = Data Management

+traffic_data_limit_type = Data Type

+traffic_data = Data

+traffic_time = Time

+traffic_limit_data_month = Monthly

+traffic_alert_when_data_reach = Remind me

+traffic_limit_time_month = Monthly

+traffic_alert_when_time_reach = Remind me

+traffic_million_byte = MB

+traffic_percent = %

+traffic_limit_disconnect_msg = Your data/time used reaches {0} percent. Do you want to disconnect from network?

+traffic_limit_connect_msg = Your data/time used reaches {0} percent. Do you still want to connect to network?

+traffic_limit_msg = Your data/time used reaches {0} percent.

+traffic_beyond_disconnect_msg = Your data/time used exceeds limit. Do you want to disconnect from network?

+traffic_beyond_connect_msg = Your data/time used exceeds limit. Do you still want to connect to network?

+traffic_beyond_msg = Your data/time used exceeds limit.

+traffic_calibrate_note = Support data calibrate function. If the data that web page displayed is not in agreement with the actual used, you can modify the used data by this operation.

+traffic_note = Remind me when used data/time reaches specified percentage.

+traffic_over_note = When the data plan''s unit is MB, the used data should be less than 4096TB.

+traffic_clear_confirm = Are you sure to clear?

+traffic_not_support = The current mode does not support this feature.

+

+#APN

+apn_currentApn = Current APN

+apn_mode = Mode

+apn_auto_apn = Auto

+apn_manual_apn = Manual

+apn_profile = Profile

+apn_profile_name = Profile Name

+apn = APN

+apn_ipv4_apn = IPv4 APN

+apn_ipv6_apn = IPv6 APN

+apn_dns_mode = DNS Mode

+apn_dns_mode_ipv4 = IPv4 DNS Mode

+apn_dns_mode_ipv6 = IPv6 DNS Mode

+apn_auto_dns = Auto

+apn_manual_dns = Manual

+apn_dns1 = DNS 1

+apn_dns2 = DNS 2

+apn_dns1_ipv4 = IPv4 DNS 1

+apn_dns2_ipv4 = IPv4 DNS 2

+apn_dns1_ipv6 = IPv6 DNS 1

+apn_dns2_ipv6 = IPv6 DNS 2

+apn_authentication = Authentication

+apn_authentication_ipv4 = IPv4 Authentication

+apn_authentication_ipv6 = IPv6 Authentication

+apn_user_name = User Name

+apn_user_name_ipv4 = IPv4 User Name

+apn_user_name_ipv6 = IPv6 User Name

+apn_password = Password

+apn_password_ipv4 = IPv4 Password

+apn_password_ipv6 = IPv6 Password

+apn_pdp_type = PDP Type

+set_default = Set as default

+apn_save_profile_exist = Profile Name already exists, please select another name.

+apn_delete_cant_delete_default = You can''t delete the default profile!

+apn_delete_confirm = Are you sure to delete?

+apn_cant_modify_status = Can''t change the current APN setting when the network is {0}!

+apn_cant_modify_current = You can''t change the APN that is in use!

+apn_cant_delete_current = You can''t delete the current profile!

+apn_profile_full = You can only add {0} items at most!

+dial_num = Dial No.

+apn_no_select_alert = Please choose a valid profile!

+

+#Status bar

+network_status = Network Status

+connection_status = Wireless Broadband Connection status

+rj45_connection_status = Cable Broadband Connection status

+battery = Battery

+charging = Charging

+sim_status = SIM Status

+sim_status_modem_waitpin = Invalid SIM card

+sim_status_modem_waitpuk = Invalid SIM card

+sim_status_modem_sim_undetected = Invalid SIM card

+sim_status_modem_undetected = Invalid SIM card

+sim_status_modem_imsi_waitnck = Invalid SIM card

+sim_status_modem_sim_destroy = Invalid SIM card

+sim_status_modem_destroy = Invalid SIM card

+sim_status_modem_init_complete = Valid SIM card

+sim_status_modem_ready = SIM is ready

+wifi_status = Wi-Fi Status

+wifi_status_on = Wi-Fi on

+wifi_status_off = Wi-Fi off

+wifi_status1 = Number of users:1

+wifi_status2 = Number of users:2

+wifi_status3 = Number of users:3

+wifi_status4 = Number of users:4

+wifi_status5 = Number of users:5

+wifi_status6 = Number of users:6

+wifi_status7 = Number of users:7

+wifi_status8 = Number of users:8

+wifi_status9 = Number of users:9

+wifi_status10 = Number of users:10

+enable_pin = Enable PIN

+remaining_time = Remaining Time

+signal = Signal

+network_type = Network type

+network_type_limited_service = Limited Service

+network_type_no_service = No Service

+network_provider = Operator

+roaming_status = Roaming status

+sim_status_ready = SIM is ready

+sim_status_waitpin = Ready to input PIN

+sim_status_waitpuk = Ready to input PUK

+sim_status_undetected = No SIM card detected

+sim_status_waitnck = Ready to input NCK

+sim_status_destroy = SIM is corrupted

+signal_strength = Signal strength

+signal_strength_label = Signal Strength

+battery_level = Battery level

+

+#dial_setting

+dial_note = WAN Connection Status

+dial_mode = Connection Mode

+dial_mode_cpe = Dial-up Mode

+dial_roam_info = The Roaming Setting is disabled. To enable it, please go to setting page and click in the checkbox.

+dial_setting_note_automatic = Automatic: The device will automatically connect to network when it is powered on.

+dial_setting_note_manual = Manual: The device will connect to network manually.

+dial_roaming_remind = Check here, you can connect to internet in the roaming status.

+dial_roaming_connect = Your device is roaming. Connecting to network may occur additional charges. Continue?

+

+#phonebook

+search = Search

+save_location = Save Location

+save_location_0 = SIM Card

+save_location_1 = Device

+group_all = All

+group_null = -

+group_common = Common

+group_family = Family

+group_friend =  Friend

+group_colleague = Colleague

+name = Name

+mobile_phone_number = Mobile Number

+home_phone_number = Home Number

+office_phone_number = Office Number

+mail = Email

+group = Group

+no_data_selected = Please select an item!

+confirm_data_delete = Are you sure to delete?

+confirm_pb_delete = Delete selected contact(s)?

+too_many_data_selected = Too many numbers are selected! Please select one number!

+delete_fail_try_again = Delete failed, please try again.

+max_send_number = You can enter 5 phone numbers at most!

+send = Send

+send_sms = Send Message

+new_message = New SMS

+send_numbers = Number

+contents = Contents

+device_full =  Phonebook space on your device is full!

+sim_full = SIM card is full!

+phonebook_init_fail = The phone book failed to initialize!<br/>Please check SIM card and restart the device.

+sim_removed = SIM card was removed!

+change_device_to_sim_confirm = Information may be lost, and whether there is a need to continue to deposit?

+

+#SMS

+smslist = Device SMS

+sms_setting = SMS Settings

+sim_messages = SIM SMS

+refresh = Refresh

+forward = Forward

+draft = Draft

+send_fail_try_again = Send failed.

+sms_content_required = Please type a SMS.

+sms_contact_required = Please select a contact.

+select_some_options = You can choose 5 contacts at most

+select_an_option = Select an Option

+chat_input_placehoder = Please type message here

+sms_chat_input_confirm = Please press Enter or enter ";" to complete

+sms_capacity_will_full = SMS capacity will be full, please delete some SMS

+sms_capacity_is_full = SMS capacity is full, please delete some SMS

+sms_capacity_is_full_for_send = SMS capacity is full, please delete some SMS to receive or send message.

+sms_capacity_will_full_just = SMS capacity will be full, you could send {0} SMS(s)

+sms_init_fail = SMS failed to initialize!<br/>Please check SIM card and restart the device.

+sms_resending = Resending SMS...

+sms_resend_fail = SMS resend failure.

+sms_stop_sending = Stop Sending

+sms_unread_count = Unread SMS

+sms_delivery_report_1 = SMS is delivered.

+sms_delivery_report_2 = SMS is undelivered.

+sms_delivery_report_3 = Sending SMS...

+sms_report = Delivery Report

+sms_cancel_sending = Cancelling...

+sms_save_draft_success = SMS is saved as a draft

+sms_save_draft_failed = Draft save failed

+sms_to_save_draft = SMS was modified, save it as a draft?

+sms_no_recipient = Your SMS doesn''t have any recipients, and this SMS will be discarded.

+phone_number_invalid = Phone number invalid

+sms_to = To:

+confirm_sms_delete = Delete selected message(s)?

+sms_save_tip = Saving...

+

+#login

+password = Password

+puk = PUK

+login = Login

+logout = Logout

+new_pin = New PIN

+confirm_pin = Confirm New PIN

+puk_locked = Your SIM card is locked permanently. Please contact your operator.

+password_error = Password is incorrect!

+password_error_left = Password is incorrect!<br/>You have {0} attempt(s) left.

+password_error_account_lock = Your account is locked. <br/>Remaining time:

+password_error_five_times = You''ve input 5 times incorrectly. Retry in 5 minutes.

+password_error_account_lock_time = Your account is locked. <br/>Please try later.

+enter_pin = SIM card is locked, please input PIN to unlock.

+enter_puk = SIM card is PIN-locked, please input PUK to unlock.

+last_enter_pin = Final attempt. If incorrect again, your SIM card will be locked!

+last_enter_puk = Final attempt. If incorrect again, your SIM card will be corrupted!

+attempts_left = Attempts Left:

+pin_error = PIN is incorrect!

+puk_error = PUK is incorrect!

+confirm_logout = Do you want to logout?

+

+#advanced password

+password_management = Login Password

+current_password = Current Password

+new_password = New Password

+confirm_password = Confirm New Password

+current_password_error = Current password is incorrect!

+password_note_info = You can change login password on this page.

+password_note_valid = The password can''t be empty and must contain at most 32 characters.

+password_note_input = The password contains 0-9 a-z A-Z ! # $ * + , - . % : = ? @ [ ] ^ _ { | } ~

+password_note_first_change = Please change your initial login password!

+password_note_too_low = Your password complexity is too low (the password could contain uppercase and lowercase letters, numbers, special characters and no less than 8 characters). Do you want to continue?

+

+#advanced pin

+pin = PIN

+current_pin = Current PIN

+pin_management = PIN Management

+pin_status = PIN Status

+modify_pin = Change PIN

+cannot_operate_when_connected = Can''t operate when connecting to network!

+cannot_change_pin_when_connected = Can''t change PIN when connecting to network!

+pin_note_info = Apply PIN security settings in PIN Management to prevent unauthorized use of the SIM, USIM, or UIM card. If you want to change current settings, please disconnect from network first.

+pin_note_operator = If enable PIN, you may need to enter PIN when the device is powered on. If disable PIN, no PIN is required.

+pin_note_modify = You can change PIN when PIN is enabled.

+

+#lan

+lan_setting = LAN Interface Setup

+ip_address = IP Address

+subnet_mask = Subnet Mask

+mac_address = MAC Address

+dhcp_server = DHCP Server

+dhcp_ip_pool = DHCP IP Pool

+dhcp_lease = DHCP Lease Time

+hours = hour(s)

+minutes = minute(s)

+lan_note = Your settings will take effect after restarting your device.

+lan_note_ip_address = IP Address: LAN IP address of the router. You can access page management on device via this IP address.

+lan_note_subnet_mask = Subnet Mask: Subnet mask for IP address.

+lan_note_dhcp_server_enable = DHCP Server Enable: If the Dynamic Host Configuration Protocol (DHCP) service is enabled, the device allocates IP addresses to clients connected to it.

+lan_note_dhcp_server_disable = DHCP Server Disable: If the Dynamic Host Configuration Protocol (DHCP) service is disabled, the device does not allocate IP addresses to clients connected to it and IP addresses must be entered manually from each client.

+lan_note_dhcp_ip_pool = DHCP IP Pool: Starting and Ending IP address specify IP address range which is assigned by DHCP server to access devices. The IP address out of this range cannot be assigned by DHCP server.

+lan_note_dhcp_lease_time = DHCP Lease Time: Lease Time specifies how long a computer can use IP address. If the device will continue to use IP address, it must initiate request again before lease time expires. This IP address will not assign to other device until the old device initiates no request when its lease time expires.

+lan_confirm_reopen = Your settings will take effect after restarting your device. Do you want to continue?<br/><br/><i>Note: Click Yes to submit the request and restart the device. If you choose No, it means that you give up the current operation.</i>

+lan_tip_staticip_notsame = IP Address and static IP address can''t be in the same segment!

+

+#sms_setting

+sms_validity = Validity

+sms_validity_twelve_hours = 12 Hours

+sms_validity_one_day = 1 Day

+sms_validity_one_week = 1 Week

+sms_validity_largest = Maximum

+center_number = Center Number

+delivery_report = Delivery Report

+list = List

+

+#restore

+restore = Reset

+restore_title = Reset Factory Settings

+restore_button = Reset Factory Settings

+restore_confirm = Parameters will be reset to factory defaults, the device will restart. Continue?

+restore_when_connected = Please disconnect from WAN first!

+restoring = Resetting factory settings

+restore_note_info = Click Reset to reset all settings to defaults, and the device will restart automatically.

+

+#wps

+wps_note_all = WPS (Wi-Fi Protected Setup) is a standard that allows users to set up a wireless network in an easy and secure way without specific configuration, such as: SSID, security mode and password.

+wps_note_pin = PIN: You need to enter the PIN that is generated by the access client.

+wps_note_pbc = PBC: You can select the PBC (Push Button Configuration) on the web page or hold the WPS button for 3-4 seconds on the device to enable WPS function.

+wps_note_wait = The device will wait for receiving the access request of wireless access client within 2 minutes.

+wps_pin = PIN

+wps_pbc = PBC

+wps_wifi_off = You can''t operate when Wi-Fi is off!

+wps_auth_open = Current encryption type does not support WPS.

+wps_on_info = WPS is enabled now, please try again later.

+wps_ssid_broadcast_disable = You can''t operate when SSID broadcast is disabled!

+

+#sleep mode

+wifi_sleep = Wi-Fi Sleep

+sleep_time = Sleep after

+sleep_mode_-1 = Never Sleep

+sleep_mode_5 = 5 Minutes

+sleep_mode_10 = 10 Minutes

+sleep_mode_20 = 20 Minutes

+sleep_mode_30 = 30 Minutes

+sleep_mode_60 = 1 Hour

+sleep_mode_120 = 2 Hours

+wifi_sleep_note_info = Sleep after: When there''s no Wi-Fi connection in specific time, Wi-Fi will be unavailable, and the system will turn to sleep mode for power-saving.

+wifi_sleep_confirm = The current setting changes may restart Wi-Fi, continue any way?

+

+#system security

+remote_management = Remote Management (via WAN)

+ping_from_wan = Ping From WAN Filter

+

+#portforward

+protocol_TCP&UDP = TCP+UDP

+protocol_TCP = TCP

+protocol_UDP = UDP

+virtual_server_setting = Virtual Server Settings

+port_forward_setting = Port Forwarding Settings

+port_forward_list = Current Virtual Servers in system

+port_forward_note_info = Configure a Port Forward to enable external computers to access WWW, FTP or other services provided by LAN.

+port_forward_note_port = Port Range: Set port numbers to be forwarded.

+port_forward_note_ip_address = IP Address: Set the source IP address which you want to forward.

+port_forward_note_protocol = Protocol: Set the protocol for forwarding.

+port_forward_note_comment = Comment: Type comment for Port Forwarding rule. It contains 0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ .

+port_range = Port Range

+protocol = Protocol

+comment = Comment

+ipExam = (e.g., 192.168.0.101)

+rules_max = The rule number exceeds {0}.

+rule_exist = This rule already exists.

+rule_max_note = The maximum number of rules is 10.

+rule_max_note_v4v6 = The maximum of rules for IPv4 and IPv6 is 10 respectively.

+

+rules_max_v4v6 =  The {0} rule number exceeds {1}.

+rule_exist_v4v6 = This {0} rule already exists.

+

+#quick setting

+step_number_1 = 1

+step_number_2 = 2

+step_number_3 = 3

+step_number_4 = 4

+step_number_5 = 5

+step_number_6 = 6

+step_name_1 = 1.Quick Setup

+step_name_2 = 2.PPP Profile Configuration

+step_name_3 = 3.PPP Authentication

+step_name_4 = 4.SSID Configuration

+step_name_5 = 5.Security Configuration

+step_name_6 = Configuration as Follows

+step1_exp1 = The wizard will show you how to set up basic parameters of gateway safely: Click "Previous" & "Next" to navigate, and click "Apply" to save settings.For advanced parameters, set them in other menu.

+step1_exp2 = Set basic parameters in this wizard. For advanced parameters, set them in other menu.

+apn_settings = APN Settings

+step2_auto_apn_explain = If you select Auto APN, the second step, i.e., PPP Authentication, will be skipped.

+step2_profile_name_explain = Profile Name: The default profile that you use currently.

+ppp_authentication = PPP Authentication

+step3_authentication_apn_explain1 = Authentication: It is provided by your Internet Service Provider (ISP). Password Authentication Protocol (PAP) provides a simple method without encryption for the peer to establish its identity using a 2-way handshake. Challenge-Handshake Authentication Protocol (CHAP) is used to periodically verify the identity of the peer using a 3-way handshake.

+step3_authentication_apn_explain2 = User Name: It is used to obtain authentication from the ISP when connection is established.

+step3_authentication_apn_explain3 = Password: It is used to obtain authentication from the ISP when connection is established.

+step3_username_password_explain = Click "Set as default" to set this profile as the default profile.

+ssid_title = SSID

+ssid_name = Network Name(SSID)

+ssid_broadcast = SSID Broadcast

+step4_ssid_explain = Network Name: Service Set Identifier (SSID). Enter name of your wireless local area network (WLAN), which is less than 32 characters.

+step4_ssid_broadcast_explain1 = SSID Broadcast: Disable or Enable (Default) this function. Once enabled, the router will broadcast SSID, and other devices can discover and connect to it.

+step4_ssid_broadcast_explain2 = Disable: The gateway disables broadcasting and hides the name of your network.

+step5_encryption_mode_info = Security Mode:

+step5_encryption_mode_explain1 = OPEN: Authentication and encryption won''t be performed. There are risks that private information may be intercepted, or network may be used by unauthorized individuals. This encryption scheme isn''t recommended.

+step5_encryption_mode_explain2 = WPA2(AES)-PSK: It is the secure version of WPA with implementation of the 802.11i standard.

+step5_encryption_mode_explain3 = WPA-PSK/WPA2-PSK: WPA Pre-Shared Key (WPA-PSK). WPA2-PSK is the secure version of WPA with implementation of the 802.11i standard.

+step5_encryption_mode_explain4 = Pass Phrase: The pass-phrase contains 0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _  { | } ~

+step6_apply_explain = You need to reconnect wireless network when committing.

+quick_setting_wifi_disable_confirm = 1. Wi-Fi is off, the settings for Wi-Fi won''t take effect.<br\>Continue?

+quick_setting_param_changed_confirm = 1. Connected Wi-Fi devices probably need to reconnect when Wi-Fi configuration changes.<br\>Continue?

+#SD Card

+sdcard = SD Card

+httpshare = HTTP Share

+sd_card_mode = Mode

+sd_card_share_setting = Share Setting

+sd_card_share_usb_mode = USB

+sd_card_share_http_share_mode = HTTP SHARE

+http_title = HTTP Share Settings

+sd_card_status = Status

+sd_card_file_to_share = File to Share

+sd_card_access_type = Access Type

+sd_card_path_to_share = Path to Share

+sd_card_entire_sd_card = Entire SD Card

+sd_card_custom_setting = Custom 

+sd_card_read_write = Read/Write

+sd_card_readonly = Read Only

+sd_card_share_setting_no_sdcard = No SD Card!

+sd_card_share_setting_exist = The folder/file already exists!

+sd_card_share_setting_noexist = The folder/file does not exist!

+sd_card_status_info_0 = No SD Card!

+sd_card_status_info_1 = SD Card already exists and can be used now

+sd_card_status_info_2 = SD Card already exists, but it is invalid now! Please retry in 5 minutes. If still invalid, please check SD Card!

+sd_card_status_info_2_reason = Possible reasons are as follows

+sd_card_status_info_2_reason_1 = SD card is of NTFS format, please switch to USB mass storage.

+sd_card_status_info_2_reason_2 = SD card is loading, please retry in 5 minutes. If still invalid, please check SD card.

+sd_card_invalid_chars_cant_download = The file name contains invalid characters and can not be downloaded! (< > " '' & + / \\ : * | # ? ~ ` are invalid characters)

+note_not_support_fs_ntfs = In HTTP Share Mode, the device only supports FAT/FAT32 file system!

+note_web_share_mode = HTTP Share Mode: Share SD card via web browser. The removable drive mapping of SD card via USB port will be disabled.

+note_usb_access = USB Access Only: By the removable drive mapping, user can access SD card via USB cable only. The web page of sharing SD card will be disabled.

+note_http_share_usb_access = USB Access Only: By the removable drive mapping, user can access SD card via USB cable only. The web page of sharing SD card will be disabled.

+note_http_share_cannot_access = You can''t access this page!

+note_path_to_share_example = Path to Share: You can input the sharing path, such as /Picture. By typing only a slash in Path to Share filed, you agree to share entire SD card.

+note_upload_not_refresh = When you''re in process of downloading or uploading the file, please don''t refresh the page!

+note_upload_single_file_2g = The single file upload can not be above 2G.

+note_upload_filelenth_25 = The name of the file / folder name modification function supports 25 characters at most.

+note_uploading_not_refresh = Uploading, please don''t refresh the page!

+note_invalid_file_path = Path to Share can''t be a dot, and can''t contain following characters: < > " '' & + / \\ : * | # ? ~ `

+browse_btn = Browse

+change_btn = Change

+no_file_selected = No file selected...

+sd_no_file_selected = Please select a file

+sd_name = Name

+sd_path = Path:

+sd_rename = Rename

+sd_download = Download

+sd_file_size = File Size

+sd_update_time = Updated Time

+no_sdcard = No SD Card!

+no_exist = The file is not exist!

+sd_card_folder_name_is_null = Please enter a name

+get_file_list_failure = Get file list failed

+create_folder_failure = Create folder failed

+delete_folder_failure = Delete folder/file failed

+sd_card_path_too_long = File path too long.

+sd_file_size_too_big = The file is too large. The single file upload can not be above 2G.

+sd_file_name_invalid = File name containing * is not supported. Please update the file name.

+back_to_login = Back to Login

+sd_config_changed_reload = The settings for SD card share are changed, and the page will reload.

+sd_upload_space_not_enough = The space is not enough!

+sd_upload_data_lost = Upload failed, please retry.

+sd_upload_file_is_downloading = File is downloading, try later!

+sd_share_path_is_invalid = Path to Share is invalid, please set the share path

+sd_share_path_cant_rename = The folder was shared and cannot be renamed.

+sd_share_path_cant_delete = The folder "{0}" was shared and cannot be deleted.

+sd_share_path_invalid = The shared path does not exist.

+sd_file_processing_cant_delete = File is being used, cannot be deleted.

+sd_file_processing_cant_rename = File is being used, cannot be renamed.

+sd_not_support = The card format don''t support or other reasons, please re-insert or replace SD card.

+sd_usb_forbidden = The card is busy now, cannot be changed.

+sd_upload_rename = The file already exists! Please change the file name and select "yes" to continue. Select "no" will cancel the upload.

+sd_upload_rename_null = Can''t be empty or more than 25 characters!

+

+#port filter

+filter_basic_setting = Basic Settings

+port_filter_enabled = MAC/IP/Port Filtering

+default_policy = Default Policy

+default_policy_note = You can set firewall policies to protect your network from viruses, worms and malicious activities on the Internet.

+default_policy_note_filter = Only when filtering is enabled, the filter policy is available.

+accepted = Accepted

+dropped = Dropped

+port_filter_setting = MAC/IP/Port Filtering Settings

+mac_address = MAC Address

+macExam = (e.g., 00:1E:90:FF:FF:FF)

+dest_ip_address = Dest. IP Address

+source_ip_address = Source IP Address

+port_filter_action = Action

+filter_accept = Accept

+filter_drop = Drop

+protocol_None = ALL

+protocol_ICMP = ICMP

+port_filter_list = Current MAC/IP/Port Filtering Rules in System

+dest_port_range = Dest. Port Range

+source_port_range = Source Port Range

+filter_accept_note = Others would be accepted.

+filter_drop_note = Others would be dropped.

+filter_optional = Please input any IP, MAC or/and port value

+mac_check = Invalid MAC address

+filter_ip_setting = IP Settings

+filter_ipv4 = IPv4

+filter_ipv6 = IPv6

+ip_type = IP Type

+source_ipv6_address = Source IPv6 Address

+dest_ipv6_address = Dest. IPv6 Address

+port_filter_note_mac_address = MAC Address: Set MAC address to be filtered.

+port_filter_note_source_ip_address = Source IP Address: Set source IP address to be filtered.

+port_filter_note_dest_ip_address = Dest IP Address: Set dest IP address to be filtered.

+port_filter_note_protocol = Protocol: Set protocol to be used for filtering.

+port_filter_note_source_port_range = Source Port Range: Set source port numbers to be filtered.

+port_filter_note_dest_port_range = Dest Port Range: Set dest port numbers to be filtered.

+port_filter_note_action = Action: Set to handle the packet if it matches with the rule.

+port_filter_note_comment = Comment: Enter comment for filter settings. It contains 0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ .

+port_filter_note_info = The filter policies are matched one by one with the rules. And if met this provision, it won''t continue to match the rules listed below.

+confirm_data_effect = Your settings may not take effect immediately. If you need to fully take effect, proposed restart the device. Continue?

+

+#wifi_range

+wifi_range_settings = Wi-Fi Performance Settings

+wifi_range = Wi-Fi Coverage

+wifi_short_mode = Short Wi-Fi Coverage - Best battery life

+wifi_medium_mode = Medium Wi-Fi Coverage

+wifi_long_mode = Long Wi-Fi Coverage

+wifi_des_short_mode = Short Wi-Fi Coverage

+wifi_des_medium_mode = Medium Wi-Fi Coverage

+wifi_des_long_mode = Long Wi-Fi Coverage

+wifi_range_note_range = Wi-Fi Coverage:

+wifi_range_note_short = Short Wi-Fi Coverage: Coverage and launch small power consumption, it is the best battery life.

+wifi_range_note_medium = Medium Wi-Fi Coverage: Coverage and emission power consumption is half of equipment support ability, normal power consume.

+wifi_range_note_long = Long Wi-Fi Coverage: Maximum emission power and coverage, if the terminal device still connect to your Wi-Fi network, which will decrease battery life.

+wifi_range_note_short_cpe = Short Wi-Fi Coverage: Minimum power consumption and coverage.

+wifi_range_note_medium_cpe = Medium Wi-Fi Coverage: 50% of device power consumption and coverage.

+wifi_range_note_long_cpe = Long Wi-Fi Coverage: Maximum power consumption and coverage.

+

+#upnp

+upnp = UPnP

+upnp_setting = UPnP Settings

+upnp_note_info = Universal Plug and Play (UPnP) is a set of networking protocols that allows networked devices, such as PC, printers, Internet gateways, Wi-Fi access points and mobile devices, to seamlessly discover each other''s presence on the network and establish functional network services for data sharing, communications, and entertainment.

+

+#dmz

+dmz = DMZ

+dmz_setting = DMZ Settings

+dmz_note_info = If a terminal device can''t run network applications via this device, please enter IP address of the terminal device in the entry box when DMZ is enabled.

+dmz_note_function = You can configure DMZ address, enable or disable DMZ on this page.

+

+#Device Information

+max_access_num = Max Access Number

+lan_domain = LAN Domain

+sim_serial_number = SIM Card Number

+software_version = Software Version

+firmware_version = Firmware Version

+hardware_version = Hardware Version

+imei = IMEI

+imsi = IMSI

+wan_ip_address = WAN IP Address

+ipv6_wan_ip_address = WAN IPv6 Address

+network_name_ssid1 = Network Name (Main SSID)

+pass_phrase_ssid1 = Pass Phrase (Main SSID)

+max_access_num_ssid1 = Max Access Number (Main SSID)

+network_name_ssid2 = Network Name (Guest SSID)

+pass_phrase_ssid2 = Pass Phrase (Guest SSID)

+max_access_num_ssid2 = Max Access Number (Guest SSID)

+

+#port map

+port_map = Port Mapping

+port_map_basic = Basic Settings

+port_map_setting = Port Mapping Settings

+source_port = Src. Port

+dest_port = Dest. Port

+port_map_list = Current Port Mapping Rules in System

+port_map_note_info = Configure a Port Mapping to enable external computers to access WWW, FTP or other services provided by LAN.

+port_map_note_port = Src. Port/Dest Port: The port of the computer that provides services.

+port_map_note_dest_ip_address = Dest. IP Address: Specify a computer located at LAN to provide services.

+port_map_note_protocol = Protocol: Protocols applied by services.

+port_map_note_comment = Comment: Type comment for Port Mapping rule. It contains 0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ .

+

+#USSD Info

+USSD = USSD

+ussd = USSD

+ussd_send_to = Send to

+ussd_send = Send

+ussd_cancel = Cancel

+ussd_reply_to = Reply to

+ussd_reply = Reply

+ussd_contents = Contents

+ussd_timeout = Network Timeout!

+ussd_operation_timeout = Operation Timeout!

+ussd_no_service = No Network Service!

+ussd_retry = Operation Failed! Please Retry!

+ussd_unsupport = USSD is unsupported!

+ussd_info_error = Get Information Error!

+ussd_fail = Operation Failed!

+ussd_error_input = Error Input!

+ussd_note1 = You can send a command to the network (have predefined numbers or symbols), the network will be based on the instruction for you to provide the corresponding services.

+

+#dlna setting

+dlna_setting = DLNA Settings

+dlna_language = Language

+dlna_language_chinese = Chinese

+dlna_language_english = English

+dlna_device_name = Device Name

+dlna_media_type = Shared Media Type

+dlna_media_info = Share Settings

+dlna_audio = Music

+dlna_image = Image

+dlna_video = Video

+dlna_rescan = Rescan

+dlna_note_info = You can set Digital Living Network Alliance(DLNA) when SD card is available or HTTP Share Mode is enabled.

+dlna_note_httpshare = You can set Digital Media Server (DMS) language, device name, and media type which you want to share on this page.

+dlna_note_rescan = In order to allow DLNA multimedia database to be synchronized with SD card, please rescan.

+

+#nosimcard

+no_sim_card_title = System Information

+no_sim_card_message = No SIM Card or SIM Card invalid!

+

+#network_locked

+network_locked = SIM Lock!

+network_locked_explain = This device is network locked. Please contact your service provider to get unlock code.

+network_locked_times_explain =  Attempts left for unlock code input:

+network_locked_enter_explain = Please input unlock code:

+network_locked_zero_times = This device is network locked. Please contact your service provider.

+

+#update_info

+update_info = Update Information

+update_no_info = Software is up to date

+update_new_version_found = New version available

+update_current_version = Current Version

+update_new_version = New Version

+update_link_prompt = Click the following links to download update tools.

+update_skip_btn = Apply

+update_id_skip_info = If you don''t want to update, please click &quot;Skip&quot;.

+update_remind = Remind me when new version found.

+update_management = Update Management

+update_log = Bug Fixed

+update_note = Note

+update_notice = New version found. For more details, please goto Settings->Device Settings->Update management

+update_note_info = Click the link to download update tool.

+update_note_install = Extract update tool and then run it to start updating.

+update_note_linux = Can''t upgrade online in Linux. Please upgrade in Windows or on a Mac.

+update_status = Status

+update_settings = Update

+wifi_connect_alert = You can only update by connecting the ethernet cable.

+

+#AP_Station

+ap_station = Internet Wi-Fi

+ap_station_switch = Internet Wi-Fi Switch

+ap_station_wlan_mode = Preferred Network

+ap_station_wifi_prior = Wi-Fi

+ap_station_3g_prior = WWAN

+ap_station_current_status = Current Status

+ap_station_wlan_connected = Wi-Fi connected

+ap_station_wan_connected = WAN connected

+ap_station_no_connection = No connection

+ap_station_hotspot_list = Wi-Fi Hotspot

+ap_station_connect = Connect

+ap_station_disconnect = Disconnect

+ap_station_add_hotspot = Add Wi-Fi Hotspot

+ap_station_edit_hotspot = Edit Wi-Fi Hotspot

+ap_station_show_password = Display Password

+ap_station_encrypt_type = Encryption Type

+ap_station_wep_keys = WEP Keys

+ap_station_encrypt_type_none = NO ENCRYPTION

+ap_station_encrypt_type_wep = WEP

+ap_station_wep_key_type_ascii = ASCII

+ap_station_wep_key_type_hex = HEX

+ap_station_cipher = WPA Algorithms

+ap_station_cipher_TKIP = TKIP

+ap_station_cipher_AES = AES

+ap_station_cipher_AUTO = AUTO

+ap_station_security_mode_OPEN = OPEN

+ap_station_security_mode_WPAPSKWPA2PSK = WPA-PSK/WPA2-PSK

+ap_station_security_mode_SHARED = SHARED

+ap_station_security_mode_WPAPSK = WPA-PSK

+ap_station_security_mode_WPA2PSK = WPA2-PSK

+ap_station_security_mode_EAPAKASIM = EAP-AKA/SIM

+ap_station_security_mode_EAP-SIM/AKA = EAP-SIM/AKA

+ap_station_security_mode_WPA3Personal = WPA3-Personal

+ap_station_security_mode_WPA2WPA3 = WPA2(AES)/WPA3-Personal

+ap_station_wep_default_key = Default Key

+ap_station_wep_key = Key

+ap_station_wep_key_0 = Key 1

+ap_station_wep_key_1 = Key 2

+ap_station_wep_key_2 = Key 3

+ap_station_wep_key_3 = Key 4

+ap_station_exceed_list_max = The max number of AP is {0}!

+ap_station_search_hotspot_fail = Search hotspot failure!

+ap_station_connect_change_alert = Will disconnect from WAN. Continue?

+ap_station_update_fail = Operate failed. The hotspot is in connection.

+ap_station_enable_confirm = Multi SSID cannot be used when Internet Wi-Fi is being used. Multi SSID is automatically turned OFF if Internet Wi-Fi is ON. Still change settings?

+ap_station_processing = Background busy, please try again.

+ap_station_exist = Hot spots of the same name already exist.

+ap_connect_error = Failed to connect {0}!

+

+#fastboot

+fastboot = Fast Boot

+fastboot_setting = Fast Boot Settings

+fastboot_note = If enable Fast Boot function, your device will start in a short time.

+

+#notes

+wifi_channel_bandwidth = Channel Bandwidth

+

+home_note = The table shows the information of connected wireless device(s).

+

+sms_setting_note_validity = Validity: Set valid period of outgoing messages.

+sms_setting_note_center_number = Center Number: Enter SMS center number. For more information, please contact your service provider.

+sms_setting_note_delivery_report = Delivery Report: Receive or reject a prompt informing you that the message is delivered to the recipient.

+

+apn_note_whole_page = You can set the Access Point Name(APN) on this page.

+apn_note_mode = Mode: If a fixed APN is provided by your service provider, select Manual APN. Otherwise, please select Auto APN, and the device will automatically obtain parameters.

+apn_note_profile = Profile: It contains one or more profile names.

+apn_note_pdp_type = PDP Type: IPv4/IPv6/IPv4&IPv6.

+apn_note_profile_name = Profile Name: It refers to the name that you assign to the new profile.

+apn_note_apn = APN: Access Point Name. The APN contains 0-9 a-z A-Z . - and it can''t start with and end with .or -.

+apn_note_dns_mode = DNS Mode: If a fixed IP address is provided by your service provider, select Manual DNS. Otherwise, please select Auto DNS, and the device will automatically obtain parameters.

+apn_note_authentication = Authentication: It is provided by your Internet Service Provider(ISP).Password Authentication Protocol (PAP) provides a simple method without encryption for the peer to establish its identity using a 2-way handshake. Challenge-Handshake Authentication Protocol (CHAP) is used to periodically verify the identity of the peer using a 3-way handshake.

+apn_note_username = User Name: User name is used to obtain authentication from the ISP when the connection is established.

+apn_note_password = Password: Password is used to obtain authentication from the ISP when the connection is established.

+apn_note_set_default = Click "Set as default" to set this profile as the default profile.

+

+wifi_basic_note_multi_ssid_switch = Multi SSID Switch: 2 SSID can be used at the same time.

+wifi_basic_note_network_name = Network Name(SSID): SSID can be understood as network name. When change the SSID, please enter a string less than 32 characters as the name for your Wi-Fi. The string contains numbers, letters (a-z, A-Z), special characters (!#()+-./%=?@^_{|}~) and space, and it can''t start and end with space.

+wifi_basic_note_network_name_input = The network name contains 0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ and space, and it can''t start and end with space.

+wifi_basic_note_broadcast = SSID Broadcast: If enable this function, the device will broadcast SSID. Other wireless devices will discover and connect to this device.

+wifi_basic_note_security_mode = Security Mode:

+wifi_basic_note_no_encryption = OPEN: Unencrypted mode. There are risks that network will be used by unauthorized individuals. This encryption mode isn't recommended.

+wifi_basic_note_shared = SHARED(WEP): Link authentication mode is shared key authentication, the encryption method is WEP.

+wifi_basic_note_wpa_psk_aes = WPA2(AES)-PSK: It is the secure version of WPA with implementation of the 802.11i standard.

+wifi_basic_note_wpa_psk = WPA-PSK/WPA2-PSK: WPA Pre-Shared Key (WPA-PSK). WPA2-PSK is the secure version of WPA with implementation of the 802.11i standard.

+wifi_basic_note_wpa3 = WPA3-Personal: It is the successor to WPA2.

+wifi_basic_note_wpa2_wpa3 = WPA2(AES)/WPA3-Personal: WPA2-PSK is the secure version of WPA with implementation of the 802.11i standard. WAP3 is the successor to WPA2.

+wifi_basic_note_pass_phrase = Pass Phrase: The pass-phrase contains 0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~

+wifi_basic_note_max_station_number1 = Max Station Number: You can select the maximum number of wireless terminals which can connect to the device.The Wi-Fi Hotspot connected by Internet Wi-Fi is also calculated.

+wifi_basic_note_max_station_number = Max Station Number: You can select the maximum number of wireless terminals which can connect to the device.

+

+wifi_advanced_note_whole_page = You can set Wi-Fi advanced characters on this page.

+wifi_advanced_note_band_selection = Band Selection: You can select the suitable band for your device.

+wifi_advanced_note_network_mode = Network Mode: Select the suitable Wi-Fi network mode, the device Wi-Fi performance will be improved.

+wifi_advanced_note_country_code = Country/Region Code: You can select the suitable Country/Region Code for your device.

+wifi_advanced_note_frequency = Frequency (Channel): Select appropriate channel to optimize the performance and coverage of your wireless network.

+

+ap_station_note_info = Please make sure that the IP address of Wi-Fi hotspot you''ve connected isn''t in the range of this device IP address, or you won''t have access to Internet via the Wi-Fi hotspot.

+ap_station_note_disable_info = If enable multi-SSID, Internet Wi-Fi will be disabled.

+ap_station_on_info = You can''t operate when Wi-Fi is enabled!

+

+wif_filter_note1 = Set MAC address filtering mode in the WLAN MAC Filter drop-down list box.

+wif_filter_note2 = Ruleless:Disable the WLAN MAC fliter.

+wif_filter_note3 = White List:Allow a client to connect to the device using the WLAN if the client's MAC address exists in the MAC Address list.

+wif_filter_note4 = Black List:Deny a client's connection to the device using the WLAN if the client's MAC address exists in the MAC Address list.

+

+#restart

+restart = Restart

+restart_button = Restart Device

+restart_confirm = Restart the device?

+restarting = Restarting Device

+

+#diconneted_operate_note

+diconneted_operate_note = To change current setting, please disconnect from network.

+diconneted_network_confirm = This operation may disconnect from network, continue any way?

+

+#ota_update

+ota_update = Update Management

+ota_title = Update

+ota_no_new_version = No new version found.

+ota_new_version = Found new version. Do you want to update?

+ota_connect_server = Connecting to server

+ota_connect_server_successfully = Connected to server successfully

+ota_downloading = Downloading...

+ota_download_failed = Download failed

+ota_no_network = No network

+ota_network_disconnected = Please connect to network before updating!

+ota_interrupted_alert = Found new version. Please login to update!

+ota_interrupted = Resume the downloading task which was interrupted before?

+ota_download_success = Download completed, and the device will restart. Please wait. Please do not power off, or reset factory settings, or turn off the device during the update.

+ota_pkg_download_success = Upgrade package has been downloaded already, and the device will restart. Please wait. Please do not power off, or reset factory settings, or turn off the device during the update.

+ota_update_success = Updated successfully!

+ota_update_failed = Update failed.

+ota_connect_server_failed = Unable to connect to server.

+ota_download_warning = Make sure there''s enough battery; Don''t force stop during download process.

+ota_update_warning = Attention: Don''t force stop during update process.

+ota_cancel = Update has been cancelled!

+ota_pkg_exceed = The update package is too large!

+ota_have_cancel = You have already cancelled!

+ota_roamming = The Roaming Setting is disabled. To enable it, please click in the checkbox  on this page.

+ota_low_battery = Download completed and battery is low, please charge before update!

+ota_pkg_low_battery = Upgrade package has been downloaded already,and battery is low, please charge before update!

+ota_md5_error = Check update package failed.

+ota_version = Version:

+ota_update_setting = Auto Check Settings

+ota_auto_update_switch = Auto-check New Version

+ota_update_interval_day = Auto-check Cycle

+ota_roaming_setting = Roaming Settings

+ota_update_roaming_remind = Check this option, the device will update when roaming, which will incur roaming charges.

+ota_update_manual = Check New Version

+ota_check_new_version = Check

+ota_check_new_version_desc = Click Check button for checking new version immediately.

+ota_check_roaming_confirm = You are on roaming! Would you like to continue?

+ota_update_every_day = Every day

+ota_update_15_day = 15 days

+ota_update_30_day = 30 days

+ota_new_version_checking = Checking new version...

+ota_update_running = Checking is ongoing...

+ota_check_fail = Check new version failed!

+fota_package_already_download = Upgrade package has been downloaded,after waiting for equipment to restart to complete.

+software_upload = Software Upload

+upload_update_success = The upgrade file upload successful and will be about to restart,do not power off.

+upload_update_failed0 = parse file failed.   

+upload_update_failed1 = verify file failed.   

+upload_update_failed2 = write file failed.   

+upload_update_failed3 = write update flag failed.

+upload_update_failed4 = verify flash failed.

+error_file_selected = please choose right files.

+upload_tip = Should not close,refresh or open more webui,when uploading until restart.

+########CPE more wording##############

+opmode = Change Mode

+wds = WDS

+url_filter = URL Filtering

+

+voip_settings = VoIP Settings

+voip_basic_settings = Basic Settings

+voip_user_details = User Details

+voip_advanced_settings = Advanced Settings

+voip_supplementary_service = Supplementary Service

+

+url_check = invalid URL

+url_filter_check = invalid url filter format

+sntp_invalid_server_name = Invalid URL format or invalid ip address

+server_alreay_exist = This server is already exist

+forwarding_uri_check = Invalid Value

+

+wifi_switch = Wi-Fi Switch

+ap_isolation = AP Isolation

+#mac filter

+black_list = Black List

+black_list_switch = Black List Switch

+block = Block

+black_list_max = The max number of black list is 10!

+mac_repeat_tip = Please delete the repeated MAC addresses!

+black_yourself_tip = You can''t block yourself!

+wifi_status11 = Number of users:11

+wifi_status12 = Number of users:12

+wifi_status13 = Number of users:13

+wifi_status14 = Number of users:14

+wifi_status15 = Number of users:15

+wifi_status16 = Number of users:16

+wifi_status17 = Number of users:17

+wifi_status18 = Number of users:18

+wifi_status19 = Number of users:19

+wifi_status20 = Number of users:20

+wifi_status21 = Number of users:21

+wifi_status22 = Number of users:22

+wifi_status23 = Number of users:23

+wifi_status24 = Number of users:24

+wifi_status25 = Number of users:25

+wifi_status26 = Number of users:26

+wifi_status27 = Number of users:27

+wifi_status28 = Number of users:28

+wifi_status29 = Number of users:29

+wifi_status30 = Number of users:30

+wifi_status31 = Number of users:31

+wifi_status32 = Number of users:32

+

+auto_connect = Auto Connect

+manual_connect = Manual Connect

+

+default_Gateway = Default Gateway

+primary_dns = Primary DNS Server

+secondary_dns = Secondary DNS Server

+gateway_check = Please input a valid gateway

+

+mac_filter_lable = MAC Filter Format

+

+wlan_mac_filter_0 = Ruleless

+wlan_mac_filter_1 = White List

+wlan_mac_filter_2 = Black List

+

+#SNTP

+local_current_time = Current Local Time

+time_set_mode = Time Set Mode

+time_set_time_manual = Manual Set Time

+time_set_time_auto = Sntp auto Synchronization

+year = Year

+month = Month

+date = Date

+hour = Hour

+minute = Minute

+second = Second

+sunday = Sunday

+monday = Monday

+tuesday = Tuesday

+wednesday = Wednesday

+thursday = Thursday

+friday = Friday

+saturday = Saturday

+stnp_server1 = SNTP Server1

+stnp_server2 = SNTP Server2

+stnp_server3 = SNTP Server3

+time_zone = Time Zone

+daylight_saving_time = Daylight Saving Time

+daylightsave_0 = Disable

+daylightsave_1 = Enable

+sntp_syn_time_wan_connected = SNTP time synchronization can be used after networking!

+operation_not_supported = operation not supported!

+network_terminated = USSD terminated by network

+upgrade_file_nomatch = You do not select the root_uImage or modem.zip!

+upgrade_confirm = Do you really want to upgrade the Image?

+upgrading = Upgrading, please wait....

+upgrading_alert = Upgrading, please don''t cut off your power supply. After upgrade, it will restart automaticly!

+upgrad_note = Please select the version you want to upgrade, then click the ''Apply'' button to start upgrade.

+sntp_processing = Synchronizing, please wait....

+sntp_req_success = The SNTP request has been sent!

+time_zone_<-12>12_0 = (GMT-12:00) Dateline West

+time_zone_SST11_0 = (GMT-11:00) Midway Islands, Samoa

+time_zone_<-10>10_0 = (GMT-10:00) Hawaii

+time_zone_<-09>9_0 = (GMT-09:00) Alaska

+time_zone_PST8PDT,M3.2.0,M11.1.0_0 = (GMT-08:00) Pacific time (USA and Canada), Tijuana

+time_zone_<-07>7_0 = (GMT-07:00) Mountain time (USA and Canada)

+time_zone_<-07>7_1 = (GMT-07:00) Arizona

+time_zone_MST7MDT,M4.1.0,M10.5.0_2 = (GMT-07:00) Chihuahua, La Paz, Mazza Tran

+time_zone_<-06>6_0 = (GMT-06:00) Saskatchewan

+time_zone_<-06>6_1 = (GMT-06:00) Central time (USA and Canada)

+time_zone_<-06>6_2 = (GMT-06:00) Central America

+time_zone_<-06>6_3 = (GMT-06:00) Guadalajara City, Mexico City, Monterey

+time_zone_<-05>5_0 = (GMT-05:00) Bogota, Lima, Quito

+time_zone_<-05>5_1 = (GMT-05:00) Eastern time (USA and Canada)

+time_zone_EST5EDT,M3.2.0,M11.1.0_2 = (GMT-05:00) Indiana (East)

+#time_zone_-4.5 = (GMT-04:30)

+time_zone_AST4ADT,M3.2.0,M11.1.0_0 = (GMT-04:00) Atlantic time (Canada)

+time_zone_<-04>4_1 = (GMT-04:00) Caracas, La Paz

+time_zone_<-04>4<-03>,M8.2.6/24,M5.2.6/24_2 = (GMT-04:00) Santiago

+time_zone_NST3:30NDT,M3.2.0,M11.1.0_0 = (GMT-03:30) Newfoundland

+time_zone_<-03>3_0 = (GMT-03:00) Brasilia

+time_zone_<-03>3_1 = (GMT-03:00) Buenos Aires, Georgetown

+time_zone_<-03>3_2 = (GMT-03:00) Greenland

+time_zone_<-02>2_0 = (GMT-02:00) Mid-Atlantic

+time_zone_<-01>1_0 = (GMT-01:00) Cape Verde Islands

+time_zone_<-01>1<+00>,M3.5.0/0,M10.5.0/1_1 = (GMT-01:00) Azores

+time_zone_GMT0IST,M3.5.0/1,M10.5.0_0 = (GMT) GMT: Dublin, Edinburgh, London, Lisbon

+time_zone_WET0WEST,M3.5.0,M10.5.0/3_1 = (GMT) Casablanca, Monrovia

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_0 = (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_1 = (GMT+01:00) Belgrad, Bratislava, Budapest, Ljubljana, Prague

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_2 = (GMT+01:00) Brussels, Copenhagen, Madrid, Paris

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_3 = (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb

+time_zone_<+01>-1_4 = (GMT+01:00) Western Central African

+time_zone_EET-2EEST,M3.5.0/3,M10.5.0/4_0 = (GMT+02:00) Bucharest

+time_zone_CAT-2_1 = (GMT+02:00) Pretoria, Harare

+time_zone_EET-2EEST,M3.5.0/3,M10.5.0/4_2 = (GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius

+time_zone_EET-2_3 = (GMT+02:00) Cairo

+time_zone_EET-2EEST,M3.5.0/3,M10.5.0/4_4 = (GMT+02:00) Athens, Beirut, Istanbul, Minsk

+time_zone_IST-2IDT,M3.4.5/02:00:00,M10.5.0/02:00:00_5 = (GMT+02:00) Jerusalem

+time_zone_<+03>-3_0 = (GMT+03:00) Baghdad

+time_zone_<+03>-3_1 = (GMT+03:00) Riyadh, Kuwait

+time_zone_<+03>-3_2 = (GMT+03:00) Moscow, St Petersburg, Volgograd

+time_zone_EAT-3_3 = (GMT+03:00) Nairobi

+time_zone_<+0330>-3:30<+0430>,J80/0,J264/0_0 = (GMT+03:30) Teheran

+time_zone_<+04>-4_0 = (GMT+04:00) Abu Zabi, Muscat

+time_zone_<+04>-4_1 = (GMT+04:00) Baku, Tbilisi, Yerevan

+time_zone_<+0430>-4:30_0 = (GMT+04:30) Kabul

+time_zone_<+05>-5_0 = (GMT+05:00) Yekaterinburg

+time_zone_PKT-5_1 = (GMT+05:00) Islamabad, Karachi, Tashkent

+time_zone_<+0530>-5:30_0 = (GMT+05:30) Madras, Calcutta, Mumbai, New Delhi

+time_zone_<+0545>-5:45_0 = (GMT+05:45) Kathmandu

+time_zone_<+06>-6_0 = (GMT+06:00) Ala Mutu, Novosibirsk

+time_zone_<+06>-6_1 = (GMT+06:00) Dhaka, Astana

+time_zone_<+06>-6_2 = (GMT+06:00) Sri Haya Ed Denny Pla

+time_zone_<+0630>-6:30_0 = (GMT+06:30) Yangon

+time_zone_<+07>-7_0 = (GMT+07:00) Krasnoyarsk

+time_zone_<+07>-7_1 = (GMT+07:00) Bangkok, Hanoi, Jakarta

+time_zone_CST-8_0 = (GMT+08:00) Beijing, Chongqing, Hongkong Special Administrative Region, Urumqi

+time_zone_<+08>-8_1 = (GMT+08:00) Kuala Lumpur, Singapore

+time_zone_AWST-8_2 = (GMT+08:00) Perth

+time_zone_CST-8_3 = (GMT+08:00) Taipei

+time_zone_<+08>-8_4 = (GMT+08:00) Irkutsk, Ulam Batu

+time_zone_JST-9_0 = (GMT+09:00) Osaka, Sapporo, Tokyo

+time_zone_KST-9_1 = (GMT+09:00) Seoul

+time_zone_<+09>-9_2 = (GMT+09:00) Yakutsk

+time_zone_ACST-9:30ACDT,M10.1.0,M4.1.0/3_0 = (GMT+09:30) Adelaide

+time_zone_ACST-9:30_1 = (GMT+09:30) Darwin

+time_zone_AEST-10_0 = (GMT+10:00) Brisbane

+time_zone_<+10>-10_1 = (GMT+10:00) Vladivostok

+time_zone_<+10>-10_2 = (GMT+10:00) Guam, Port Moresby

+time_zone_AEST-10AEDT,M10.1.0,M4.1.0/3_3 = (GMT+10:00) Hobart

+time_zone_AEST-10AEDT,M10.1.0,M4.1.0/3_4 = (GMT+10:00) Canberra, Melbourne, Sydney

+time_zone_<+11>-11_0 = (GMT+11:00) Magadan, Solomon islands, New Caledonia

+time_zone_<+12>-12_0 = (GMT+12:00) Wellington, Oakland

+time_zone_<+12>-12_1 = (GMT+12:00) Fiji, Kamchatka, Marshall Islands

+time_zone_<+13>-13_0 = (GMT+13:00) Nukualofa

+

+#operation mode

+opmode_auto = Automatic

+opmode_bridge = Bridge Mode

+opmode_cable = Cable Broadband Mode

+opmode_gateway = Wireless Broadband Mode

+EthPort_Status = Ethernet Port Status

+change_mode = Change Mode

+current_mode = Current Mode:

+change = Change

+change_mode_alert = Cable Broadband mode can only use Wi-Fi to access, please remember Wi-Fi SSID and password! Continue?

+opmode_msg1 = If wireless broadband mode is enabled, please remove network cable of public network.

+opmode_msg2 = The device will be restarted when operation mode is changed.

+opmode_msg3 = The network cable of public network has been removed.

+#pppoe dial

+pppoe_mode = PPPoE

+pppoe_success = PPPoE dial successfully

+pppoe_fail = PPPoE dial failed

+pppoe_processing = PPPoE dialing

+static_success = Successfully set static IP

+static_fail = Set static IP failed

+static_processing = Setting static IP

+dyn_success = Successfully obtained dynamic IP

+dyn_fail = Obtain dynamic IP failed

+dyn_processing = Obtaining dynamic IP

+pppoe_msg = The network cable of public network has been removed

+pppoe_message_send_fail = Send message failed!

+ip_gate_not_same = IP Address and Default Gateway can''t be same!

+ip_innergate_not_same = IP Address and  LAN IP address of the router can''t be in the same segment!

+auto_success = AUTO dial successfully

+auto_fail = AUTO dial failed

+auto_processing = AUTO dialing

+#url filter

+url_filter_list = Current URL Filtering

+url_filter_max = The maximum number of URL filter rules is {0}

+url_repeated = This URL already exists.

+url_note1 = You can set the web address of URL filter to protect your network from some of the bad site.

+url_note2 = URL: Set the URL address that needs to be filtered.

+

+#wds

+wds_mode = WDS Mode

+wds_mode_0 = Disable

+wds_mode_1 = RootAP Mode

+wds_mode_2 = Bridge Mode

+wds_mode_3 = Repeater Mode

+repeater_ssid = Repeater SSID

+wpa_algorithms = WPA Algorithms

+enable_wds_confirm = If enable WDS, Wi-Fi basic settings will be disabled. Continue?

+#sys log

+sys_log = System Log

+log_setting = Log Settings

+syslog_mode_all = All

+syslog_mode_wan_connect = WAN Connect

+syslog_mode_sms = SMS

+syslog_mode_tr069 = tr069

+syslog_mode_voip = VoIP

+syslog_mode_dlna = DLNA

+syslog_mode_wlan = WLAN

+syslog_mode_router = Router

+view_log = View log

+log_info = Log information

+

+#add at 2013.6.20

+periodic_inform = Periodic Inform

+periodic_inform_interval = Periodic Inform Interval

+periodic_inform_time = Periodic Inform Time

+certificate_import = Certificate

+import_certificate_btn = Import

+certificate_file_nomatch = You do not select the ca-cert.crt!

+#voip setting

+outbound_mode = Outbound Mode

+outbound_server = Outbound Server

+outbound_port = Outbound Port

+stun_mode = STUN Mode

+stun_server = STUN Server

+register_every = Register Every

+advanced_options = Advanced Options

+sip_port = SIP Port

+rtp_port = RTP Port

+voip_outbound_port_check = Invalid port.

+voip_time_check = Invalid register time.

+timeRange = [1, 3600] seconds

+voip_sip_port_check = Invalid port.

+voip_port_compare = Invalid port range.

+warn_information = The parameters of VoIP set success, please register again.

+#voip user details

+user_details_title = SIP Server and Configuration

+sip_register_server = SIP Register Server

+sip_domain = SIP Domain

+sip_realm = SIP Realm

+sip_proxy_mode = SIP Proxy Mode

+sip_proxy_server = SIP Proxy Server

+authorization = Authorization

+display_name = Display Name

+authorized_user_name = Authorized User Name

+authorized_password = Authorized Password

+voip_register_status = VoIP Register Status

+register_failed = Register Fail

+register_success = Register Success

+register_connecting = Register Connecting

+unregister = Unregister

+deregister = Deregister

+sip_domain_check = SIP Domain Address invalid

+sip_realm_check = SIP Realm invalid

+sip_proxy_server_check = IP Proxy Server invalid

+display_name_check = Display Name invalid

+authorized_username_check = Authorized User Name invalid

+account_password_check = Password invalid

+#voip advanced settings

+sip_advanced_options = Advanced Options

+adv_sip_t38 = T.38 FAX Encoder

+sip_dtmf = DTMF

+voip_sip_dtmf_method_inband = InBand

+voip_sip_dtmf_method_rfc2833 = RFC2833

+voip_sip_dtmf_method_sipinfo = SIPInfo

+sip_encoder = Encoder

+voip_sip_encoder_method_0 = G.711 u-Law

+voip_sip_encoder_method_1 = G.711 a-Law

+voip_sip_encoder_method_2 = G.722

+voip_sip_encoder_method_3 = G.729

+voip_sip_encoder_method_4 = G.726-16kps

+voip_sip_encoder_method_5 = G.726-24kps

+voip_sip_encoder_method_6 = G.726-32kps

+voip_sip_encoder_method_7 = G.726-40kps

+sip_vad = VAD

+sip_cng = CNG

+#voip supplementary service

+sip_protocol_voip = VoIP supplementary service

+sip_protocol_call_forw = Call Forwarding

+voip_forwarding_mode_1 = Unconditional forwarding

+voip_forwarding_mode_2 = When busy

+voip_forwarding_mode_3 = When no answer

+voip_forwarding_mode_0 = Cancel all forwarding

+sip_protocol_forw_uri = Forwarding URI

+show_msg = Please press '*80' on the phone!

+sip_protocol_incoming_call = Do Not Disturb

+sip_protocol_call_waiting = Call Waiting

+wds_note = WDS: Wireless Distribution System

+#voip user details

+connect_note = Please connect to internet if you want to use VoIP phone!

+#fota

+upgrade_pack_fix_success = Upgrade success!

+upgrade_pack_fix_failed = Upgrade failed!

+have_new_version = New version is found,the device will update.

+

+######key same value different###########

+dmz_note_info = If a terminal device can''t run network applications via this device, please enter IP address of the terminal device in the entry box when DMZ is enabled.

+dlna_note_info = DLNA: Digital Living Network Alliance.

+dlna_note_httpshare = You can set Digital Media Server (DMS) device name, and media type which you want to share on this page.

+#############串口转网口###################

+switch_port_title = Switch ethernet port to serial port

+open_serial_port = Turn ethernet port to serial port

+close_serial_port = Close ethernet port to serial port

+switching = switching...

+##############定时重启功能wording###################

+restart_schedule = Restart Schedule

+enable_reboot_switch = Turn on automatic restart function

+enable_reboot_byday = Automatic restart schedule based on every day

+enable_reboot_byweek = Automatic restart schedule based on the week

+enable_reboot_bymonth = Automatic restart schedule based on the month

+synchronized = synchronized

+unsynchronized = unsynchronized

+week = Week

+login_password_length_check = Please input 4 characters at least.

+system_time_not_syn = System time not synchronized!

+fota_note1 = You can set up an auto-check cycle for your device, so that the device automatically detects whether there is a new version of the software.

+local_note = You can choose the upgrade file on the local computer, upgrade the device software to the selected version, complete the system repair and optimization.

+

+#new word

+modify_password = Modify Login Password

+

+#parental control

+parental_control = Parental Control

+pc_children_group = Kids Devices

+pc_children_group_manage = Kids Manage

+pc_manage = Manage

+pc_no_children_device = Not set Kids Devices

+pc_children_group_desc = All kids devices will follow network access policy

+pc_edit_host_name = Edit the hostname:

+pc_internet_rule = Network Access Policy

+pc_time_limited =  Online Time Setting

+pc_site_white_list = Website Whitelist

+pc_manage_children_group = Manage Kids Devices

+pc_current_attached_devices = Current Devices

+pc_action = Operation

+pc_remove = Remove

+pc_remove_all = Remove All

+pc_add = Add

+pc_leave = Leave

+pc_add_white_site = Add The White List

+pc_in_child_group = Added as kids device

+pc_forbid_time = Not Allow

+pc_allow_time = Allow

+pc_setting_desc = Click with your mouse to allow or forbid network access

+pc_name = Name

+pc_link = URL

+pc_not_save = Data not saved, please pay attention to save

+pc_link_exist = URL already exists!

+no_data = No data

+sun = SUN

+mon = MON

+tues = TUES

+wed = WED

+thur = THUR

+fri = FRI

+sat = SAT

+

+#定时休眠唤醒

+tsw_settings = Wi-Fi Awake Settings

+tsw = Wi-Fi Awake

+time_sleep_wake_up = Wi-Fi Awake Settings

+tsw_timer_on = Wake-up Time

+tsw_timer_off = Sleep Time

+tsw_sys_time_mode_alert = Please connect to the network and using the SNTP auto synchronizing time.

+tsw_time_interval_alert = The time interval should not be less than 10 minutes.

+

+#new wording

+advanced_settings = Advanced Settings

+others = Others

+others_restart_reset = Restart and Reset

+others_note_info = Please login again after rebooting or resetting router

+

+pwd_sub_title = Manage information about your wireless router

+pwd_note = When you log in wireless router, need to input this password (password is different from your wireless network password)

+current_network = Current Network

+

+wifi_wireless_settings = Wi-Fi Settings

+wifi_main_sub_title = Set up wireless hotspot so that your mobile phone or laptop could access network via it

+wifi_broadcast_desc = SSID Broadcast

+wifi_isolated_desc = All the wireless client device is completely isolated

+

+detail_info = Detail Information

+sd_u_share = SD Sharing

+

+settings_wireless = Wi-Fi Settings

+settings_internet = Network Settings

+not_connect_network = Disconnected

+

+traffic_data_plan = Statistics

+traffic_pie_title = Data Plan

+traffic_sub_title = You can create statistic plan, query used and left statistic

+traffic_used = Used

+traffic_used_text = {0} Used

+traffic_limit_data = Data Plan

+traffic_limit_data_text = {0} Data Plan

+traffic_alert_reach_text = When reached {0}%, {1} to remind me

+traffic_data_left_text = {0} of remaining

+traffic_when = When reached

+traffic_remind_me = %, to remind me

+traffic_remind_me_time = , to remind me

+traffic_limit_time_text = {0} Plan

+traffic_limit_time_h = {0} Hour(s) Plan

+traffic_limit_time_m = {0} Minute(s) Plan

+traffic_not_set_limited = Not set, click Settings

+

+echarts_used = Used

+echarts_left1 = Left

+echarts_alert = Alert

+echarts_alarm = Used(exceed alert)

+echarts_free = Left

+echarts_full = Exceed

+echarts_no = Not set

+

+3g = 3G

+wan = WAN

+connection_mode = Connection Mode

+wireless_access_device = Wireless Access Device

+cable_access_device = Cable Access Devices

+station_info_sub_title = All of wireless devices connected to this router will show on the page, including device name and MAC address

+station_info_desc = More access control options, please click here

+

+device_unit = &nbsp;

+ota_last_update_check = Last Update Time:

+main_ssid_num = Main SSID ({0})

+guest_ssid_num = Guest SSID ({0})

+wifi_slider_desc = * Drag the progress bar has adjusted the SSID maximum access number

+wif_guest_disabled = Guest SSID is disabled

+

+phone_number = Number

+equalToPin = The PINs you've entered do not match

+equalToPassword = The passwords you've entered do not match

+

+pppoe_mode_type_PPPOE = PPPoE

+pppoe_mode_type_STATIC = Static IP

+pppoe_mode_type_DHCP = Dynamic IP

+pppoe_mode_type_AUTO = Auto

+

+tsw_note = Awake Settings: When awake settings is enabled, device will automatically sleep; Wi-Fi will be unavailable.

+tsw_note_on = Wake-up Time: You can set the wake-up time.

+tsw_note_off = Sleep Time: You can set the sleep time.

+

+parent_control_note_kids = Kids Devices: Show Kids devices.

+parent_control_note_manage = Kids Management: Manage Kids devices.

+parent_control_note_time = Online Time Setting: Set online time for kids.

+parent_control_note_whitelist = Website Whitelist: Set website white list for kids to access websites.

+

+wan_note_dial = Dial-up Mode:

+wan_note_connection_mode = Please select network connection mode for your device:

+wan_note_connection_mode_pppoe = PPPoE: Access Internet. You may ask your network provider for PPPoE username and password.

+wan_note_connection_mode_dhcp =  Dynamic IP: Access Internet via dynamic IP address.

+wan_note_connection_mode_static = Static IP: Access Internet via static IP address. Please set IP address, subnet mask, default gateway, primary and secondary DNS.

+wan_note_user_name = User Name: Enter your PPPoE account.

+wan_note_password = Password: Enter your PPPoE password.

+wan_note_connection_mode_auto = AUTO: Access Internet via dynamic IP address or PPPoE. You may ask your network provider for PPPoE username and password.

+parent_control_note_siteName = The White List namecan''t contain following characters: < > [ ] * $ & : , ; " ' ` / \\ | ? ¥

+parent_control_note_siteLink = The white list link should start with "http://" or "https://".

+firewal_note = Note : Firewall''s related rule settings may not take effect immediately, need to wait for a few minutes or restart the device. If you need to take effect immediately, it is recommended to restart the device.

+

+wps_pin_validator = Please input a valid PIN number

+device_rename = Please input a valid name.

+

+turnoff_button = Turn Off Device

+others_turn_off= Turn Off Device

+turnoff_confirm  = Turn Off the device?

+turnoff = Turn Off...

+setting_no_change = Your settings did not change.

+Extend_accessDevice = The Max Station Number is not less than current access device number.

+

+TBcheck = Please input a value between 1 and 4095

+apn_pdptype_change_note = If the setting is changed,you may have a risk not to visit the Webpage by {0}. Then please try {1} to visit.

+apn_alert = This operation may restart the device. Continue any way?

+apn_alert_restart = The default APN settings are successful and the device is being restarted.

+apn_diconneted_network_confirm = This operation may disconnect from network, continue any way?

+

+#super

+super = Lock cell Settings

+lockCell_settings = Lock cell Settings

+v4_settings = Lock(V4 Encryption)

+cell_id1 = Cell Id 1

+cell_id2 = Cell Id 2

+cell_id3 = Cell Id 3

+cell_id4 = Cell Id 4

+cell_id5 = Cell Id 5

+v4_check = Invalid character, The character must be 0-9, a-z, A-Z

+v4_note = Your settings will take effect after restarting your device,Do you want to continue?

+

+export_title = Export settings

+band_3 = Band 3

+band_8 = Band 8

+band_38 = Band 38

+band_39 = Band 39

+band_40 = Band 40

+band_info = Band Settings

+cell_id = Current registration Cell

+lock_apply = Lock

+unlock_apply= Unlock

+sinr = SINR

+band_cell_settings = Band Cell Settings

+export = Export

+cell_not_correct= Not Lock Cell,Connected Fail!

+cell_id_lock = Locked Cell

+

+sip_uri_format = URI format

+user_name = User Name

+pin_v4_encrypt = PIN encrypt

+wep_cannot_2040 = When Current Security Mode of Main SSID or Guest SSID is OPEN (WEP) or SHARED, Channel Bandwidth can''t be 20MHz/40MHz!

+2040_cannot_wep = When Channel Bandwidth is 20MHz/40MHz, Current Security Mode of SSID can''t be OPEN (WEP) or SHARED.

+wifi_device_busy = Wi-Fi driver is busy, please wait...

+manufactory_code = Manufactory Code

+key_version_number = Key Version Number

+key_value = Key Value

+

+white_list = White List

+black_enable= Black list

+white_enable = White list

+mac_white_address = MAC Address

+max_white_list = The maximum number of white list is 6.

+LockCell_note1 =  Cell locking is for the LTE network community lock, the current registration area and locking the same cell allows network, currently registered residential and residential lock inconsistent when inhibit the initiation network.

+LockCell_note2 =  Residential lock to open and save the locking area not is empty, network community of the current registration of every boot and timing 8:00/14:00/20:00 ratio on the and locking area is the same, if different is broken network processing.

+mac_blank = MAC Address can''t be empty.

+

+vlan_switch = VLAN Switch

+vlan_notice = If you choose the Disable, it will take effect after restarting your device. Do you want to continue?

+vlan_notice2 = If you want to Enable this function, the Multi SSID Switch must be Enable. Do you want to open Multi SSID Switch and Enable this function?

+ap_hide = AP Hide

+

+urlparent = The end of URL can''t follow with /.

+not_change_mode = The device is setting parameters, please wait...

+#device

+device_status = Device Status

+device_status_0 = Decrypted

+device_status_1 = Encrypted

+

+######DDNS###########

+ddns = DDNS

+Hash value is empty = Hash value is empty!

+DDNS Provider is empty = DDNS Provider is empty!

+register successful = Register successful

+login error = Login error

+network error = Network error

+registering = Registering

+not registered = Not registered

+error registering = Error registering

+error = error

+ddns_set_mode = DDNS

+mode_set_mode_1 = Enable

+mode_set_mode_0 = Disable

+mode_select_auto = Auto

+mode_select_manual = Manual

+ddns_mode = DDNS Mode

+Auto = Auto

+Manual = Manual

+DDNS_Status = DDNS Status

+DDNSHashValue = Hash Value

+ddns_ProviderList = Dynamic DNS Provider

+ddns_account = Account

+ddns_passwd = Password

+ddns_domainName = Domain Name

+ddns_hashvalue_check = Invalid character, The character must be 0-9, a-z, A-Z or =

+ddns_note1 = You can set the dynamic domain name service to assign a fixed domain name for the dynamic IP WAN address.

+ddns_note2 = Dynamic DNS Provider: Set the server which will provide dynamic domain name service.

+ddns_note3 = Password: The pass-phrase contains: 0-9 a-z A-Z ! # $ * + , - . % : = ? @ [ ] ^ _ { | } ~ 

+ddns_note4 = Domain Name: Set the domain name you want to apply for.

+ddns_note5 = Hash Value: DDNS hash value, you need to fill in the Hash value when select the freedns server. It contains: 0-9 a-z A-Z 或 = 

diff --git a/ap/app/zte_webui_min/i18n/Messages_zh-cn.properties b/ap/app/zte_webui_min/i18n/Messages_zh-cn.properties
new file mode 100755
index 0000000..ca42078
--- /dev/null
+++ b/ap/app/zte_webui_min/i18n/Messages_zh-cn.properties
@@ -0,0 +1,1694 @@
+#menu 中文字符

+pc_version = PC版

+mobile_version = 手机版

+home = 首页

+phonebook = 电话本

+sms = 短信

+sd = SD卡

+setting = 设置

+status = 基本信息

+net_select = 找网方式

+dial_setting = 拨号设置

+apn_setting = APN设置

+wifi_advance = 高级设置

+management = 管理

+net_setting = 联网设置

+quick_setting = 快速设置

+

+device_info = 状态信息

+traffic_statistics = 流量统计

+traffic_alert = 流量管理

+

+wifi = Wi-Fi 设置

+wifi_basic = 基本设置

+device_setting = 设备设置

+sim = SIM卡侧

+device = 设备侧

+router_setting = 路由

+mac_filter = 无线MAC过滤

+

+wps = WPS

+sleep_mode = 省电

+lan = 局域网

+

+firewall = 防火墙

+system_security = 系统安全

+port_forward = 端口转发

+port_filter = 端口过滤

+fastboot = 快速开机

+display_password = 显示密码

+display_QR = 显示二维码

+cable = 有线

+wireless = 无线

+

+my_router = 网络设置

+net_surfing = 网络连接

+

+#validate

+phonenumbers_check = 最多可输入 5 个电话号码,并且用 ';' 将号码隔开

+required = 必填项

+remote = 请修正该字段

+url = 请输入有效的网址

+siteLink_check = 请输入有效的网址

+siteName_check = 请输入有效的网站名

+date = 请输入有效的日期

+dateISO = 请输入有效的日期 (ISO)

+number = 请输入有效的数字

+digits = 只能输入整数

+decimalRange = 请输入正数且小数位最多2位

+any_digits = 只能输入整数

+creditcard = 请输入有效的信用卡号

+equalTo = 请再次输入相同的值

+accept = 请输入拥有效后缀名的字符串

+maxlength = 最多输入 {0} 个字符

+minlength = 最少输入 {0} 个字符

+rangelength = 请输入一个长度介于 {0} 和 {1} 之间的字符串

+range = 请输入一个介于{0}和{1}之间的值

+max = 请输入一个最大为 {0} 的值

+min = 请输入一个最小为 {0} 的值

+ssid = 请输入有效的 SSID

+ssid_ap = 请输入有效的 SSID(无效字符包括 , ; " \)

+email_check = 请输入有效的邮箱

+ipv4 = 请输入有效的 IP 地址

+ipv6 = 请输入有效的 IPv6 地址

+name_check = 请输入有效的姓名

+phonenumber_check = 请输入有效的电话号码

+sms_service_center_check = 请输入有效的短信中心号码

+pin_check = 请输入 4 到 8 位的数字

+puk_check = 请输入 8 位数字

+password_check = 请输入有效的密码

+subnetmask_check = 无效的子网掩码

+dns_check = 无效的 DNS,DNS不能为255.255.255.255或0.0.0.0

+dhcp_check = DHCP 的 {0}IP 超出局域网子网范围

+start = 起始

+end = 结束

+dhcpCompare = 无效的 IP 地址,起始地址不能大于结束地址

+ipRange = IP 地址池不能包含局域网 IP 地址(DHCP 起始地址应该比局域网 IP 地址大)

+lanip_check = 请输入有效的 IP 地址

+ip_check = 请输入完整且有效的 IP 地址

+dmz_ip_check = 请输入有效的 IP 地址

+wps_pin_check = 无效的 PIN

+wps_pin_length_check = 请输入4位或8位数字

+browse_sdcard = 查看 SD 卡

+portCompare = 无效的端口范围

+comment_check = 无效字符

+check_file_path = 文件夹名称中包含无效的字符

+check_filefold_name = 文件夹名称中包含无效的字符: ` ~ # & * + | \ : ? / < > . " '

+apn_check = 请输入有效的 APN

+ppp_username_check = 请输入有效的用户名

+ppp_password_check = 请输入有效的密码

+unlock_code_check =  请输入正确的解锁码。解锁码只能输入 0-9、a-f、A-F,并且长度为 16 个字符

+apn_profile_name_check = APN 配置文件名称中包含无效的字符

+dlna_name_check = 设备名称只能输入 0-9、a-z、A-Z 或 _

+wifi_password_check = 请输入有效的密码

+wifi_wep_password_check = 请输入 5 或 13 位ASCII密钥,或者输入 10 或 26 位 Hex 密钥。

+range_except = 请输入有效值,有效范围:{0}-{1}。(32000-32007 的范围值除外)。

+

+#common

+copyright = Copyright &copy; 2010-2022 示例公司 版权所有

+enable=启用

+disable=关闭

+apply= 应用

+cancel = 取消

+clear = 清除

+reset = 重置

+add = 添加

+add_new = 新增

+save = 保存

+new = 新建

+view = 查看

+select = 选择

+edit = 编辑

+delete = 删除

+delete_all = 删除所有

+success_info = 成功

+error_info = 失败

+connect = 连接

+disconnect = 断开连接

+connected = 已连接

+disconnected = 已断开连接

+connecting = 正在连接…

+disconnecting = 正在断开连接…

+cancelconnect = 取消连接

+confirm = 确认

+prompt = 提示

+info = 信息

+alert = 提醒

+yes = 是

+no = 否

+ok = 确定

+back = 返回

+exit = 退出

+next_step = 下一步

+prev_step = 上一步

+next_page = &gt;&gt;

+prev_page = &lt;&lt;

+root = 根目录

+create = 创建

+speed = 速率

+upload = 上传

+download = 下载

+uploaded = 已上传

+downloaded = 已下载

+on = 打开

+off = 关闭

+need_login_again = 您的帐户已退出,请重新登录。

+modify = 更改

+content = 内容

+time = 时间

+processing = 处理中…

+saving = 保存中…

+deleting = 删除中…

+scanning = 状态:扫描中…

+dlna_scanning = 状态:扫描中…

+scanned = 状态:扫描结束。

+need_rescan = 状态: 需要重新扫描。

+sending = 发送中…

+creating = 创建中…

+uploading = 上传中…

+waiting = 请稍等…

+leave_page_info = 您有未保存的修改。您确定要继续吗?

+colon = :

+page = 页码:

+go = 跳转

+ALL = 全部

+open_source_licenses = 开放源代码许可

+vertical_bar = |

+

+#security

+security_policy = 安全策略

+security_mode = 安全模式

+security_mode_OPEN = OPEN

+security_mode_SHARED = SHARED

+security_mode_WPA2PSK = WPA2(AES)-PSK

+security_mode_WPAPSKWPA2PSK = WPA-PSK/WPA2-PSK

+security_mode_WPA3Personal = WPA3-Personal

+security_mode_WPA2WPA3 = WPA2(AES)/WPA3-Personal

+wpa = WPA

+pass_phrase = 密码

+

+#Station

+station_info = 接入设备

+station_number = 序号

+host_name = 主机名

+

+#Wifi Basic

+multi_ssid_enable = 多重网络名称开关

+multi_ssid_1 = 主SSID

+multi_ssid_2 = 副SSID

+multi_ssid_enable_confirm = 如果开启“多重网络名称”,Internet Wi-Fi 功能将会停用。您要继续吗?

+multi_ssid_enable_confirm2 = 如果开启“多重网络名称”,Internet Wi-Fi 功能将会停用。且已连接的 Wi-Fi 设备可能需要重连。您要继续吗?

+multi_ssid_max_access_number_alert = 主SSID 和 副SSID 的最大接入数之和不能超过 {0}!

+network_band_selection = 频段选择

+network_mode = 网络模式

+network_name = 网络名称(SSID)

+broadcast_network_name = SSID 广播

+country_region_code = 国家/地区 码

+frequency_channel = 信道

+rate = 速率

+max_station_number = 最大接入数

+wifi_basic_note = 点击“应用”时,任意已连接的 Wi-Fi 设备需要重新连接。

+wifi_disconnect_confirm = 所有已连接的 Wi-Fi 设备需要重连。您要继续吗?

+wifi_disconnect_confirm2 = 已连接的 Wi-Fi 设备可能需要重连。您要继续吗?

+network_mode_2 = 仅 802.11 n

+network_mode_4 = 802.11 b/g/n

+network_mode_5 = 仅 802.11 a

+network_mode_6 = 802.11 b/g/n/ax

+frequency_channel_0 = 自动

+frequency_channel_1 = (频道 1)

+frequency_channel_2 = (频道 2)

+frequency_channel_3 = (频道 3)

+frequency_channel_4 = (频道 4)

+frequency_channel_5 = (频道 5)

+frequency_channel_6 = (频道 6)

+frequency_channel_7 = (频道 7)

+frequency_channel_8 = (频道 8)

+frequency_channel_9 = (频道 9)

+frequency_channel_10 = (频道 10)

+frequency_channel_11 = (频道 11)

+frequency_channel_12 = (频道 12)

+frequency_channel_13 = (频道 13)

+frequency_channel_14 = (频道 14)

+frequency_channel_15 = (频道 15)

+frequency_channel_16 = (频道 16)

+frequency_channel_17 = (频道 17)

+frequency_channel_18 = (频道 18)

+frequency_channel_19 = (频道 19)

+frequency_channel_20 = (频道 20)

+frequency_channel_21 = (频道 21)

+frequency_channel_22 = (频道 22)

+frequency_channel_23 = (频道 23)

+frequency_channel_24 = (频道 24)

+frequency_channel_25 = (频道 25)

+frequency_channel_26 = (频道 26)

+frequency_channel_36 = (频道 36)

+frequency_channel_40 = (频道 40)

+frequency_channel_44 = (频道 44)

+frequency_channel_48 = (频道 48)

+frequency_channel_149 = (频道 149)

+frequency_channel_153 = (频道 153)

+frequency_channel_157 = (频道 157)

+frequency_channel_161 = (频道 161)

+frequency_channel_165 = (频道 165)

+rate_0 = 自动

+rate_1 = 1 Mbps

+rate_2 = 2 Mbps

+rate_3 = 5.5 Mbps

+rate_4 = 6 Mbps

+rate_5 = 6.5 Mbps

+rate_6 = 9 Mbps

+rate_7 = 11 Mbps

+rate_8 = 12 Mbps

+rate_9 = 13 Mbps

+rate_10 = 18 Mbps

+rate_11 = 19.5 Mbps

+rate_12 = 24 Mbps

+rate_13 = 26 Mbps

+rate_14 = 36 Mbps

+rate_15 = 39 Mbps

+rate_16 = 48 Mbps

+rate_17 = 52 Mbps

+rate_18 = 54 Mbps

+rate_19 = 58.5 Mbps

+rate_20 = 65 Mbps

+cannot_operate_when_wifi_connected = Wi-Fi 连接时无法进行该操作!

+network_mode_select_2 = 仅 802.11 n

+network_mode_select_3 = 802.11 b/g

+network_mode_select_4 = 802.11 b/g/n

+network_mode_select_6 = 802.11 b/g/n/ax

+network_modes_band_select_2 = 仅802.11 n

+network_modes_band_select_4 = 802.11 a/n

+network_modes_band_select_5 = 仅 802.11 a

+

+#net select

+auto_select = 自动

+manual_select = 手动

+auto_select_type_WCDMA_preferred = 自动

+auto_select_type_LTE_preferred = 自动

+auto_select_type_NETWORK_auto = 自动

+auto_select_type_Only_LTE = 仅4G

+auto_select_type_WCDMA_AND_LTE = 仅4G/3G

+auto_select_type_Only_WCDMA = 仅3G

+auto_select_type_TD_W = 仅3G

+auto_select_type_Only_GSM = 仅2G

+

+search = 搜索

+searching_net = 搜索中,请稍候...

+registering_net = 注册中,请稍候...

+network_list = 网络列表

+register = 注册

+auto = 自动

+unknown = 未知

+available = 可用

+current = 当前

+forbidden = 禁止

+net_select_note_automatic = 自动:该设备将会自动搜索可用网络。

+net_select_note_manual = 手动:将会手动搜索可用网络。

+net_status = 网络状态

+mccmnc = MCCMNC

+option = 选项

+networktype = 网络类型

+subnet = 制式

+

+#home

+ap_station_clear = 清空

+current_flux = 当前流量

+total_flux = 已用总流量

+connected_time = 持续时间

+flux_up = 上传速率

+flux_down = 下载速率

+traffic_current_connection = 当前连接

+traffic_current_month_data = 当月

+traffic_total_traffic = 已用总流量

+traffic_used_data_month = 本月流量使用情况:

+traffic_used_time_month = 本月上网时间:

+traffic_data_approximated = 流量仅供参考,建议向运营商查询以获得准确流量。

+traffic_used_month = 已用:

+traffic_left_month = 剩余:

+traffic_exceeded_month = 超出:

+traffic_total_month = 限额:

+traffic_apply_volume_limit = 流量管理

+traffic_data_limit_type = 套餐形式

+traffic_data = 流量

+traffic_time = 时间

+traffic_limit_data_month = 每月

+traffic_alert_when_data_reach = 提醒设置

+traffic_limit_time_month = 当月配额

+traffic_alert_when_time_reach = 提醒设置

+traffic_million_byte = MB

+traffic_percent = %

+traffic_limit_disconnect_msg = 您的流量/时间已经达到 {0}%,要断开网络连接吗?

+traffic_limit_connect_msg = 您的流量/时间已经达到 {0}%,要继续连接网络吗?

+traffic_limit_msg = 您的流量/时间已经达到 {0}%。

+traffic_beyond_disconnect_msg = 您的流量/时间已超出配额,要断开网络连接吗?

+traffic_beyond_connect_msg = 您的流量/时间已超出配额,要继续连接网络吗?

+traffic_beyond_msg = 您的流量/时间已超出配额。

+traffic_calibrate_note = 支持手动校准流量功能。如果页面流量统计与实际有偏差,您可以修改实际已用流量。

+traffic_note = 当已用流量/时间达到设置的百分比时提醒我。

+traffic_over_note = 当流量套餐单位为MB时,已使用流量的统计范围需小于4096TB。

+traffic_clear_confirm = 您确定要清除吗?

+traffic_not_support = 当前模式不支持此功能。

+

+#APN

+apn_currentApn = 当前 APN

+apn_mode = 模式

+apn_auto_apn = 自动

+apn_manual_apn = 手动

+apn_profile = 配置文件

+apn_profile_name = 配置文件名称

+apn = APN

+apn_ipv4_apn = IPv4 APN

+apn_ipv6_apn = IPv6 APN

+apn_dns_mode = DNS 模式

+apn_dns_mode_ipv4 = IPv4 DNS 模式

+apn_dns_mode_ipv6 = IPv6 DNS 模式

+apn_auto_dns = 自动

+apn_manual_dns = 手动

+apn_dns1 = DNS 1

+apn_dns2 = DNS 2

+apn_dns1_ipv4 = IPv4 DNS 1

+apn_dns2_ipv4 = IPv4 DNS 2

+apn_dns1_ipv6 = IPv6 DNS 1

+apn_dns2_ipv6 = IPv6 DNS 2

+apn_authentication = 鉴权方式

+apn_authentication_ipv4 = IPv4 鉴权方式

+apn_authentication_ipv6 = IPv6 鉴权方式

+apn_user_name = 用户名

+apn_user_name_ipv4 = IPv4 用户名

+apn_user_name_ipv6 = IPv6 用户名

+apn_password = 密码

+apn_password_ipv4 = IPv4 密码

+apn_password_ipv6 = IPv6 密码

+apn_pdp_type = PDP 类型

+set_default = 设为默认

+apn_save_profile_exist = 配置文件名称已存在,请选择其他名称。

+apn_delete_cant_delete_default = 无法删除默认配置文件。

+apn_delete_confirm = 确定删除?

+apn_cant_modify_status = 网络为 {0} 时无法更改当前的 APN 设置! 

+apn_cant_modify_current = 无法更改正在使用的 APN!

+apn_cant_delete_current = 无法删除正在使用的配置文件!

+apn_profile_full = 最多只能添加 {0} 项设置!

+dial_num = 拨号号码

+apn_no_select_alert = 请选择有效的配置文件!

+

+#Status bar

+network_status = 网络状态

+connection_status = 无线宽带连接状态

+rj45_connection_status = 有线宽带连接状态

+battery = 电量

+charging = 充电中

+sim_status = SIM卡状态

+sim_status_modem_waitpin = 无效的 SIM卡

+sim_status_modem_waitpuk = 无效的 SIM卡

+sim_status_modem_sim_undetected = 无效的 SIM卡

+sim_status_modem_undetected = 无效的 SIM卡

+sim_status_modem_imsi_waitnck = 无效的 SIM卡

+sim_status_modem_sim_destroy = 无效的 SIM卡

+sim_status_modem_destroy = 无效的 SIM卡

+sim_status_modem_init_complete = 有效的 SIM卡

+sim_status_modem_ready = SIM卡就绪

+wifi_status = Wi-Fi 状态

+wifi_status_on = Wi-Fi 开

+wifi_status_off = Wi-Fi 关

+wifi_status1 = 用户数:1

+wifi_status2 = 用户数:2

+wifi_status3 = 用户数:3

+wifi_status4 = 用户数:4

+wifi_status5 = 用户数:5

+wifi_status6 = 用户数:6

+wifi_status7 = 用户数:7

+wifi_status8 = 用户数:8

+wifi_status9 = 用户数:9

+wifi_status10 = 用户数:10

+enable_pin = 启用 PIN

+remaining_time = 剩余时间

+signal = 信号

+network_type = 网络类型

+network_type_limited_service = 服务受限

+network_type_no_service = 无服务

+network_provider = 运营商

+roaming_status = 漫游状态

+sim_status_ready = SIM卡就绪

+sim_status_waitpin = 等待输入 PIN

+sim_status_waitpuk = 等待输入 PUK

+sim_status_undetected = 未检测到 SIM卡

+sim_status_waitnck = 等待输入 NCK

+sim_status_destroy = SIM卡已损毁

+signal_strength = 信号强度

+signal_strength_label = 信号强度

+battery_level = 电量

+

+#dial_setting

+dial_note = WAN 连接状态

+dial_mode = 连接模式

+dial_mode_cpe = 拨号方式

+dial_roam_info = 您尚未开启漫游设置。要开启漫游功能,请到设置页面中勾选复选框。

+dial_setting_note_automatic = 自动:开机后,设备会自动连接到网络。

+dial_setting_note_manual = 手动:开机后,设备需要手动连接到网络。

+dial_roaming_remind = 勾选此项,您可以在漫游状态下连接到网络,且可能会产生额外费用。

+dial_roaming_connect = 设备处于漫游状态,连接网络会使您的资费增加。确定继续?

+

+#phonebook

+search = 搜索

+save_location = 存储位置

+save_location_0 = SIM卡

+save_location_1 = 设备

+group_all = 全部

+group_null = -

+group_common = 普通

+group_family = 家人

+group_friend =  朋友

+group_colleague = 同事

+name = 姓名

+mobile_phone_number = 移动电话

+home_phone_number = 住宅电话

+office_phone_number = 单位电话

+mail = 邮箱

+group = 群组

+no_data_selected = 请选择一项!

+confirm_data_delete = 确定删除?

+confirm_pb_delete = 确定要删除所选联系人吗?

+too_many_data_selected = 选择电话号码过多,请选择一个电话号码!

+delete_fail_try_again = 删除失败,请重试。

+max_send_number = 最多输入 5 个电话号码!

+send = 发送

+send_sms = 发送短信

+new_message = 新短信

+send_numbers = 电话号码

+contents = 短信内容

+device_full = 设备的电话本存储空间已满!

+sim_full = SIM卡已满!

+phonebook_init_fail = 电话本初始化失败!<br/>请检查SIM卡并重启设备。

+sim_removed = SIM卡已被移除!

+change_device_to_sim_confirm = 可能会丢掉信息,是否需要继续转存?

+

+#SMS

+smslist = 设备侧短信

+sms_setting = 短信设置

+sim_messages = SIM侧短信

+refresh = 刷新

+forward = 转发

+draft = 草稿

+send_fail_try_again = 发送失败。

+sms_content_required = 请输入短信息内容。

+sms_contact_required = 请选择联系人。

+select_some_options = 最多可选择5位联系人

+select_an_option = 请选择一个选项

+chat_input_placehoder = 请在此输入信息

+sms_chat_input_confirm = 请按回车键或者用分号完成输入

+sms_capacity_will_full = 短信容量将满,请删除部分短信

+sms_capacity_is_full = 短信容量满,请删除部分短信

+sms_capacity_is_full_for_send = 短信容量满,请删掉部分短信以正常收发新信息。

+sms_capacity_will_full_just = 容量将满,您最多只能发送 {0} 条。

+sms_init_fail = 短信初始化失败!<br/>请检查SIM卡并重启设备。

+sms_resending = 正在重发短信...

+sms_resend_fail = 短信重发失败。

+sms_stop_sending = 停止发送

+sms_unread_count = 未读短信

+sms_delivery_report_1 = 短信已送达对方。

+sms_delivery_report_2 = 短信未送达对方。

+sms_delivery_report_3 = 正在发送短信...

+sms_report = 发送报告

+sms_cancel_sending = 取消中…

+sms_save_draft_success = 短信已存为草稿

+sms_save_draft_failed = 草稿保存失败

+sms_to_save_draft = 短信已修改,要存为草稿吗?

+sms_no_recipient = 您尚未选择收件人,该短信将被舍弃。

+phone_number_invalid = 电话号码无效

+sms_to = 接收人:

+confirm_sms_delete = 确定要删除所选信息吗?

+sms_save_tip = 保存草稿中...

+

+#login

+password = 密码

+puk = PUK

+login = 登录

+logout = 退出

+new_pin = 新 PIN

+confirm_pin = 确认新 PIN

+puk_locked = 您的 SIM卡已彻底锁定。请联系您的运营商。

+password_error = 密码不正确!

+password_error_left = 密码不正确!<br/>您的剩余尝试次数:{0}。

+password_error_account_lock = 你的账户被锁定。<br/>剩余时间:

+password_error_five_times = 您已经输错5次。请5分钟后再试。

+password_error_account_lock_time = 您的账户已被锁定。<br/>请稍后再试。

+enter_pin = SIM卡已锁,请输入 PIN码以解锁。

+enter_puk = SIM卡 PIN码已锁,请输入 PUK码以解锁。

+last_enter_pin = 最后尝试机会。如果再次错误,您的 SIM卡将被锁定!

+last_enter_puk = 最后尝试机会。如果再次错误,您的 SIM卡将会损毁!

+attempts_left = 剩余次数:

+pin_error = PIN码不正确!

+puk_error = PUK码不正确!

+confirm_logout = 您要注销吗?

+

+#advanced password

+password_management = 登录密码

+current_password = 当前密码

+new_password = 新密码

+confirm_password = 确认新密码

+current_password_error = 当前密码错误!

+password_note_info = 您可以在该网页更改登录密码。

+password_note_valid = 密码不能为空,且最多包含 32 个字符。

+password_note_input = 密码的有效字符包含:0-9 a-z A-Z ! # $ * + , - . % : = ? @ [ ] ^ _ { | } ~

+password_note_first_change = 请修改您的初始登陆密码!

+password_note_too_low = 您的密码复杂度太低(密码中可以包含大小写字母、数字、特殊字符,且不小于8位)。您要继续吗?

+

+#advanced pin

+pin = PIN

+current_pin = 当前 PIN

+pin_management = PIN码管理

+pin_status = PIN码状态

+modify_pin = 更改 PIN

+cannot_operate_when_connected = 网络连接时无法进行该操作!

+cannot_change_pin_when_connected = 网络连接时无法更改 PIN!

+pin_note_info = “PIN码管理”提供PIN保密设置功能,防止对SIM/USIM/UIM卡的非授权使用。如果要改变当前设置,请先断开网络。

+pin_note_operator = 启用PIN码后,下次启动设备时,需要输入PIN码;关闭PIN码后,下次启动设备时,不需要输入PIN码。

+pin_note_modify = 启用PIN码后,可修改PIN码。

+

+#lan

+lan_setting = 局域网接口设置

+ip_address = IP 地址

+subnet_mask = 子网掩码

+mac_address = MAC地址

+dhcp_server = DHCP服务

+dhcp_ip_pool = DHCP IP池

+dhcp_lease = DHCP租期

+hours = 小时

+minutes = 分钟

+lan_note = 新的设置会在设备重启后生效。

+lan_note_ip_address = IP 地址:路由器局域网的IP地址,使用该IP地址可以通过浏览器管理设备。

+lan_note_subnet_mask = 子网掩码:对应 IP 地址的子网掩码。

+lan_note_dhcp_server_enable = DHCP服务启用:如果开启DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)服务,设备将会为所连接的客户端自动分配IP地址。

+lan_note_dhcp_server_disable = DHCP服务关闭:如果关闭DHCP服务,设备将不会为连接的客户端自动分配IP地址,客户端必须手动输入IP地址。

+lan_note_dhcp_ip_pool = DHCP IP 池:起始IP地址和终止IP地址指定了DHCP服务器分配给接入设备的IP地址范围。这个范围之外的地址不能由DHCP服务器分配。

+lan_note_dhcp_lease_time = DHCP 租期时间:租期时间表示计算机获取IP地址后可以使用这个IP地址的期限,到达租期时间后,如果客户端需要继续使用这个地址,必须在到期前重新发起请求。只有当原来的客户端租期到期并且不再发起续租请求时,这个地址才能分配给其他客户端使用。

+lan_confirm_reopen = 您的设置将在设备重启后生效。您要继续吗?<br/><br/><i>注意:选择是,表示提交请求并重启设备。如果选择否,表示您放弃当前的选择。</i>

+lan_tip_staticip_notsame = 路由器局域网的IP地址不能与静态IP地址在同一个网段内!

+

+#sms_setting

+sms_validity = 有效期

+sms_validity_twelve_hours = 12 小时

+sms_validity_one_day = 1 天

+sms_validity_one_week = 1 周

+sms_validity_largest = 最长

+center_number = 中心号码

+delivery_report = 发送报告

+list = 列表

+

+#restore

+restore = 恢复出厂

+restore_title = 恢复出厂设置

+restore_button = 恢复出厂设置

+restore_confirm = 所有参数将恢复为出厂设置,设备会重启。确定继续?

+restore_when_connected = 请先断开 WAN 网络!

+restoring = 出厂设置恢复中

+restore_note_info = 点击“恢复出厂”以将所有设置还原为默认值,并且设备会自动重启。

+

+#wps

+wps_note_all = WPS(Wi-Fi Protected Setup)代表Wi-Fi保护设置,是一个简单且安全地建立无线网络的标准,您可以通过这一过程轻松地将无线客户端连接到设备,而无需进行任何具体的配置,例如SSID、安全模式和密码。

+wps_note_pin = PIN:您需要输入客户端的PIN码。

+wps_note_pbc = PBC:您可以在该网页选择PBC(Push Button Configuration)或者长按(3-4秒)设备上的WPS按键启用WPS功能。

+wps_note_wait = 该设备在 2 分钟内会等候接收无线接入客户端的访问请求。

+wps_pin = PIN

+wps_pbc = PBC

+wps_wifi_off = Wi-Fi 关闭时无法进行操作!

+wps_auth_open = 当前的加密类型不支持WPS。

+wps_on_info = WPS 已经启用,请稍后再试!

+wps_ssid_broadcast_disable = SSID 广播关闭时无法进行该操作!

+

+#sleep mode

+wifi_sleep = Wi-Fi 休眠设置

+sleep_time = 休眠时间

+sleep_mode_-1 = 从不休眠

+sleep_mode_5 = 5分钟

+sleep_mode_10 = 10分钟

+sleep_mode_20 = 20分钟

+sleep_mode_30 = 30分钟

+sleep_mode_60 = 1小时

+sleep_mode_120 = 2小时

+wifi_sleep_note_info = 休眠时间:当在指定的时间内无 Wi-Fi 连接时,Wi-Fi 功能将会停用,系统会转入休眠模式以节省电量。

+wifi_sleep_confirm = 当前设置改变时将会重启wifi,是否继续?

+

+#system security

+remote_management = 远程管理(通过 WAN 口)

+ping_from_wan = 从外网 PING 入

+

+#portforward

+protocol_TCP&UDP = TCP+UDP

+protocol_TCP = TCP

+protocol_UDP = UDP

+virtual_server_setting = 虚拟服务器设置

+port_forward_setting = 端口转发设置

+port_forward_list = 系统当前虚拟服务器

+port_forward_note_info = 配置端口转发以启用外部计算机,访问局域网提供的网络、FTP 或其他服务。

+port_forward_note_port = 端口范围:设置要转发的源端口数量。

+port_forward_note_ip_address = IP 地址:设置要转发的源 IP 地址。

+port_forward_note_protocol = 协议:设置用于转发的协议。

+port_forward_note_comment = 注释:输入用于转发设置的注释。有效字符包含:0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ 。

+port_range = 端口范围

+protocol = 协议

+comment = 注释

+ipExam = (例如:192.168.0.101)

+rules_max = 规则数量已达最大值{0}。

+rule_exist = 规则已经存在。

+rule_max_note = 规则的最大数量为 10。

+rule_max_note_v4v6 = IPv4 或 IPv6 规则的最大数量为 10。

+

+rules_max_v4v6 =  {0}规则数量已达最大值{1}。

+rule_exist_v4v6 = {0}规则已经存在。

+

+#quick setting

+step_number_1 = 1

+step_number_2 = 2

+step_number_3 = 3

+step_number_4 = 4

+step_number_5 = 5

+step_number_6 = 6

+step_name_1  = 1.快速设置

+step_name_2  = 2.APN 设置

+step_name_3  = 3.PPP 鉴权

+step_name_4  = 4.SSID 配置

+step_name_5  = 5.安全配置

+step_name_6  = 配置如下

+step1_exp1 = 该向导帮助您安全设置网关基本参数:点击“上一步”和“下一步”进行导航;点击“应用”以保存设置。您也可以在其他菜单中设置高级参数。

+step1_exp2 = 在该向导中设置基本参数。您也可以在其他菜单中设置高级参数。

+apn_settings = APN 设置

+step2_auto_apn_explain = 如果您选择了“自动 APN”,将跳过第二步设置(PPP 鉴权)。

+step2_profile_name_explain = 配置文件名称:您当前使用的默认配置文件。

+ppp_authentication = PPP 鉴权

+step3_authentication_apn_explain1 = 鉴权方式:由您的互联网服务提供商 (ISP) 来提供。密码验证协议 (PAP) 不用加密就可以通过两次握手建立对端的身份。询问握手认证协议(CHAP)通过三次握手周期性的校验对端的身份。

+step3_authentication_apn_explain2 = 用户名:用于建立连接时,从互联网服务提供商获取验证。

+step3_authentication_apn_explain3 = 密码:用于建立连接时,从互联网服务提供商获取验证。

+step3_username_password_explain = 点击“设为默认”以将该配置文件设置为默认配置文件。

+ssid_title = SSID

+ssid_name = 网络名称 (SSID)

+ssid_broadcast = SSID 广播

+step4_ssid_explain = 网络名称:服务集标识符 (SSID)。输入无线局域网 (WLAN) 名称,最多 32 个字符。

+step4_ssid_broadcast_explain1 = SSID 广播:停用或启用(默认为启用)该功能。一旦启用该功能,路由器将会广播 SSID,其他设备将会发现该设备并进行连接。

+step4_ssid_broadcast_explain2 = 禁用:网关停止广播 SSID,在网络中隐藏您的网络名称。

+step5_encryption_mode_info = 安全模式:

+step5_encryption_mode_explain1 = OPEN:不进行验证以及加密。这可能会导致个人信息被拦截,或者网络被他人滥用,因此不推荐使用此方式。

+step5_encryption_mode_explain2 = WPA2(AES)-PSK:WPA2(AES)-PSK 是 Wi-Fi 网络安全存取 (WPA) 的安全保护版本,该版本施行了802.11i 无线安全标准。

+step5_encryption_mode_explain3 = WPA-PSK/WPA2-PSK:WPA 预共享密钥 (WPA-PSK)。以纯文本 (ASCII) 密码的方式输入预共享密钥。WPA2-PSK 是 Wi-Fi 网络安全存取 (WPA) 的安全保护版本,该版本施行了802.11i 无线安全标准。

+step5_encryption_mode_explain4 = 密码:密码的有效字符包含:0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _  { | } ~

+step6_apply_explain = 一旦设置完成时,您需要重新连接无线网络。

+quick_setting_wifi_disable_confirm = 1、Wi-Fi 已关闭,与 Wi-Fi 相关的设置不会生效。<br\>要继续吗?

+quick_setting_param_changed_confirm = 1、Wi-Fi 配置更改后已连接的 Wi-Fi 设备可能需要重连。<br\>要继续吗?

+#SD Card

+sdcard = SD卡

+httpshare = HTTP 共享

+sd_card_mode = 模式

+sd_card_share_setting = 共享设置

+sd_card_share_usb_mode = USB

+sd_card_share_http_share_mode = HTTP 共享

+http_title = HTTP 共享设置

+sd_card_status = 状态

+sd_card_file_to_share = 共享文件

+sd_card_access_type = 访问类型

+sd_card_path_to_share = 路径共享

+sd_card_entire_sd_card = 整个SD卡

+sd_card_custom_setting = 自定义

+sd_card_read_write = 读/写

+sd_card_readonly = 只读

+sd_card_share_setting_no_sdcard = 无 SD卡!

+sd_card_share_setting_exist = 该文件或文件夹已经存在!

+sd_card_share_setting_noexist = 该文件或文件夹不存在!

+sd_card_status_info_0 = 无 SD卡!

+sd_card_status_info_1 = SD卡存在,现在可以使用了

+sd_card_status_info_2 = SD卡存在,但目前处于无效状态,请 5 秒后重试。如果无法使用,请检查 SD卡!

+sd_card_status_info_2_reason = 可能的原因如下

+sd_card_status_info_2_reason_1 = SD卡格式是NTFS,请切换至USB方式使用。

+sd_card_status_info_2_reason_2 = SD卡内容正在加载中,请5分钟后再试;如果仍然无效,请检查SD卡。

+sd_card_invalid_chars_cant_download = 文件名称中包含无效的字符,无法下载!(无效字符包括 < > " '' & + / \\ : * | # ? ~ `)。

+note_not_support_fs_ntfs = 在 HTTP 共享模式下,设备仅支持 FAT/FAT32 文件系统!

+note_web_share_mode = HTTP 分享模式:通过网络浏览器分享 SD 卡。此模式将会停用通过 USB 端口访问 SD 卡的可移动驱动器映射功能。

+note_usb_access = 仅通过 USB 访问:在可移动的驱动器映射模式下,用户仅能通过 USB 数据线来访问 SD 卡。共享的 SD 卡的网页将会停用。

+note_http_share_usb_access = 仅通过 USB 访问:在可移动的驱动器映射模式下,用户仅能通过 USB 数据线来访问 SD 卡。共享的 SD 卡的网页将会停用。

+note_http_share_cannot_access = 无法访问此页面!

+note_path_to_share_example = 路径共享:您可以输入共享路径,例如:/Picture。当仅输入斜线号“/”时,表示共享整个SD卡。

+note_upload_not_refresh = 当下载或者上传文件时,请不要刷新该网页!

+note_upload_single_file_2g = 单个文件上传最大支持2G。

+note_upload_filelenth_25 = 文件名、文件夹名称修改支持最长25个字符。

+note_uploading_not_refresh = 文件上传中,请不要刷新该页面!

+note_invalid_file_path = 路径共享不能为单独的小数点,也不能包含以下字符: < > " '' & + / \\ : * | # ? ~ `

+browse_btn = 浏览

+change_btn = 更改

+no_file_selected = 未选择文件

+sd_no_file_selected = 请选择一个文件

+sd_name = 名称

+sd_path = 路径:

+sd_rename = 重命名

+sd_download = 下载

+sd_file_size = 文件大小

+sd_update_time = 更新时间

+no_sdcard = 无 SD卡!

+no_exist = 文件不存在!

+sd_card_folder_name_is_null = 请输入名称

+get_file_list_failure = 获取文件列表失败

+create_folder_failure = 创建文件夹失败

+delete_folder_failure = 删除文件或文件夹失败

+sd_card_path_too_long = 文件路径过长。

+sd_file_size_too_big = 文件过大。单个文件上传最大支持2G。

+sd_file_name_invalid = 本设备不支持含有*号的文件名,请更新文件名。

+back_to_login = 返回登录

+sd_config_changed_reload = SD卡共享设置已改变,页面将重新加载。

+sd_upload_space_not_enough = SD卡空间不足!

+sd_upload_data_lost = 文件上传出现异常,请重试。

+sd_upload_file_is_downloading = 文件正在下载中,请稍候!

+sd_share_path_is_invalid = 共享路径无效,请重新设置

+sd_share_path_cant_rename = 文件夹已共享,无法重命名。

+sd_share_path_cant_delete = 文件夹“{0}”已共享,无法删除。

+sd_share_path_invalid = 共享路径失效。

+sd_file_processing_cant_delete = 文件正在被使用,无法删除。

+sd_file_processing_cant_rename = 文件正在被使用,无法重命名。

+sd_not_support = SD卡格式不支持或其它原因,请重新插入或更换SD卡。

+sd_usb_forbidden = SD卡正在被使用,无法切换。

+sd_upload_rename = 该文件已经存在!如需继续上传请修改文件名并选择“是”。选择“否”将取消上传。

+sd_upload_rename_null = 文件名不能为空或超过25个字符!

+

+#port filter

+filter_basic_setting = 基本设置

+port_filter_enabled = MAC/IP/端口过滤

+default_policy = 默认策略

+default_policy_note = 您可以设置防火墙策略以保护网络免受病毒、蠕虫和恶意网络行为的攻击。

+default_policy_note_filter = 过滤策略仅在启用过滤功能时可用。

+accepted = 放行

+dropped = 丢弃

+port_filter_setting = MAC/IP/端口过滤设置

+mac_address = MAC 地址

+macExam = (例如:00:1E:90:FF:FF:FF)

+dest_ip_address = 目的 IP 地址

+source_ip_address = 源 IP 地址

+port_filter_action = 操作

+filter_accept = 放行

+filter_drop = 丢弃

+protocol_None = 全部

+protocol_ICMP = ICMP

+port_filter_list = 系统当前 MAC/IP/端口过滤规则

+dest_port_range = 目的端口范围

+source_port_range = 源端口范围

+filter_accept_note = 其它数据包会被放行。

+filter_drop_note = 其它数据包会被丢弃。

+filter_optional = 请输入IP,MAC 或者端口值

+mac_check = 无效的 MAC 地址

+filter_ip_setting = IP设置

+filter_ipv4 = IPv4

+filter_ipv6 = IPv6

+ip_type = IP 类型

+source_ipv6_address = 源 IPv6 地址

+dest_ipv6_address = 目的 IPv6 地址

+port_filter_note_mac_address = MAC 地址:设置要过滤的 MAC 地址。

+port_filter_note_source_ip_address = 源 IP 地址:设置要过滤的源 IP 地址。

+port_filter_note_dest_ip_address = 目的 IP 地址:设置要过滤的目的 IP 地址。

+port_filter_note_protocol = 协议:设置用于过滤的协议。

+port_filter_note_source_port_range = 源端口范围:设置要过滤的源端口数量。

+port_filter_note_dest_port_range = 目的端口范围:设置要过滤的目的端口数量。

+port_filter_note_action = 操作:如果信息包与规则相符,可设置处理信息包。

+port_filter_note_comment = 注释:输入用于过滤设置的注释。有效字符包含:0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ 。

+port_filter_note_info = 过滤策略同规则是一一对应的。如果与此条款相抵触,将不会继续同下列规则匹配。

+confirm_data_effect = 您的设置可能不会立即生效,如果需要全部生效,建议重启设备,是否继续?

+

+#wifi_range

+wifi_range_settings = Wi-Fi 性能设置

+wifi_range = Wi-Fi 覆盖范围

+wifi_short_mode = 近距离 Wi-Fi 范围 - 最佳电池续航

+wifi_medium_mode = 中距离 Wi-Fi 范围

+wifi_long_mode = 远距离 Wi-Fi 范围

+wifi_des_short_mode = 近距离 Wi-Fi 范围

+wifi_des_medium_mode = 中距离 Wi-Fi 范围

+wifi_des_long_mode = 远距离 Wi-Fi 范围

+wifi_range_note_range = Wi-Fi 范围:

+wifi_range_note_short =  近距离 Wi-Fi 范围:覆盖范围和发射功耗小,是最佳电池续航方案。

+wifi_range_note_medium = 中距离 Wi-Fi 范围:覆盖范围和发射功耗是设备支持能力的一半,正常耗电。

+wifi_range_note_long = 远距离 Wi-Fi 范围:设备最大发射功耗和覆盖范围,如果一直有终端接入,耗电会增加,减少电池续航。

+wifi_range_note_short_cpe =  近距离 Wi-Fi 范围:覆盖范围和发射功耗最小。

+wifi_range_note_medium_cpe = 中距离 Wi-Fi 范围:覆盖范围和发射功耗是设备支持能力的一半。

+wifi_range_note_long_cpe = 远距离 Wi-Fi 范围:设备最大发射功耗和覆盖范围。

+

+#upnp

+upnp = UPnP

+upnp_setting = UPnP 设置

+upnp_note_info = 通用即插即用 (UPnP) 是网络协议集。它允许电脑、打印机、互联网网关、Wi-Fi 接入点和移动设备之间在网络上更方便地进行互相搜索,并为数据共享、通信和娱乐建立功能性的网络服务。

+

+#dmz

+dmz = DMZ

+dmz_setting = DMZ 设置

+dmz_note_info = 如果终端设备无法通过该设备运行网络应用程序,请启用 DMZ,在输入框输入该终端设备的 IP 地址。

+dmz_note_function = 您可以在该网页配置 DMZ 地址、启用或停用 DMZ 功能。

+

+#Device Information

+max_access_num = 最大连接数

+lan_domain = 局域网域名

+sim_serial_number = SIM卡卡号

+software_version = 软件版本

+firmware_version = 固件版本

+hardware_version = 硬件版本

+imei = IMEI

+imsi = IMSI

+wan_ip_address = WAN IP 地址

+ipv6_wan_ip_address = WAN IPv6 地址

+network_name_ssid1 = 网络名称 (主SSID)

+pass_phrase_ssid1 = 密码 (主SSID)

+max_access_num_ssid1 = 最大连接数 (主SSID)

+network_name_ssid2 = 网络名称 (副SSID)

+pass_phrase_ssid2 = 密码 (副SSID)

+max_access_num_ssid2 = 最大连接数 (副SSID)

+

+#port map

+port_map = 端口映射

+port_map_basic = 基本设置

+port_map_setting = 端口映射设置

+source_port = 源端口

+dest_port = 目的端口

+port_map_list = 当前映射规则

+port_map_note_info = 配置端口映射以启用外部计算机,访问局域网提供的网络、FTP 或其他服务。

+port_map_note_port = 源端口/目的端口:提供服务的计算机端口。

+port_map_note_dest_ip_address = 目的 IP 地址:指定一台加入局域网的计算机以提供服务。

+port_map_note_protocol = 协议:由服务应用的协议。

+port_map_note_comment = 注释:输入用于端口映射规则的注释。有效字符包含:0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ 。

+

+#USSD Info

+USSD = USSD

+ussd = USSD

+ussd_send_to = 发送

+ussd_send = 发送

+ussd_cancel = 取消

+ussd_reply_to = 回复

+ussd_reply = 回复

+ussd_contents = 内容

+ussd_timeout = 网络超时!

+ussd_operation_timeout = 操作超时!

+ussd_no_service = 无网络服务!

+ussd_retry = 操作失败!请重试!

+ussd_unsupport = 不支持 USSD 功能!

+ussd_info_error = 获取信息出错!

+ussd_fail = 操作失败!

+ussd_error_input = 输入有误!

+ussd_note1 = 您可以向网络发送一条指令(已预先制定的数字或者符号),网络将会根据指令给您提供相应的服务。

+

+#dlna setting

+dlna_setting = DLNA 设置

+dlna_language = 语言

+dlna_language_chinese = 中文

+dlna_language_english = 英文

+dlna_device_name = 设备名称

+dlna_media_type = 共享媒体类型

+dlna_media_info = 共享设置

+dlna_audio = 音乐

+dlna_image = 图片

+dlna_video = 视频

+dlna_rescan = 重新扫描

+dlna_note_info = 当 SD 卡可用或者 HTTP 共享模式启用时,您可以设置数字生活网络联盟 (DLNA)。

+dlna_note_httpshare = 您可以设置要在该网页上共享的数字媒体服务器 (DMS) 语言、设备名称和媒体类型。

+dlna_note_rescan = 为了使 DLNA 多媒体文件数据库与 SD 卡保持同步,建议重新扫描。

+

+#nosimcard

+no_sim_card_title = 系统信息

+no_sim_card_message = 没有 SIM卡或者 SIM卡无效!

+

+#network_locked

+network_locked = 网络被锁!

+network_locked_explain = 设备的网络被锁,请联系您的服务提供商获取解锁码。

+network_locked_times_explain = 解锁码输入剩余次数:

+network_locked_enter_explain = 请输入解锁码:

+network_locked_zero_times = 网络被锁,请联系您的服务提供商。

+

+#update_info

+update_info = 升级信息

+update_no_info = 当前已是最新版本

+update_new_version_found = 有新版本可用

+update_current_version = 当前版本

+update_new_version = 新版本

+update_link_prompt = 点击下面的链接下载升级工具

+update_skip_btn = 应用

+update_id_skip_info = 如果不想升级至此版本,请点击“跳过”按钮

+update_remind = 有新版本时提醒我。

+update_management = 更新管理

+update_log = 问题解决

+update_note = 备注

+update_notice = 发现新版本。通过“设置->设备设置->更新管理”查看详情。

+update_note_info = 点击链接以下载对应系统的更新工具。

+update_note_install = 解压更新工具并运行,进行版本更新。

+update_note_linux = Linux 系统不支持在线升级。如需升级,请在 Windows 系统或 Mac 上完成。

+update_status = 状态

+update_settings = 升级

+wifi_connect_alert = 您只能通过以太网升级。

+

+#AP_Station

+ap_station = Internet Wi-Fi

+ap_station_switch = Internet Wi-Fi 开关

+ap_station_wlan_mode = 首选网络

+ap_station_wifi_prior = Wi-Fi

+ap_station_3g_prior = WWAN

+ap_station_current_status = 当前状态

+ap_station_wlan_connected = Wi-Fi 已连接

+ap_station_wan_connected = WAN 已连接

+ap_station_no_connection = 无任何连接

+ap_station_hotspot_list = Wi-Fi 热点

+ap_station_connect = 连接

+ap_station_disconnect = 断开连接

+ap_station_add_hotspot = 添加 Wi-Fi 热点

+ap_station_edit_hotspot = 编辑 Wi-Fi 热点

+ap_station_show_password = 显示密码

+ap_station_encrypt_type = 加密方式

+ap_station_wep_keys = WEP密钥

+ap_station_encrypt_type_none = 不加密

+ap_station_encrypt_type_wep = WEP

+ap_station_wep_key_type_ascii = ASCII

+ap_station_wep_key_type_hex = HEX

+ap_station_cipher = WPA算法

+ap_station_cipher_TKIP = TKIP

+ap_station_cipher_AES = AES

+ap_station_cipher_AUTO = AUTO

+ap_station_security_mode_OPEN = OPEN

+ap_station_security_mode_WPAPSKWPA2PSK = WPA-PSK/WPA2-PSK

+ap_station_security_mode_SHARED = SHARED

+ap_station_security_mode_WPAPSK = WPA-PSK

+ap_station_security_mode_WPA2PSK = WPA2-PSK

+ap_station_security_mode_EAPAKASIM = EAP-AKA/SIM

+ap_station_security_mode_EAP-SIM/AKA = EAP-SIM/AKA

+ap_station_security_mode_WPA3Personal = WPA3-Personal

+ap_station_security_mode_WPA2WPA3 = WPA2(AES)/WPA3-Personal

+ap_station_wep_default_key = 网络密钥

+ap_station_wep_key = WEP密钥

+ap_station_wep_key_0 = 密钥 1

+ap_station_wep_key_1 = 密钥 2

+ap_station_wep_key_2 = 密钥 3

+ap_station_wep_key_3 = 密钥 4

+ap_station_exceed_list_max = 最多可添加 {0} 个热点!

+ap_station_search_hotspot_fail = 搜索热点失败!

+ap_station_connect_change_alert = WAN连接将断开,要继续吗?

+ap_station_update_fail = 操作失败,该热点处于连接状态。

+ap_station_enable_confirm = 当Internet Wi-Fi使用时多重网络名称不能使用。如果开启Internet Wi-Fi,多重网络名称将自动关闭,是否修改设置?

+ap_station_processing = 后台忙,请重试。

+ap_station_exist = 存在同名热点。

+ap_connect_error = 无法连接上热点 {0}!

+

+#fastboot

+fastboot = 快速开机

+fastboot_setting = 快速开机设置

+fastboot_note = 如果启用了快速开机功能,设备将花费较短的时间开机。

+

+#notes

+wifi_channel_bandwidth = 频带宽度

+

+home_note = 表格中显示了已连接的无线终端设备信息。

+

+sms_setting_note_validity = 有效期:设置外发短信的有效期。

+sms_setting_note_center_number = 中心号码:请输入短信中心号码。如需详情请联系您的服务提供商。

+sms_setting_note_delivery_report = 发送报告:当短信已送达收件人时,接收或者拒绝送达提示。

+

+apn_note_whole_page = 您可以在该网页设置接入点名称 (APN)。

+apn_note_mode = 模式:如果您的服务提供商向您提供了固定的 APN,请选择“手动 APN”。如果没有提供,请选择“自动 APN”,该设备将会自动获取参数。

+apn_note_profile = 配置文件:包含了一个或多个配置文件名称。

+apn_note_pdp_type = PDP 类型:IPv4/IPv6/IPv4&IPv6。

+apn_note_profile_name = 配置文件名称:有关您指定的新的配置文件的名称。

+apn_note_apn = APN:接入点名称。有效字符包含:0-9 a-z A-Z . - 且开头和结尾不能是 . 或者 - 。

+apn_note_dns_mode = DNS 模式:如果您的服务提供商向您提供了固定的 IP 地址,请选择“手动 DNS”,如果没有提供,请选择“自动 DNS”,该设备将会自动获取参数。

+apn_note_authentication = 鉴权方式:由您的互联网服务提供商 (ISP) 来提供。密码验证协议 (PAP) 不用加密就可以通过两次握手建立对端的身份。询问握手认证协议(CHAP)通过三次握手周期性的校验对端的身份。

+apn_note_username = 用户名:用于建立连接时,从互联网服务提供商处获取验证。

+apn_note_password = 密码:用于建立连接时,从互联网服务提供商处获取验证。

+apn_note_set_default = 点击“设为默认”以将该配置文件设置为默认配置文件。

+

+wifi_basic_note_multi_ssid_switch = 多重网络名称开关:可以同时使用 2 个网络名称。

+wifi_basic_note_network_name = 网络名称(SSID):SSID可以简单地理解为无线网络的名称。修改SSID时,请在本框中输入一个最多不超过32个字符的字符串,该字符串由数字、字母(a-z、A-Z)、特殊字符(!#()+-./%=?@^_{|}~)和空格,且开头和结尾不能是空格。

+wifi_basic_note_network_name_input = 网络名称的有效字符包含:0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~ 和空格且开头和结尾不能是空格。

+wifi_basic_note_broadcast = SSID 广播:启用后,设备将会广播其无线网络标识(SSID)。这样附近的计算机或其他无线客户端即可搜索到本路由器的无线信号并连接到该设备。

+wifi_basic_note_security_mode = 安全模式:

+wifi_basic_note_no_encryption = OPEN:无数据加密。这可能会导致网络被他人滥用,因此不推荐使用此方式。

+wifi_basic_note_shared = SHARED(WEP):链路认证方式为共享密钥认证方式,加密方式为WEP加密。

+wifi_basic_note_wpa_psk_aes = WPA2(AES)-PSK: WPA2(AES)-PSK 是 Wi-Fi 网络安全存取 (WPA) 的安全保护版本,该版本施行了802.11i 无线安全标准。

+wifi_basic_note_wpa_psk = WPA-PSK/WPA2-PSK:WPA 预共享密钥 (WPA-PSK)。WPA2-PSK 是 Wi-Fi 网络安全存取 (WPA) 的安全保护版本,该版本施行了802.11i 无线安全标准。

+wifi_basic_note_wpa3 = WPA3-Personal:WPA2加密协议的升级版本。

+wifi_basic_note_wpa2_wpa3 = WPA2(AES)/WPA3-Personal: WPA2-PSK 是 Wi-Fi 网络安全存取 (WPA) 的安全保护版本,该版本施行了802.11i 无线安全标准。WAP3是WPA2加密协议的升级版本。

+wifi_basic_note_pass_phrase = 密码:密码的有效字符包含:0-9 a-z A-Z ! # ( ) + - . / % = ? @ ^ _ { | } ~

+wifi_basic_note_max_station_number1 = 最大接入数:通过本操作,可以选择连接到该设备的最大无线终端接入数。通过Internet Wi-Fi功能连接的Wi-Fi热点也属于该设备的无线终端接入设备。

+wifi_basic_note_max_station_number = 最大接入数:通过本操作,可以选择连接到该设备的最大无线终端接入数。

+

+wifi_advanced_note_whole_page = 您可以在该网页设置 Wi-Fi 高级字符。

+wifi_advanced_note_band_selection = 频段选择:您可以为您的设备选择合适的频段。

+wifi_advanced_note_network_mode = 网络模式:选择合适的无线网络模式,该设备的无线性能会提高。

+wifi_advanced_note_country_code = 国家/地区码:您可以为您的设备选择合适的国家/地区码。

+wifi_advanced_note_frequency = 信道:选择合适的频道来优化Wi-Fi网络性能和覆盖范围。

+

+ap_station_note_info = 请确保您所连接的 Wi-Fi 热点的IP地址段与本设备的IP地址段不在同一范围内,否则您将无法通过该 Wi-Fi 热点连接网络。

+ap_station_note_disable_info = 如果开启“多重网络名称”,Internet Wi-Fi 功能将会停用。

+ap_station_on_info = Internet Wi-Fi 功能启用时无法进行该操作!

+

+wif_filter_note1 = 无线局域网地址过滤规则设置。

+wif_filter_note2 = 无规则:不启用无线局域网地址过滤规则。

+wif_filter_note3 = 白名单:允许MAC地址列表中的用户通过无线网络与本设备连接。

+wif_filter_note4 = 黑名单:不允许MAC地址列表中的用户通过无线网络与本设备连接。

+

+#restart

+restart = 重启

+restart_button = 重启设备

+restart_confirm = 确定重启设备吗?

+restarting = 设备重启中

+

+#diconneted_operate_note

+diconneted_operate_note = 要更改当前设置,请断开网络连接。

+diconneted_network_confirm = 当前操作将会断开网络,是否继续?

+

+#ota_update

+ota_update = 更新管理

+ota_title = 更新 

+ota_no_new_version = 没有发现新版本。

+ota_new_version = 发现新版本,是否更新? 

+ota_connect_server = 正在连接服务器 

+ota_connect_server_successfully = 连接服务器成功  

+ota_downloading = 正在下载...  

+ota_download_failed = 下载失败  

+ota_no_network = 无网络  

+ota_network_disconnected = 请连接网络后更新! 

+ota_interrupted_alert = 发现新版本,请登陆后更新!

+ota_interrupted = 是否恢复上次被中断的下载任务?

+ota_download_success = 下载完成,设备将重启,请稍候。升级过程中请不要断电、恢复出厂设置或关机。

+ota_pkg_download_success = 升级包已存在,设备将重启,请稍候。升级过程中请不要断电、恢复出厂设置或关机。

+ota_update_success = 更新成功。 

+ota_update_failed = 更新失败。  

+ota_connect_server_failed = 无法连接到服务器  

+ota_download_warning = 请保持电量充足;请不要强制中断下载。 

+ota_update_warning = 注意事项:请不要强制中断更新。 

+ota_cancel = 更新已取消! 

+ota_pkg_exceed = 更新包太大! 

+ota_have_cancel = 你已经选择取消了! 

+ota_roamming = 您尚未开启漫游设置。要开启漫游功能,请勾选本页复选框。

+ota_low_battery = 下载成功,设备电量不足,请充电后再升级! 

+ota_pkg_low_battery = 升级包已存在,设备电量不足,请充电后再升级!

+ota_md5_error = 检测更新包失败。

+ota_version = 版本:

+ota_update_setting = 自动检测设置

+ota_auto_update_switch = 自动检测新版本 

+ota_update_interval_day = 自动检测周期  

+ota_roaming_setting = 漫游设置 

+ota_update_roaming_remind = 勾选此项后,设备将在漫游状态下进行更新,并且会产生漫游费用。

+ota_update_manual = 检测新版本  

+ota_check_new_version = 检测  

+ota_check_new_version_desc = 点击“检测”按钮,立即检测新版本。 

+ota_check_roaming_confirm = 当前处于漫游网络下,您确定要升级吗?

+ota_update_every_day = 每天  

+ota_update_15_day = 15天  

+ota_update_30_day = 30天  

+ota_new_version_checking = 新版本检测中...

+ota_update_running = 检测已经在进行...

+ota_check_fail = 检测新版本失败!

+fota_package_already_download = 升级包已下载,待设备重启后完成升级

+software_upload = 软件升级

+upload_update_success = 升级文件上传成功,即将重启,请勿断电。

+upload_update_failed0 = 文件解析失败。   

+upload_update_failed1 = 文件校验失败。   

+upload_update_failed2 = 文件写入失败。   

+upload_update_failed3 = 升级标志写入失败。

+upload_update_failed4 = Flash校验失败。

+error_file_selected = 请选择正确的升级文件

+upload_tip = 上传中,请勿关闭、刷新或多页面操作webui,直至重启。

+########CPE more wording##############

+opmode = 模式切换

+wds = WDS

+url_filter = URL过滤设置

+

+voip_settings = VoIP设置

+voip_user_details = 用户详情

+voip_advanced_settings = 高级设置

+voip_supplementary_service = 补充业务

+

+url_check = 无效的URL

+url_filter_check = 无效的URL过滤规则

+sntp_invalid_server_name = 无效的URL格式或者IP地址!

+server_alreay_exist = 该服务器已经存在!

+forwarding_uri_check = 无效值

+

+wifi_switch = Wi-Fi开关

+ap_isolation = AP 隔离

+#mac filter

+black_list = 黑名单

+black_list_switch = 黑名单开关

+block = 屏蔽

+black_list_max = 黑名单支持的最大个数是10!

+mac_repeat_tip = 请删除设置列表中重复的MAC地址!

+black_yourself_tip = 你不能屏蔽你自己!

+wifi_status11 = 用户数:11

+wifi_status12 = 用户数:12

+wifi_status13 = 用户数:13

+wifi_status14 = 用户数:14

+wifi_status15 = 用户数:15

+wifi_status16 = 用户数:16

+wifi_status17 = 用户数:17

+wifi_status18 = 用户数:18

+wifi_status19 = 用户数:19

+wifi_status20 = 用户数:20

+wifi_status21 = 用户数:21

+wifi_status22 = 用户数:22

+wifi_status23 = 用户数:23

+wifi_status24 = 用户数:24

+wifi_status25 = 用户数:25

+wifi_status26 = 用户数:26

+wifi_status27 = 用户数:27

+wifi_status28 = 用户数:28

+wifi_status29 = 用户数:29

+wifi_status30 = 用户数:30

+wifi_status31 = 用户数:31

+wifi_status32 = 用户数:32

+

+auto_connect = 自动连接

+manual_connect = 手动连接

+

+default_Gateway = 默认网关

+primary_dns = 首选 DNS

+secondary_dns = 备用 DNS

+gateway_check = 请输入有效的网关

+

+mac_filter_lable = MAC过滤规则

+

+wlan_mac_filter_0 = 无规则

+wlan_mac_filter_1 = 白名单

+wlan_mac_filter_2 = 黑名单

+black_enable= 黑名单

+white_list = 白名单

+white_enable = 白名单

+mac_white_address = MAC 地址

+max_white_list = 白名单最多只能添加6条。

+

+#SNTP

+local_current_time = 本地当前时间

+time_set_mode = 时间设置模式

+time_set_time_manual = 手动设置时间

+time_set_time_auto = 自动同步Sntp

+year = 年

+month = 月

+date = 日

+hour = 时

+minute = 分

+second = 秒

+sunday = 星期日

+monday = 星期一

+tuesday = 星期二

+wednesday = 星期三

+thursday = 星期四

+friday = 星期五

+saturday = 星期六

+stnp_server1 = SNTP 服务器1

+stnp_server2 = SNTP 服务器2

+stnp_server3 = SNTP 服务器3

+time_zone =  时区

+daylight_saving_time = 夏时制

+daylightsave_0 = 禁用

+daylightsave_1 = 启用

+sntp_syn_time_wan_connected = 联网后才可以使用sntp时间同步!

+operation_not_supported = 不支持该操作!

+network_terminated = 网络终止!

+upgrade_file_nomatch = 升级文件错误!

+upgrade_confirm = 您确认要升级吗?

+upgrading = 升级中,请稍等...

+upgrading_alert = 升级中,请勿切断电源。升级后,系统将会自动重启!

+upgrad_note = 请选择您要升级的版本,然后点击“应用”按钮后,开始升级。

+sntp_processing = 同步中,请稍等...

+sntp_req_success = 同步请求已发送!

+time_zone_<-12>12_0 = (GMT-12:00) 日界线西

+time_zone_SST11_0 = (GMT-11:00) 中途岛,萨摩亚群岛

+time_zone_<-10>10_0 = (GMT-10:00) 夏威夷

+time_zone_<-09>9_0 = (GMT-09:00) 阿拉斯加

+time_zone_PST8PDT,M3.2.0,M11.1.0_0 = (GMT-08:00) 太平洋时间(美国和加拿大),蒂华纳

+time_zone_<-07>7_0 = (GMT-07:00) 山地时间(美国和加拿大)

+time_zone_<-07>7_1 = (GMT-07:00) 亚利桑那

+time_zone_MST7MDT,M4.1.0,M10.5.0_2 = (GMT-07:00) 奇瓦瓦,拉巴斯,马扎特兰

+time_zone_<-06>6_0 = (GMT-06:00) 萨斯喀彻温

+time_zone_<-06>6_1 = (GMT-06:00) 中部时间(美国和加拿大)

+time_zone_<-06>6_2 = (GMT-06:00) 中美洲

+time_zone_<-06>6_3 = (GMT-06:00) 瓜达拉哈拉,墨西哥城,蒙特雷

+time_zone_<-05>5_0 = (GMT-05:00) 波哥大,利马,基多

+time_zone_<-05>5_1 = (GMT-05:00) 东部时间(美国和加拿大)

+time_zone_EST5EDT,M3.2.0,M11.1.0_2 = (GMT-05:00) 印第安纳州(东部)

+#time_zone_-4.5 = (GMT-04:30)

+time_zone_AST4ADT,M3.2.0,M11.1.0_0 = (GMT-04:00) 大西洋时间(加拿大)

+time_zone_<-04>4_1 = (GMT-04:00) 加拉加斯,拉巴斯

+time_zone_<-04>4<-03>,M8.2.6/24,M5.2.6/24_2 = (GMT-04:00) 圣地亚哥

+time_zone_NST3:30NDT,M3.2.0,M11.1.0_0 = (GMT-03:30) 纽芬兰

+time_zone_<-03>3_0 = (GMT-03:00) 巴西利亚

+time_zone_<-03>3_1 = (GMT-03:00) 布宜诺斯艾利斯,乔治敦

+time_zone_<-03>3_2 = (GMT-03:00) 格陵兰

+time_zone_<-02>2_0 = (GMT-02:00) 中大西洋

+time_zone_<-01>1_0 = (GMT-01:00) 佛得角群岛

+time_zone_<-01>1<+00>,M3.5.0/0,M10.5.0/1_1 = (GMT-01:00) 亚速尔群岛

+time_zone_GMT0IST,M3.5.0/1,M10.5.0_0 = (GMT) 格林威治标准时间:都柏林,爱丁堡,伦敦,里斯本

+time_zone_WET0WEST,M3.5.0,M10.5.0/3_1 = (GMT) 卡萨布兰卡,蒙罗维亚

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_0 = (GMT+01:00) 阿姆斯特丹,柏林,伯尔尼,罗马,斯德哥尔摩,维也纳

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_1 = (GMT+01:00) 贝尔格莱德,布拉迪斯拉发,布达佩斯,卢布尔雅那,布拉格

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_2 = (GMT+01:00) 布鲁塞尔,哥本哈根,马德里,巴黎

+time_zone_CET-1CEST,M3.5.0,M10.5.0/3_3 = (GMT+01:00) 萨拉热窝,斯科普里,华沙,萨格勒布

+time_zone_<+01>-1_4 = (GMT+01:00) 中非西部

+time_zone_EET-2EEST,M3.5.0/3,M10.5.0/4_0 = (GMT+02:00) 布加勒斯特

+time_zone_CAT-2_1 = (GMT+02:00) 哈拉雷,比勒陀利亚

+time_zone_EET-2EEST,M3.5.0/3,M10.5.0/4_2 = (GMT+02:00) 赫尔辛基,基辅,里加,索非亚,塔林,维尔纽斯

+time_zone_EET-2_3 = (GMT+02:00) 开罗

+time_zone_EET-2EEST,M3.5.0/3,M10.5.0/4_4 = (GMT+02:00) 雅典,贝鲁特,伊斯坦布尔,明斯克

+time_zone_IST-2IDT,M3.4.5/02:00:00,M10.5.0/02:00:00_5 = (GMT+02:00) 耶路撒冷

+time_zone_<+03>-3_0 = (GMT+03:00) 巴格达

+time_zone_<+03>-3_1 = (GMT+03:00) 科威特,利雅得

+time_zone_<+03>-3_2 = (GMT+03:00) 莫斯科,圣彼得堡,伏尔加格勒

+time_zone_EAT-3_3 = (GMT+03:00) 内罗毕

+time_zone_<+0330>-3:30<+0430>,J80/0,J264/0_0 = (GMT+03:30) 德黑兰

+time_zone_<+04>-4_0 = (GMT+04:00) 阿布扎比,马斯喀特

+time_zone_<+04>-4_1 = (GMT+04:00) 巴库,第比利斯,埃里温

+time_zone_<+0430>-4:30_0 = (GMT+04:30) 喀布尔

+time_zone_<+05>-5_0 = (GMT+05:00) 叶卡捷琳堡

+time_zone_PKT-5_1 = (GMT+05:00) 伊斯兰堡,卡拉奇,塔什干

+time_zone_<+0530>-5:30_0 = (GMT+05:30) 马德拉斯,加尔各答,孟买,新德里

+time_zone_<+0545>-5:45_0 = (GMT+05:45) 加德满都

+time_zone_<+06>-6_0 = (GMT+06:00) 阿拉木图,新西伯利亚

+time_zone_<+06>-6_1 = (GMT+06:00) 阿斯塔纳,达卡

+time_zone_<+06>-6_2 = (GMT+06:00) 斯里哈亚华登尼普拉

+time_zone_<+0630>-6:30_0 = (GMT+06:30) 仰光

+time_zone_<+07>-7_0 = (GMT+07:00) 克拉斯诺亚尔斯克

+time_zone_<+07>-7_1 = (GMT+07:00) 曼谷,河内,雅加达

+time_zone_CST-8_0 = (GMT+08:00) 北京,重庆,香港特别行政区,乌鲁木齐

+time_zone_<+08>-8_1 = (GMT+08:00) 吉隆坡,新加坡

+time_zone_AWST-8_2 = (GMT+08:00) 珀斯

+time_zone_CST-8_3 = (GMT+08:00) 台北

+time_zone_<+08>-8_4 = (GMT+08:00) 伊尔库茨克,乌兰巴图

+time_zone_JST-9_0 = (GMT+09:00) 大阪,札幌,东京

+time_zone_KST-9_1 = (GMT+09:00) 汉城

+time_zone_<+09>-9_2 = (GMT+09:00) 雅库茨克

+time_zone_ACST-9:30ACDT,M10.1.0,M4.1.0/3_0 = (GMT+09:30) 阿德莱德

+time_zone_ACST-9:30_1 = (GMT+09:30) 达尔文

+time_zone_AEST-10_0 = (GMT+10:00) 布里斯班

+time_zone_<+10>-10_1 = (GMT+10:00) 弗拉迪沃斯托克

+time_zone_<+10>-10_2 = (GMT+10:00) 关岛,莫尔兹比港

+time_zone_AEST-10AEDT,M10.1.0,M4.1.0/3_3 = (GMT+10:00) 霍巴特

+time_zone_AEST-10AEDT,M10.1.0,M4.1.0/3_4 = (GMT+10:00) 堪培拉,墨尔本,悉尼

+time_zone_<+11>-11_0 = (GMT+11:00) 马加丹,所罗门群岛,新喀里多尼亚

+time_zone_<+12>-12_0 = (GMT+12:00) 奥克兰,惠灵顿

+time_zone_<+12>-12_1 = (GMT+12:00) 斐济,勘察加半岛,马绍尔群岛

+time_zone_<+13>-13_0 = (GMT+13:00) 努库阿洛法

+

+#operation mode

+opmode_auto = 自动模式

+opmode_bridge = 桥模式

+opmode_cable = 有线宽带模式

+opmode_gateway = 无线宽带模式

+EthPort_Status = 以太网端口状态

+change_mode = 选择模式

+current_mode = 当前模式:

+change = 改变

+change_mode_alert = 有线宽带模式只能使用Wi-Fi访问,请记住Wi-Fi SSID和密码!要继续吗?

+

+opmode_msg1 = 无线宽带模式下请将公网网线拔掉。

+opmode_msg2 = 改变工作模式后,设备会自动重启。

+#pppoe dial

+pppoe_mode = PPPoE

+pppoe_success = PPPoE拨号成功

+pppoe_fail = PPPoE拨号失败

+pppoe_processing = 正在进行PPPoE拨号

+static_success = 配置静态IP成功

+static_fail = 配置静态IP失败

+static_processing = 正在获取静态IP

+dyn_success = 动态获取IP成功

+dyn_fail = 动态获取IP失败

+dyn_processing = 正在获取动态IP

+pppoe_msg = 公网网线未连上

+pppoe_message_send_fail = 消息发送失败!

+ip_gate_not_same = IP地址和默认网关不可以相同!

+ip_innergate_not_same = IP地址和局域网的IP地址不可以在同一网段中!

+auto_success = 自动拨号成功

+auto_fail = 自动拨号失败

+auto_processing = 正在进行自动拨号

+#url filter

+url_filter_list = 当前系统的URL过滤规则

+url_filter_max = URL过滤规则最大数量为{0}

+url_repeated = URL已经存在。

+url_note1 = 您可以设置网页地址的过滤以过滤一些不良的网站。

+url_note2 = URL:设置需要过滤的url地址。

+

+#wds

+wds_mode = WDS模式

+wds_mode_0 = 禁用

+wds_mode_1 = RootAP 模式

+wds_mode_2 = Bridge 模式

+wds_mode_3 = Repeater 模式

+repeater_ssid = Repeater SSID

+wpa_algorithms = WPA算法

+enable_wds_confirm = 如果开启WDS,那么Wi-Fi基本设置将被禁用,继续吗?

+#sys log

+sys_log = 系统日志

+log_setting = 日志设置

+syslog_mode_all = 所有

+syslog_mode_wan_connect = WAN Connect

+syslog_mode_sms = SMS

+syslog_mode_tr069 = tr069

+syslog_mode_voip = VoIP

+syslog_mode_dlna = DLNA

+syslog_mode_wlan = Wi-Fi

+syslog_mode_router = Router

+view_log = 查看日志

+log_info = 日志信息

+

+#add at 2013.6.20

+periodic_inform = 周期性通知

+periodic_inform_interval = 周期性通知间隔

+periodic_inform_time = 周期性通知时间

+certificate_import = 证书

+import_certificate_btn = 导入

+certificate_file_nomatch = 证书文件错误

+#voip setting

+outbound_mode = Outbound模式

+outbound_server = Outbound服务器

+outbound_port = Outbound端口

+stun_mode = STUN模式

+stun_server = STUN服务器

+register_every = 注册有效期

+advanced_options = 高级选项

+sip_port = SIP端口

+rtp_port = RTP端口

+voip_outbound_port_check = 无效端口

+voip_time_check = 注册时间无效

+timeRange = [1,3600]秒

+voip_sip_port_check = 无效端口

+voip_port_compare = 无效的端口范围

+warn_information = VoIP参数设置成功,请重新注册。

+#voip user details

+user_details_title = SIP服务器和配置

+sip_register_server = SIP注册服务器

+sip_domain = SIP域

+sip_realm = SIP范围

+sip_proxy_mode = SIP代理模式

+sip_proxy_server = SIP代理服务器

+authorization = 鉴权

+display_name = 显示名称

+authorized_user_name = 鉴权用户名

+authorized_password = 授权密码

+voip_register_status = VoIP注册状态

+register_failed = 注册失败

+register_success = 注册成功

+register_connecting = 注册连接中

+unregister = 注销成功

+deregister = 注销

+sip_domain_check = SIP域地址无效!

+sip_realm_check = SIP域无效!

+sip_proxy_server_check = 代理服务器无效!

+display_name_check = 显示名称无效!

+authorized_username_check = 鉴权用户名无效!

+account_password_check = 密码无效!

+#voip advanced settings

+sip_advanced_options = 高级选项

+adv_sip_t38 = T.38传真编码

+sip_dtmf = DTMF

+voip_sip_dtmf_method_inband = InBand

+voip_sip_dtmf_method_rfc2833 = RFC2833

+voip_sip_dtmf_method_sipinfo = SIPInfo

+sip_encoder = 编码

+voip_sip_encoder_method_0 = G.711 u-Law

+voip_sip_encoder_method_1 = G.711 a-Law

+voip_sip_encoder_method_2 = G.722

+voip_sip_encoder_method_3 = G.729

+voip_sip_encoder_method_4 = G.726-16kps

+voip_sip_encoder_method_5 = G.726-24kps

+voip_sip_encoder_method_6 = G.726-32kps

+voip_sip_encoder_method_7 = G.726-40kps

+sip_vad = VAD

+sip_cng = CNG

+#voip supplementary service

+sip_protocol_voip = VoIP补充业务

+sip_protocol_call_forw = 呼叫转移

+voip_forwarding_mode_1 = 无条件呼叫转移

+voip_forwarding_mode_2 = 遇忙转移

+voip_forwarding_mode_3 = 无应答转移

+voip_forwarding_mode_0 = 禁止所有转移

+sip_protocol_forw_uri = 发送URI

+show_msg = 请在电话上按'*80'!

+sip_protocol_incoming_call = 免扰功能

+sip_protocol_call_waiting = 呼叫等待

+wds_note = WDS:无线分布式系统

+#voip user details

+connect_note = 请先连接网络,再使用VOIP功能!

+#fota

+upgrade_pack_fix_success = 升级成功!

+upgrade_pack_fix_failed = 升级失败!

+have_new_version = 发现新版本,设备将升级。

+######key same value different###########

+dmz_note_info = 如果终端设备无法通过该设备运行网络应用程序,请启用 DMZ,在输入框输入该终端设备的 IP 地址。

+dlna_note_info = DLNA: 数字生活网络联盟。

+dlna_note_httpshare = 您可以设置要在该网页上共享的数字媒体服务器 (DMS) 设备名称和媒体类型。

+#############串口转网口###################

+switch_port_title = 网口转串口

+open_serial_port = 开启网口转串口

+close_serial_port = 关闭网口转串口

+switching = 转换中...

+##############定时重启功能wording###################

+restart_schedule = 定时重启

+enable_reboot_switch = 启动定时重启功能

+enable_reboot_byday = 按天自动重启

+enable_reboot_byweek = 按周自动重启

+enable_reboot_bymonth = 按月自动重启

+synchronized = 已同步

+unsynchronized = 未同步

+week = 星期

+login_password_length_check = 请输入至少4位字符。

+system_time_not_syn = 系统时间未同步!

+fota_note1 = 您可以为您的设备设置自动检测周期,使设备定时自动检测是否有新版本的软件。

+local_note = 您可以选择本地电脑中的升级文件,将设备软件升级到选中的版本,完成系统修复和优化。

+

+#new word

+modify_password = 修改登录密码

+

+#家长控制

+parental_control = 家长控制

+pc_children_group = 儿童组设备

+pc_children_group_manage = 儿童组管理

+pc_manage = 管理

+pc_no_children_device = 没有设置儿童组设备

+pc_children_group_desc = 添加到儿童组的所有设备将受到上网规则的限制

+pc_edit_host_name = 修改主机名:

+pc_internet_rule = 上网规则

+pc_time_limited = 上网时间设置

+pc_site_white_list = 网站白名单

+pc_manage_children_group = 管理儿童组设备

+pc_current_attached_devices =当前接入设备

+pc_action = 操作

+pc_remove = 移除

+pc_remove_all = 移除所有

+pc_add = 添加

+pc_leave = 离开

+pc_add_white_site = 添加白名单

+pc_in_child_group = 已在儿童组

+pc_forbid_time = 禁止上网时段

+pc_allow_time = 允许上网时段

+pc_setting_desc =可用鼠标点按设置禁止或允许上网时段

+pc_name = 网站名

+pc_link = 链接

+pc_not_save = 数据还未保存,请注意保存。

+pc_link_exist = 链接已存在!

+no_data = 没有数据

+sun = 周日

+mon = 周一

+tues = 周二

+wed = 周三

+thur = 周四

+fri = 周五

+sat = 周六

+

+#定时休眠唤醒

+tsw_settings = 定时休眠唤醒设置

+tsw = 定时休眠唤醒

+time_sleep_wake_up = 定时休眠唤醒设置

+tsw_timer_on = 定时唤醒时间

+tsw_timer_off = 定时休眠时间

+tsw_sys_time_mode_alert = 请先连接网络,使SNTP同步服务器时间后即可设置。

+tsw_time_interval_alert = 时间间隔不得小于10分钟。

+

+#new wording

+advanced_settings = 高级设置

+others = 其他

+others_restart_reset = 重启与复位

+others_note_info = 当重启或复位路由器后,你需要重新登陆

+

+pwd_sub_title = 管理你的无线路由器有关信息

+pwd_note = 当你登陆无线路由器时,需要输入此密码(不同于你的无线网络密码)

+current_network = 当前网络

+

+wifi_wireless_settings = Wi-Fi设置

+wifi_main_sub_title = 建立你的无线热点,以供手机或笔记本等无线设备上网使用

+wifi_broadcast_desc = SSID 广播

+wifi_isolated_desc = 将所有的无线客户端设备完全隔离

+

+detail_info = 详细信息

+sd_u_share = U盘共享

+

+settings_wireless = 设置无线内网

+settings_internet = 设置外网连接

+not_connect_network = 未连接网络

+

+traffic_data_plan = 流量统计

+traffic_pie_title = 流量套餐

+traffic_sub_title = 您可以在该页面创建流量计划、查询已用流量及剩余流量

+traffic_used = 已使用

+traffic_used_text = {0} 已使用

+traffic_limit_data = 流量套餐

+traffic_limit_data_text = {0} 流量套餐

+traffic_alert_reach_text = 当达到{0}%,{1} 时提醒我

+traffic_data_left_text = {0} 剩余

+traffic_when = 当达到

+traffic_remind_me = %,时提醒我

+traffic_remind_me_time = ,时提醒我

+traffic_limit_time_text = {0}套餐

+traffic_limit_time_h =  {0} 小时套餐

+traffic_limit_time_m =  {0} 分钟套餐

+traffic_not_set_limited = 未设置流量套餐,点按设置

+

+echarts_used = 已使用

+echarts_left1 = 未使用

+echarts_alert = 提醒值

+echarts_alarm = 已使用(超出提醒值)

+echarts_free = 未使用

+echarts_full = 流量超出

+echarts_no = 未设置

+

+3g = 3G

+wan = WAN

+connection_mode = 联网模式

+wireless_access_device = 无线接入设备

+cable_access_device = 有线接入设备

+station_info_sub_title = 本页面显示了连接到本路由器的所有无线终端,其中包括无线终端的设备名称、MAC(介质访问控制)地址

+station_info_desc = 更多的权限控制选项,请查看

+

+device_unit = 台

+ota_last_update_check = 最后更新时间:

+main_ssid_num = 主 SSID ({0})

+guest_ssid_num = 副 SSID ({0})

+wifi_slider_desc = * 拖动进度条已调整各SSID最大可接入数量

+wif_guest_disabled = 副SSID 没有开启

+

+phone_number = 号码

+equalToPin = 两次输入的PIN码不一致

+equalToPassword = 两次输入的密码不一致

+

+pppoe_mode_type_PPPOE = PPPoE

+pppoe_mode_type_STATIC = 静态IP

+pppoe_mode_type_DHCP = 动态IP

+pppoe_mode_type_AUTO = 自动

+

+tsw_note = 定时休眠唤醒功能,当定时休眠唤醒功能打开时,设备将进入休眠状态,此时设备的Wi-Fi功能将会自动关闭。

+tsw_note_on = 定时唤醒时间:您可以设置设备唤醒时间。

+tsw_note_off = 定时休眠时间:您可以设置设备定时休眠时间。

+

+parent_control_note_kids = 儿童组设备:显示当前儿童组设备。

+parent_control_note_manage = 儿童组管理:管理儿童组设备,您可以从当前连接设备列表添加儿童组设备。

+parent_control_note_time = 上网时间设置:设置儿童上网时间规则,即允许儿童设备上网的时间。

+parent_control_note_whitelist = 网站白名单:设置网站白名单,即允许儿童设备访问的网站。

+parent_control_note_siteName = 白名单网站名不能包含以下字符: < > [ ] * $ & : , ; " ' ` / \\ | ? ¥

+parent_control_note_siteLink = 白名单链接输入时请以“http://”或“https://”开头。

+firewal_note = 注意:防火墙相关的规则设置,可能不会立即生效,需等待几分钟或重启设备,如需立即生效,建议重启设备。

+

+wan_note_dial = 拨号方式:

+wan_note_connection_mode = 请为您的设备设置合适的网络连接方式:

+wan_note_connection_mode_pppoe = PPPoE:通过PPPoE方式接入外网,您需要向您的运营商咨询PPPoE用户名和密码。

+wan_note_connection_mode_dhcp =  动态IP:通过动态IP地址方式接入外网。

+wan_note_connection_mode_static = 静态IP:通过设置静态IP地址的方式接入外网,您需要设置IP地址、子网掩码、默认网关、首选DNS及备用DNS。

+wan_note_user_name = 用户名:填写您的PPPoE帐号。

+wan_note_password = 密码:填写您的PPPoE密码。

+wan_note_connection_mode_auto = 自动:自动选择动态IP或PPPoE方式接入外网,您需要向您的运营商咨询PPPoE用户名和密码。

+

+wps_pin_validator = 请输入有效的PIN码

+device_rename = 请输入有效的名称。

+

+turnoff_button = 关机

+others_turn_off = 关机

+turnoff_confirm  = 确定关机吗?

+turnoff = 关机中...

+setting_no_change = 您的设置未发生变化。

+Extend_accessDevice = WIFI最大接入数不能小于当前接入设备数。

+TBcheck = 请输入一个介于1和4095之间的值。

+apn_pdptype_change_note = 如果该设置被改变,通过域名 {0} 访问Web页面可能存在打不开的风险,这时候请尝试 {1} 来访问。

+apn_alert = 当前操作将会重启设备。是否继续?

+apn_alert_restart = 默认APN设置成功,设备正在重启。

+apn_diconneted_network_confirm = 当前操作将会断开网络,是否继续?

+

+#super

+super = 锁小区设置

+lockCell_settings = 锁小区设置

+v4_settings = 机卡互锁 (V4 加密)

+

+cell_id1 = Cell Id 1

+cell_id2 = Cell Id 2

+cell_id3 = Cell Id 3

+cell_id4 = Cell Id 4

+cell_id5 = Cell Id 5

+

+v4_check = 无效字符,只能输入 0-9、a-z、A-Z

+v4_note = 您的设置将在设备重启后生效,您要继续吗?

+export_title = 导出设置

+band_3 = 频段 3

+band_8 = 频段 8

+band_38 = 频段 38

+band_39 = 频段 39

+band_40 = 频段 40

+band_info = 频段设置

+cell_id = 当前注册的小区

+lock_apply = 加锁

+unlock_apply= 解锁

+band_cell_settings = 频段小区设置

+export = 导出

+sinr = SINR

+cell_not_correct = 非锁定小区,联网失败!

+cell_id_lock = 已锁定的小区

+

+sip_uri_format = URI 模式

+user_name = 用户名

+pin_v4_encrypt = PIN 加密

+wep_cannot_2040 = 当主SSID或者副SSID的安全模式是OPEN (WEP)或者SHARED的时候,频带宽度不能是20MHz/40MHz!

+2040_cannot_wep = 当频带宽度是20MHz/40MHz的时候,SSID的安全模式不能为OPEN (WEP)或者SHARED。

+wifi_device_busy = Wi-Fi驱动繁忙中,请稍等...

+v4_settings = 机卡互锁 (V4 加密)

+manufactory_code = 厂商代码

+key_version_number = 密钥版本号

+key_value = 密钥值

+

+LockCell_note1 =  锁小区功能是用于对LTE网络的小区锁定,当前注册小区与锁定小区一致时允许联网,当前注册小区与锁定小区不一致时禁止发起联网。

+LockCell_note2 =  锁定小区功能开启且保存的锁定小区不为空时,每天开机和定时(8:00/14:00/20:00)比对当前注册的网络小区与锁定小区是否相同,如果不同则做断网处理。

+mac_blank = MAC地址不能为空

+

+vlan_switch = VLAN开关

+vlan_notice = 如果您要停用该功能,重启后才生效。请问您是否继续?

+vlan_notice2 = 如果您要开启该功能,多重网络名称开关必须是开启状态。请问您是否开启多重网络名称开关并开启VLAN功能?

+ap_hide = AP隐藏

+

+urlparent = 主域名后面不能再跟随以/开始的内容。

+not_change_mode = 设备正在后台配置相关参数,请稍后尝试

+

+

+#device

+device_status = 设备加密状态

+device_status_0 = 已解密

+device_status_1 = 未解密

+

+######DDNS###########

+ddns = DDNS

+Hash value is empty = Hash 值为空!

+DDNS Provider is empty = DDNS 服务器为空!

+register successful = 注册成功

+login error = 登陆错误

+network error = 网络错误

+registering = 正在注册

+not registered = 未注册

+error registering = 注册失败

+error = 错误

+ddns_set_mode = DDNS

+mode_set_mode_1 = 启用

+mode_set_mode_0 = 禁用

+mode_select_auto = 自动

+mode_select_manual = 手动

+ddns_mode = DDNS 模式

+Auto = 自动

+Manual = 手动

+DDNS_Status = DDNS 状态

+DDNSHashValue = Hash 值

+ddns_ProviderList = 动态DNS服务器

+ddns_account = 用户

+ddns_passwd = 密码

+ddns_domainName = 域名

+ddns_hashvalue_check = 无效字符,只能输入 0-9、a-z、A-Z 或 =

+ddns_note1 = 您可以设置动态域名服务,为动态WAN IP地址分配一个固定域名。

+ddns_note2 = 动态DNS服务器:设置提供动态域名服务的服务器。

+ddns_note3 = 密码:密码的有效字符包含:0-9 a-z A-Z ! # $ * + , - . % : = ? @ [ ] ^ _ { | } ~ 

+ddns_note4 = 域名:设置要申请的域名。

+ddns_note5 = Hash 值:DDNS哈希值,在使用freedns服务器的时候需要。有效字符包含:0-9 a-z A-Z 或 = 

diff --git a/ap/app/zte_webui_min/index.html b/ap/app/zte_webui_min/index.html
new file mode 100755
index 0000000..1a2d3a4
--- /dev/null
+++ b/ap/app/zte_webui_min/index.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>

+<html>

+<head>

+<meta charset="UTF-8"/>

+<meta name="renderer" content="webkit"/>

+<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"/>

+<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>

+<meta http-equiv="Pragma" content="no-cache"/>

+<meta http-equiv="Expires" content="0"/>

+<title></title>

+<script type="text/javascript">

+document.write("<link rel='stylesheet' type='text/css' href='css/csn.css?random=" + Math.random() + "' />");

+document.write("<link rel='stylesheet' type='text/css' href='css/bt_strp.css?random=" + Math.random() + "' />");

+document.write("<link rel='stylesheet' type='text/css' href='css/com.css?random=" + Math.random() + "' />");

+</script>

+<link href="favicon.ico" rel="shortcut icon" />

+<!--[if lt IE 9]>

+<script type="text/javascript">

+document.write("<script type='text/javascript' rc='js/3rd/html5shiv.js?random=" + Math.random() + "'></s" + "cript>");

+document.write("<script type='text/javascript' rc='js/3rd/respond.js?random=" + Math.random() + "'></s" + "cript>");

+</script>

+<![endif]-->

+</head>

+<body>

+<div class="container" id="topContainer">

+    <div id="langLogoBar" class="row">

+        <div class="col-xs-4">

+            <a href="index.html">

+			<script type="text/javascript">

+			document.write("<img src='pic/res_logo_web.png?random=" + Math.random() + "' />");

+			</script>

+            </a>

+            <!--span class="center-block" id="webui_title"></span-->

+        </div>

+        <div id="statusBar" style="display: none;" class="col-xs-8 text-right">

+            <span id="networkType" title="network_type" i18n="true" data-bind="text: networkType" class="statusItem"></span>

+            <span id="operator" title="network_provider" i18n="true" data-bind="text: networkOperator" class="statusItem"></span>

+            <span id="OTA" title="ota_title" i18n="true" data-bind="visible:isShowFotaNewversionIcon()" class="statusItem">

+                <a onclick="return showOTAAlert();">

+				<script type="text/javascript">

+				document.write("<img src='pic/res_update.gif?random=" + Math.random() + "' class='paddingbottom6' />");

+				</script>

+                </a>

+            </span>

+            <span id="signal_strength" title="signal_strength" i18n="true" class="statusItem"><i data-bind="attr:{'class': signalCssClass}" class="signal">&nbsp;</i></span>

+            <span id="connection_status" title="connection_status" i18n="true" class="statusItem"><i data-bind="attr:{'class': connectionCssClass}" class="icon_connection">&nbsp;</i></span>

+            <span id="rj45_connection_status" title="rj45_connection_status" i18n="true" data-bind="visible: isShowRj45ConnectionIcon" class="statusItem"><i data-bind="attr:{'class': rj45ConnectionCssClass}" class="icon_connection">&nbsp;</i></span>

+            <span id="sms_unread_count" title="sms_unread_count" i18n="true" data-bind="visible: smsUnreadCount() > 0 || showSmsDeleteConfirm()" style="display: none; position: relative;" class="statusItem">

+                <a onclick="return gotoSmsList();" href="javascript: void(0)">

+					<script type="text/javascript">

+					document.write("<img data-bind='visible: smsUnreadCount() > 0 && !showSmsDeleteConfirm()' src='./pic/msg_unread.png?random=" + Math.random() + "' class='paddingbottom6'/>");

+					document.write("<img data-bind='visible: showSmsDeleteConfirm()' src='./pic/msg_full.gif?random=" + Math.random() + "' class='paddingbottom6'/>");

+					</script>

+                    <sup data-bind="visible: smsUnreadCount() > 0, text: smsUnreadCount" class="smsUnreadCount"></sup>

+                </a>

+            </span>

+            <span id="statusItemSimStatus" title="sim_status" i18n="true"  class="statusItem"><img data-bind="attr: {src: simStatus}" class="paddingbottom6"/></span>

+            <span id="roamingStatus" title="roaming_status" i18n="true" data-bind="visible: roamingStatus() == 'R'" style="display: none;" class="statusItem">

+			<script type="text/javascript">

+			document.write("<img src='./pic/res_roaming.png?random=" + Math.random() + "' class='paddingbottom6'/>");

+			</script>			

+			</span>

+            <span id="wifi_status" title="wifi_status" i18n="true" data-bind="visible: hasWifi" class="statusItem">

+                <!--img class="paddingbottom6" id="wifi_status_img" data-bind="attr: {src: wifiStatusImg}"/-->

+                <i class="wifi_status" data-bind="attr:{'class': wifiStatusCssClass}">&nbsp;</i>

+            </span>

+            <span title="battery_level" i18n="true" data-bind="visible: hasBattery" class="statusItem"><img id="batteryCharging" data-bind="attr: {src: batteryPers}" class="paddingbottom6"/></span>

+        </div>

+    </div>

+    <div id="manageBar" class="row">

+        <div id="manageContainer" class="col-xs-12 text-right">

+            <span id="logout">

+                <a data-trans="modify_password" href="#pwd_mode" data-bind="visible:showLogout()" class="margin-right-10"></a>

+                <a id="logoutlink" data-trans="logout" href="javascript:void(0)" data-bind="click:logout,visible:showLogout() " style="display: none;" class="margin-right-10"></a>

+            </span>

+            <select id="language" data-bind="options: languages, value: currentLan, optionsText: 'text', optionsValue: 'value', event:{ change: langChangeHandler}" class="marginright10"></select>

+        </div>

+    </div>

+</div>

+<div id="indexContainer" class="container">

+    <div id="mainContainer" style="min-height: 450px;">

+        <div id='container'></div>

+    </div>

+</div>

+<div id="footer" style="border-top:1px solid #dddddd" class="container margin-top-5">

+    <span data-trans='copyright'></span>&nbsp; <!--span data-trans="vertical_bar"></span> &nbsp;<a href="http://www.demo.com" target="_blank" data-trans="open_source_licenses" class="extendLink"></a-->

+</div>

+

+<div id='result-overlay'>

+    <div class='header'></div>

+    <br/>

+    <div class="text-center">

+        <div>

+            <div id="result-image"></div>

+        </div>

+        <div id="result_wording"></div>

+    </div>

+</div>

+

+<div id='loading'>

+    <div class='header'><span id="loadMsg"></span></div>

+    <br/>

+    <div class="text-center">

+		<div><span id="loading_wording" class="message"></span></div>

+        <img id="loadingImg" src="pic/res_loading.gif?bG9hZGluZy5naWY="/>

+        <div id="loading_container"></div>

+    </div>

+</div>

+

+<div id='progress'>

+    <div class='header'><span id="barMsg"></span></div>

+     <br/>

+     <div class="progress-content">

+         <div class="progress-bar-container">

+             <div id="bar" class="progress-bar"></div>

+             <div id="barValue" class="progress-bar-value"></div>

+         </div>

+         <div id="progress_container" class="progress-prompt"></div>

+     </div>

+ </div>

+<!-- confirm content -->

+<div id='confirm'>

+    <div class='header'><span id="popTitle"></span></div>

+    <div id="confirm-message-container">

+        <div class='icon'><img id='confirmImg'/></div>

+        <div class="confirm-message">

+            <div class='message'></div>

+            <div class='promptDiv'>

+                <input id="promptInput" name="promptInput" type="text" maxlength="25" class="width190"/><br/>

+                <label class="promptErrorLabel colorRed"></label>

+            </div>

+        </div>

+    </div>

+    <div class='buttons'>

+        <input id='okbtn' type="button" data-trans='ok' class="btn btn-default simplemodal-close"/>

+        <input id='yesbtn' type="button" data-trans='yes' class="btn btn-default "/>

+        <input id='nobtn' type="button" data-trans='no' class="btn btn-default simplemodal-close"/>

+    </div>

+</div>

+<div id='popupSettingWindow'>

+    <div class='header'>

+		<p class="tag-popup-close"><a href="javascript:hidePopupSettingWindow();"></a></p>

+	</div>

+	<div id="htmlContainer" class="modal-body"></div>

+</div>

+<div id="buttom-bubble">

+</div>

+<script type="text/x-jquery-tmpl" id="newMessagePopTmpl">

+    <div class="bubbleItem ${report}" id="${mark}">

+        <h3>

+			<span data-trans="${titletrans}">${title}</span> ${name} <a href="javascript:void(0);" data-targetid="${mark}" class="bubbleCloseBtn"></a>

+		</h3>

+        <div class="bubbleContainer">

+            <div class="bubbleContent">${content}</div>

+            <div class="bubbleDatetime">${datetime}</div>

+        </div>

+    </div>

+</script>

+<script type="text/javascript">

+document.write("<script type='text/javascript' data-main='js/main' src='js/3rd/require-jquery.js?random=" + Math.random() + "'></s" + "cript>");

+</script>

+</body>

+</html>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/js/3rd/apache.echarts.js b/ap/app/zte_webui_min/js/3rd/apache.echarts.js
new file mode 100755
index 0000000..93e6746
--- /dev/null
+++ b/ap/app/zte_webui_min/js/3rd/apache.echarts.js
@@ -0,0 +1,8978 @@
+!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], 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")

+

+          , S = t("zrender")

+          , M = t(Ae)

+

+          , 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 (!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.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.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/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/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("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"], 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")

+

+          , 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 = {}

+                  , 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),

+

+        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], function(t) {

+        function e(t) {

+            return null != t && "none" != t

+        }

+        function i(t) {

+            return t

+        }

+        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)

+          , C = Math.round

+          , T = t("zrender/graphic/Path")

+          , P = t("zrender/core/matrix")

+          , z = t("zrender/core/vector")

+          , k = t("zrender/graphic/Gradient")

+          , I = {};

+        return I.Group = t("zrender/container/Group"),

+        I.Text = t("zrender/graphic/Text"),

+        I[w] = t("zrender/graphic/shape/Sector"),

+        I.Polyline = t("zrender/graphic/shape/Polyline"),

+        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/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")

+          , 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;

+                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/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/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/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("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/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) {

+

+                    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/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/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/Polyline", [Ce, "../Path"], function(t) {

+        return t("../Path")[le]({

+            type: "polyline",

+            shape: {

+                points: null,

+                smooth: !1,

+                smoothConstraint: null

+            },

+            style: {

+                stroke: "#000",

+                fill: null

+            },

+        })

+    }),

+    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/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], 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 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)

+          , 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"], 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("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("zrender/contain/path", [Ce, "../core/PathProxy", "./line", "./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")

+          , 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("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;

+                this.clipPath && this.clipPath.addSelfToZr(t)

+            },

+            removeSelfFromZr: function(t) {

+                this.__zr = null;

+                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("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], function(t) {

+        var e = t("../animation/Animator")

+          , i = t(d)

+          , n = i.isString

+          , r = i.isFunction

+          , a = i[ue]

+          , 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("zrender/animation/Animator", [Ce, "./Clip", 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")

+          , 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("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("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("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/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("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/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", "./Layer"], 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")

+          , d = t("./Layer")

+          , 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 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/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("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/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/tooltip/TooltipContent", [Ce, Ae, "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)

+          , 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/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)

+

+                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/pie"),

+    t("echarts/component/tooltip"),

+    Te

+});

diff --git a/ap/app/zte_webui_min/js/3rd/crypto-js.js b/ap/app/zte_webui_min/js/3rd/crypto-js.js
new file mode 100755
index 0000000..be5c2ea
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/html5shiv.js b/ap/app/zte_webui_min/js/3rd/html5shiv.js
new file mode 100755
index 0000000..8783215
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.additional-methods.js b/ap/app/zte_webui_min/js/3rd/jquery.additional-methods.js
new file mode 100755
index 0000000..e250c79
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.chosen.js b/ap/app/zte_webui_min/js/3rd/jquery.chosen.js
new file mode 100755
index 0000000..56e8e9b
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.fileinput.js b/ap/app/zte_webui_min/js/3rd/jquery.fileinput.js
new file mode 100755
index 0000000..80971a1
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.i18n.js b/ap/app/zte_webui_min/js/3rd/jquery.i18n.js
new file mode 100755
index 0000000..547a753
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.simplemodal.js b/ap/app/zte_webui_min/js/3rd/jquery.simplemodal.js
new file mode 100755
index 0000000..9e9d5a4
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.tmpl.js b/ap/app/zte_webui_min/js/3rd/jquery.tmpl.js
new file mode 100755
index 0000000..a615f5b
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.translate.js b/ap/app/zte_webui_min/js/3rd/jquery.translate.js
new file mode 100755
index 0000000..1301956
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jquery.validate.js b/ap/app/zte_webui_min/js/3rd/jquery.validate.js
new file mode 100755
index 0000000..ef398db
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/jqui.js b/ap/app/zte_webui_min/js/3rd/jqui.js
new file mode 100755
index 0000000..8ad022f
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/knockout.base.js b/ap/app/zte_webui_min/js/3rd/knockout.base.js
new file mode 100755
index 0000000..226a50a
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/knockout.js b/ap/app/zte_webui_min/js/3rd/knockout.js
new file mode 100755
index 0000000..7301dca
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/knockout.simpleGrid.js b/ap/app/zte_webui_min/js/3rd/knockout.simpleGrid.js
new file mode 100755
index 0000000..2053f39
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/require-jquery.js b/ap/app/zte_webui_min/js/3rd/require-jquery.js
new file mode 100755
index 0000000..4167af3
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/require-text.js b/ap/app/zte_webui_min/js/3rd/require-text.js
new file mode 100755
index 0000000..4c13a84
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/respond.js b/ap/app/zte_webui_min/js/3rd/respond.js
new file mode 100755
index 0000000..df51dd2
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/twbs.bootstrap.js b/ap/app/zte_webui_min/js/3rd/twbs.bootstrap.js
new file mode 100755
index 0000000..a7bd176
--- /dev/null
+++ b/ap/app/zte_webui_min/js/3rd/twbs.bootstrap.js
@@ -0,0 +1,2127 @@
+/*
+ * 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)
+
+    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
+    var $this   = $(this)
+    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+    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)
+
+    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
+    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)
+
+    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)
+
+      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)
+
+    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_min/js/3rd/underscore.base.js b/ap/app/zte_webui_min/js/3rd/underscore.base.js
new file mode 100755
index 0000000..62b3c30
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/3rd/underscore.js b/ap/app/zte_webui_min/js/3rd/underscore.js
new file mode 100755
index 0000000..2f29de4
--- /dev/null
+++ b/ap/app/zte_webui_min/js/3rd/underscore.js
@@ -0,0 +1,3 @@
+define(["3rd/underscore.base"], function () {

+    return window._

+});

diff --git a/ap/app/zte_webui_min/js/3rd/webtoolkit.base64.js b/ap/app/zte_webui_min/js/3rd/webtoolkit.base64.js
new file mode 100755
index 0000000..8ab9944
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/com.js b/ap/app/zte_webui_min/js/com.js
new file mode 100755
index 0000000..334893b
--- /dev/null
+++ b/ap/app/zte_webui_min/js/com.js
@@ -0,0 +1,11146 @@
+

+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;

+        }

+        if(set.WIFI_SUPPORT_QR_CODE){

+            target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + libjq.now();

+        } else {

+            target.qrcodeSrc = './pic/res_blacktrans.png';

+        }

+        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_min/js/ext/crypto-js-null.js b/ap/app/zte_webui_min/js/ext/crypto-js-null.js
new file mode 100755
index 0000000..eb3a541
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/ext/menu.js b/ap/app/zte_webui_min/js/ext/menu.js
new file mode 100755
index 0000000..6277652
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/ext/menu_pppoe.js b/ap/app/zte_webui_min/js/ext/menu_pppoe.js
new file mode 100755
index 0000000..a1bf328
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/ext/set.js b/ap/app/zte_webui_min/js/ext/set.js
new file mode 100755
index 0000000..4be0732
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/ext/set_aic8800.js b/ap/app/zte_webui_min/js/ext/set_aic8800.js
new file mode 100755
index 0000000..e1f4049
--- /dev/null
+++ b/ap/app/zte_webui_min/js/ext/set_aic8800.js
@@ -0,0 +1,64 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Mobile Hotspot',

+        PRODUCT_TYPE: 'UFI', // ²úÆ·ÀàÐÍUFI¡¢CPE

+        TURN_OFF_SUPPORT: false, //ÊÇ·ñÖ§³Ö¹Ø»ú

+        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,

+        //WIFI_WAP3_SUPPORT: false, 

+        //WIFI_WPA2_WAP3_SUPPORT: false, 

+	WIFI_SUPPORT_QR_CODE: false, //ÊÇ·ñÖ§³Öwifi¶þάÂëÏÔʾ

+        SD_CARD_SUPPORT: false, //ÊÇ·ñÖ§³ÖSD¿¨

+	UPGRADE_TYPE: 'NONE', //ȡֵÓÐ"NONE","OTA","FOTA","TWO_PORTION"

+	HAS_FOTA: false, //ÊÇ·ñÖ§³ÖFOTA

+	HAS_UPDATE_CHECK: false, //ÊÇ·ñÖ§³ÖÉý¼¶¼ì²âÉèÖÃ

+	HAS_UPNP: false, //ÊÇ·ñÖ§³ÖUPNP

+        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: '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_min/js/ext/set_cpe.js b/ap/app/zte_webui_min/js/ext/set_cpe.js
new file mode 100755
index 0000000..aa929eb
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/ext/set_cpe_sw.js b/ap/app/zte_webui_min/js/ext/set_cpe_sw.js
new file mode 100755
index 0000000..3e3e4da
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/ext/set_min.js b/ap/app/zte_webui_min/js/ext/set_min.js
new file mode 100755
index 0000000..e33eb5f
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/ext/set_ssv6x5x.js b/ap/app/zte_webui_min/js/ext/set_ssv6x5x.js
new file mode 100755
index 0000000..a70fcd1
--- /dev/null
+++ b/ap/app/zte_webui_min/js/ext/set_ssv6x5x.js
@@ -0,0 +1,56 @@
+define(function () {

+    var config = {

+        WEBUI_TITLE: '4G Mobile Hotspot',

+        PRODUCT_TYPE: 'UFI', // ²úÆ·ÀàÐÍUFI¡¢CPE

+        TURN_OFF_SUPPORT: false, //ÊÇ·ñÖ§³Ö¹Ø»ú

+        WIFI_SLEEP_SUPPORT: false, // ÊÇ·ñÖ§³ÖwifiÐÝÃß

+        HAS_BATTERY: false, //ÊÇ·ñÓÐµç³Ø

+        FAST_BOOT_SUPPORT: false, //ÊÇ·ñÖ§³Ö¿ìËÙ¿ª»ú

+        HAS_BLACK_AND_WHITE_FILTER: 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, 

+	WIFI_SUPPORT_QR_CODE: false, //ÊÇ·ñÖ§³Öwifi¶þάÂëÏÔʾ

+        SD_CARD_SUPPORT: false, //ÊÇ·ñÖ§³ÖSD¿¨

+	UPGRADE_TYPE: 'NONE', //ȡֵÓÐ"NONE","OTA","FOTA","TWO_PORTION"

+	HAS_FOTA: false, //ÊÇ·ñÖ§³ÖFOTA

+	HAS_UPDATE_CHECK: false, //ÊÇ·ñÖ§³ÖÉý¼¶¼ì²âÉèÖÃ

+	HAS_UPNP: false, //ÊÇ·ñÖ§³ÖUPNP

+        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_min/js/ext/set_xr819.js b/ap/app/zte_webui_min/js/ext/set_xr819.js
new file mode 100755
index 0000000..6c8a276
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/lib.js b/ap/app/zte_webui_min/js/lib.js
new file mode 100755
index 0000000..59354d2
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/main.js b/ap/app/zte_webui_min/js/main.js
new file mode 100755
index 0000000..a771f7d
--- /dev/null
+++ b/ap/app/zte_webui_min/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_min/js/net.js b/ap/app/zte_webui_min/js/net.js
new file mode 100755
index 0000000..f245f41
--- /dev/null
+++ b/ap/app/zte_webui_min/js/net.js
@@ -0,0 +1,4175 @@
+

+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_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;

+		target.hasUpnp = config.HAS_UPNP;

+    }

+

+	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;

+        }

+        if(config.WIFI_SUPPORT_QR_CODE){

+            target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + $.now();

+        } else {

+            target.qrcodeSrc = './pic/res_blacktrans.png';

+        }

+        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_min/js/set.js b/ap/app/zte_webui_min/js/set.js
new file mode 100755
index 0000000..f2dc0cc
--- /dev/null
+++ b/ap/app/zte_webui_min/js/set.js
@@ -0,0 +1,959 @@
+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, //是否有登录页面

+        HAS_UPNP: true, //是否支持UPNP

+        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_min/js/sim_device.js b/ap/app/zte_webui_min/js/sim_device.js
new file mode 100755
index 0000000..97e3e9f
--- /dev/null
+++ b/ap/app/zte_webui_min/js/sim_device.js
@@ -0,0 +1,5009 @@
+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;

+        }

+        if(config.WIFI_SUPPORT_QR_CODE){

+            target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + $.now();

+        } else {

+            target.qrcodeSrc = './pic/res_blacktrans.png';

+        }

+        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_min/js/wifi.js b/ap/app/zte_webui_min/js/wifi.js
new file mode 100755
index 0000000..df3583a
--- /dev/null
+++ b/ap/app/zte_webui_min/js/wifi.js
@@ -0,0 +1,3732 @@
+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);

+        }

+        if(config.WIFI_SUPPORT_QR_CODE){

+            target.qrcodeSrc = './pic/qrcode_multi_ssid_wifikey.png?_=' + $.now();

+        } else {

+            target.qrcodeSrc = './pic/res_blacktrans.png';

+        }

+        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);

+        }

+        if(config.WIFI_SUPPORT_QR_CODE){

+            target.qrcodeSrc = './pic/qrcode_ssid_wifikey.png?_=' + $.now();

+        } else {

+            target.qrcodeSrc = './pic/res_blacktrans.png';

+        }

+        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

+    };

+});

+

diff --git a/ap/app/zte_webui_min/makefile b/ap/app/zte_webui_min/makefile
new file mode 100755
index 0000000..03c1c4b
--- /dev/null
+++ b/ap/app/zte_webui_min/makefile
@@ -0,0 +1,77 @@
+include $(zte_app_mak)

+

+all:

+	echo "zte_webui compile do nothing"

+

+clean:

+	echo "zte_webui clean do nothing"

+

+romfs:

+	@mkdir -p $(ROOTFS_DIR)/etc_ro/web

+	@cp -afvp $(APP_DIR)/zte_webui_min/*   $(ROOTFS_DIR)/etc_ro/web

+	find . -type f -name '*.js' | xargs -n1 -I {} java -jar $(YUICOMPRESSOR)  {} -o  $(ROOTFS_DIR)/etc_ro/web/{}

+	find . -type f -name '*.css' | xargs -n1 -I {} java -jar $(YUICOMPRESSOR)  {} -o  $(ROOTFS_DIR)/etc_ro/web/{}

+	find . -type f -name '*.html' | xargs -n1 -I {} sed -i 's/^[ \t]*//g' $(ROOTFS_DIR)/etc_ro/web/{}

+	find . -type f -name '*.html' | xargs -n1 -I {} sed -i 's/[ \t]*$$//g' $(ROOTFS_DIR)/etc_ro/web/{}

+	find . -type f -name '*.html' | xargs -n1 -I {} sed -i ":a;N;s/\r//g;ta" $(ROOTFS_DIR)/etc_ro/web/{}

+	find . -type f -name '*.html' | xargs -n1 -I {} sed -i ":a;N;s/\n//g;ta" $(ROOTFS_DIR)/etc_ro/web/{}

+ifneq ($(CONFIG_WIFI_MODULE), aic8800)

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/subpg/wifi_ap_station.html

+endif

+ifeq ($(CONFIG_WEBUI_TYPE),CPE)

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+	-cp -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_cpe.js $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+endif

+ifeq ($(CONFIG_WEBUI_TYPE),CPE_SW)	

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+	-cp -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_cpe_sw.js $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+endif

+

+ifeq ($(PRJ_IS_MIN), yes)

+	-cp -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_min.js $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+ifeq ($(CONFIG_WIFI_MODULE), xr819)

+	-cp -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_xr819.js $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+endif

+ifeq ($(CONFIG_WIFI_MODULE), ssv6x5x)

+	-cp -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_ssv6x5x.js $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+endif

+ifeq ($(CONFIG_WIFI_MODULE), aic8800)

+	-cp -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_aic8800.js $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+ifeq ($(CONFIG_WIFI_SINGLEAP), no)

+	-sed -i 's/WIFI_SLEEP_SUPPORT:false,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+	-sed -i 's/HAS_BATTERY:false,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+	-sed -i 's/TURN_OFF_SUPPORT:false,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+else

+	-sed -i 's/AP_STATION_SUPPORT:true,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+	-sed -i 's/HAS_MULTI_SSID:true,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js	

+endif

+endif

+endif

+

+ifneq ($(CONFIG_USE_WEBUI_SECURITY),yes)

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/3rd/crypto-js.js

+	-cp -v $(ROOTFS_DIR)/etc_ro/web/js/ext/crypto-js-null.js $(ROOTFS_DIR)/etc_ro/web/js/3rd/crypto-js.js

+	-sed -i 's/PASSWORD_ENCODE:false,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+endif

+ifeq ($(USE_FOTA),yes)

+	-sed -i 's/UPGRADE_TYPE:"NONE",//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+	-sed -i 's/HAS_FOTA:false,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+	-sed -i 's/HAS_UPDATE_CHECK:false,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+endif

+ifeq ($(CONFIG_MMI_LCD),yes)

+	-sed -i 's/WIFI_SUPPORT_QR_CODE:false,//' $(ROOTFS_DIR)/etc_ro/web/js/ext/set.js

+endif

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/crypto-js-null.js

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_min.js

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_xr819.js

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_ssv6x5x.js

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_aic8800.js

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_cpe.js

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/js/ext/set_cpe_sw.js

+	-rm -v $(ROOTFS_DIR)/etc_ro/web/makefile

+ifeq ($(CONFIG_USE_WEBUI_ZIP),yes)

+	(cd $(ROOTFS_DIR)/etc_ro && zip -r web.zip web)

+	(cd $(ROOTFS_DIR)/etc_ro && rm -rfv web)

+endif

+

+	

diff --git a/ap/app/zte_webui_min/mobile.html b/ap/app/zte_webui_min/mobile.html
new file mode 100755
index 0000000..7ea592a
--- /dev/null
+++ b/ap/app/zte_webui_min/mobile.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>

+<html>

+<head>

+    <meta charset="utf-8">

+    <script>

+        window.location.href="index.html";

+    </script>

+</head>

+<body >

+</body>

+</html>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/pic/a-direct.png b/ap/app/zte_webui_min/pic/a-direct.png
new file mode 100755
index 0000000..2d51031
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/a-direct.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/b-direct.png b/ap/app/zte_webui_min/pic/b-direct.png
new file mode 100755
index 0000000..3b617ef
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/b-direct.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/c-direct.png b/ap/app/zte_webui_min/pic/c-direct.png
new file mode 100755
index 0000000..128a5ea
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/c-direct.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/dial-off.png b/ap/app/zte_webui_min/pic/dial-off.png
new file mode 100755
index 0000000..cd78a46
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/dial-off.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/dial-on.png b/ap/app/zte_webui_min/pic/dial-on.png
new file mode 100755
index 0000000..07b9939
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/dial-on.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/direct-back.png b/ap/app/zte_webui_min/pic/direct-back.png
new file mode 100755
index 0000000..79cf8d2
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/direct-back.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/direct-right.png b/ap/app/zte_webui_min/pic/direct-right.png
new file mode 100755
index 0000000..a6b9e74
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/direct-right.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/local-connected.png b/ap/app/zte_webui_min/pic/local-connected.png
new file mode 100755
index 0000000..a673a5e
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/local-connected.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/local-connecting.png b/ap/app/zte_webui_min/pic/local-connecting.png
new file mode 100755
index 0000000..8adfe8c
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/local-connecting.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/local-disconnected.png b/ap/app/zte_webui_min/pic/local-disconnected.png
new file mode 100755
index 0000000..3c42666
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/local-disconnected.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/local-disconnecting.png b/ap/app/zte_webui_min/pic/local-disconnecting.png
new file mode 100755
index 0000000..a98598c
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/local-disconnecting.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/mobile.png b/ap/app/zte_webui_min/pic/mobile.png
new file mode 100755
index 0000000..8e386ab
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/mobile.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/msg_full.gif b/ap/app/zte_webui_min/pic/msg_full.gif
new file mode 100755
index 0000000..17db36a
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/msg_full.gif
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/msg_unread.png b/ap/app/zte_webui_min/pic/msg_unread.png
new file mode 100755
index 0000000..94fda40
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/msg_unread.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/new/device.png b/ap/app/zte_webui_min/pic/new/device.png
new file mode 100755
index 0000000..9d5cf04
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/new/device.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/new/direct.png b/ap/app/zte_webui_min/pic/new/direct.png
new file mode 100755
index 0000000..f0ebe8d
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/new/direct.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/new/direct_down.png b/ap/app/zte_webui_min/pic/new/direct_down.png
new file mode 100755
index 0000000..670ca41
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/new/direct_down.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/new/direct_top.png b/ap/app/zte_webui_min/pic/new/direct_top.png
new file mode 100755
index 0000000..5b7b720
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/new/direct_top.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/new/router.png b/ap/app/zte_webui_min/pic/new/router.png
new file mode 100755
index 0000000..217a531
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/new/router.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/new/surfing1.png b/ap/app/zte_webui_min/pic/new/surfing1.png
new file mode 100755
index 0000000..d9e01d2
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/new/surfing1.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/new/surfing2.png b/ap/app/zte_webui_min/pic/new/surfing2.png
new file mode 100755
index 0000000..5faa13f
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/new/surfing2.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-doc.png b/ap/app/zte_webui_min/pic/pic-doc.png
new file mode 100755
index 0000000..ce83429
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-doc.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-download.png b/ap/app/zte_webui_min/pic/pic-download.png
new file mode 100755
index 0000000..a06b8f1
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-download.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-file.png b/ap/app/zte_webui_min/pic/pic-file.png
new file mode 100755
index 0000000..8ef1617
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-file.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-film.png b/ap/app/zte_webui_min/pic/pic-film.png
new file mode 100755
index 0000000..e18657c
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-film.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-folder.png b/ap/app/zte_webui_min/pic/pic-folder.png
new file mode 100755
index 0000000..6853992
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-folder.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-mp3.png b/ap/app/zte_webui_min/pic/pic-mp3.png
new file mode 100755
index 0000000..1fea616
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-mp3.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-pdf.png b/ap/app/zte_webui_min/pic/pic-pdf.png
new file mode 100755
index 0000000..626a2dc
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-pdf.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-picture.png b/ap/app/zte_webui_min/pic/pic-picture.png
new file mode 100755
index 0000000..a67516b
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-picture.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-ppt.png b/ap/app/zte_webui_min/pic/pic-ppt.png
new file mode 100755
index 0000000..ff9fbe0
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-ppt.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-rar.png b/ap/app/zte_webui_min/pic/pic-rar.png
new file mode 100755
index 0000000..1af00b8
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-rar.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-xls.png b/ap/app/zte_webui_min/pic/pic-xls.png
new file mode 100755
index 0000000..2a457d1
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-xls.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic-xml.png b/ap/app/zte_webui_min/pic/pic-xml.png
new file mode 100755
index 0000000..dc11326
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic-xml.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic_connecting.gif b/ap/app/zte_webui_min/pic/pic_connecting.gif
new file mode 100755
index 0000000..6a0f9f4
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic_connecting.gif
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic_connection.png b/ap/app/zte_webui_min/pic/pic_connection.png
new file mode 100755
index 0000000..ad1a485
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic_connection.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic_disconnect.png b/ap/app/zte_webui_min/pic/pic_disconnect.png
new file mode 100755
index 0000000..2511516
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic_disconnect.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic_red.png b/ap/app/zte_webui_min/pic/pic_red.png
new file mode 100755
index 0000000..fce27ff
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic_red.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic_rj45_connect.png b/ap/app/zte_webui_min/pic/pic_rj45_connect.png
new file mode 100755
index 0000000..97c1154
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic_rj45_connect.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/pic_wifi_connect.png b/ap/app/zte_webui_min/pic/pic_wifi_connect.png
new file mode 100755
index 0000000..c5a6208
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/pic_wifi_connect.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_add_contact.png b/ap/app/zte_webui_min/pic/png_add_contact.png
new file mode 100755
index 0000000..cbeb0ed
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_add_contact.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_add_contact_hover.png b/ap/app/zte_webui_min/pic/png_add_contact_hover.png
new file mode 100755
index 0000000..4574e5b
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_add_contact_hover.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_delete.png b/ap/app/zte_webui_min/pic/png_delete.png
new file mode 100755
index 0000000..03238f9
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_delete.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_delete_hover.png b/ap/app/zte_webui_min/pic/png_delete_hover.png
new file mode 100755
index 0000000..849c8cb
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_delete_hover.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_forward.png b/ap/app/zte_webui_min/pic/png_forward.png
new file mode 100755
index 0000000..24cb20a
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_forward.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_forward_hover.png b/ap/app/zte_webui_min/pic/png_forward_hover.png
new file mode 100755
index 0000000..a948791
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_forward_hover.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_new_sms_bg.png b/ap/app/zte_webui_min/pic/png_new_sms_bg.png
new file mode 100755
index 0000000..65d5c67
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_new_sms_bg.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_resend1.png b/ap/app/zte_webui_min/pic/png_resend1.png
new file mode 100755
index 0000000..98ffbbe
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_resend1.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_resend_hover.png b/ap/app/zte_webui_min/pic/png_resend_hover.png
new file mode 100755
index 0000000..e448901
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_resend_hover.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/png_time.png b/ap/app/zte_webui_min/pic/png_time.png
new file mode 100755
index 0000000..d449f35
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/png_time.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/power_charging.gif b/ap/app/zte_webui_min/pic/power_charging.gif
new file mode 100755
index 0000000..a76a28e
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/power_charging.gif
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/power_full.png b/ap/app/zte_webui_min/pic/power_full.png
new file mode 100755
index 0000000..5101e5b
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/power_full.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/power_one.png b/ap/app/zte_webui_min/pic/power_one.png
new file mode 100755
index 0000000..ec2cca7
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/power_one.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/power_out.png b/ap/app/zte_webui_min/pic/power_out.png
new file mode 100755
index 0000000..5868c88
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/power_out.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/power_three.png b/ap/app/zte_webui_min/pic/power_three.png
new file mode 100755
index 0000000..ce92dab
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/power_three.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/power_two.png b/ap/app/zte_webui_min/pic/power_two.png
new file mode 100755
index 0000000..6e98f70
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/power_two.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_alert.png b/ap/app/zte_webui_min/pic/res_alert.png
new file mode 100755
index 0000000..85da1d6
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_alert.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_blacktrans.png b/ap/app/zte_webui_min/pic/res_blacktrans.png
new file mode 100755
index 0000000..1b3ef9b
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_blacktrans.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_cancel.png b/ap/app/zte_webui_min/pic/res_cancel.png
new file mode 100755
index 0000000..b0a0b69
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_cancel.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_card.png b/ap/app/zte_webui_min/pic/res_card.png
new file mode 100755
index 0000000..b885970
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_card.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_confirm.png b/ap/app/zte_webui_min/pic/res_confirm.png
new file mode 100755
index 0000000..6e6a386
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_confirm.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_delete.png b/ap/app/zte_webui_min/pic/res_delete.png
new file mode 100755
index 0000000..e41fd8c
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_delete.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_device.png b/ap/app/zte_webui_min/pic/res_device.png
new file mode 100755
index 0000000..988965d
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_device.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_edit.png b/ap/app/zte_webui_min/pic/res_edit.png
new file mode 100755
index 0000000..1681b53
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_edit.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_failure.png b/ap/app/zte_webui_min/pic/res_failure.png
new file mode 100755
index 0000000..8091236
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_failure.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_help.png b/ap/app/zte_webui_min/pic/res_help.png
new file mode 100755
index 0000000..68bb586
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_help.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_info.png b/ap/app/zte_webui_min/pic/res_info.png
new file mode 100755
index 0000000..bb12585
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_info.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_list.png b/ap/app/zte_webui_min/pic/res_list.png
new file mode 100755
index 0000000..665201a
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_list.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_loading.gif b/ap/app/zte_webui_min/pic/res_loading.gif
new file mode 100755
index 0000000..178ac58
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_loading.gif
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_login-bg.png b/ap/app/zte_webui_min/pic/res_login-bg.png
new file mode 100755
index 0000000..14f8089
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_login-bg.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_logo_web.png b/ap/app/zte_webui_min/pic/res_logo_web.png
new file mode 100755
index 0000000..27802f8
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_logo_web.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_point.png b/ap/app/zte_webui_min/pic/res_point.png
new file mode 100755
index 0000000..b5c86b0
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_point.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_roaming.png b/ap/app/zte_webui_min/pic/res_roaming.png
new file mode 100755
index 0000000..64f9849
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_roaming.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_save.png b/ap/app/zte_webui_min/pic/res_save.png
new file mode 100755
index 0000000..14557fb
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_save.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_search.png b/ap/app/zte_webui_min/pic/res_search.png
new file mode 100755
index 0000000..3d151b7
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_search.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_signal.png b/ap/app/zte_webui_min/pic/res_signal.png
new file mode 100755
index 0000000..9de0f99
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_signal.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_succ.png b/ap/app/zte_webui_min/pic/res_succ.png
new file mode 100755
index 0000000..c7b4a8d
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_succ.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/res_update.gif b/ap/app/zte_webui_min/pic/res_update.gif
new file mode 100755
index 0000000..96a05d9
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/res_update.gif
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/select-sprite.png b/ap/app/zte_webui_min/pic/select-sprite.png
new file mode 100755
index 0000000..3611ae4
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/select-sprite.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/select-sprite@2x.png b/ap/app/zte_webui_min/pic/select-sprite@2x.png
new file mode 100755
index 0000000..ffe4d7d
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/select-sprite@2x.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/simcard.png b/ap/app/zte_webui_min/pic/simcard.png
new file mode 100755
index 0000000..5c43ec0
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/simcard.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/simcard_detected.png b/ap/app/zte_webui_min/pic/simcard_detected.png
new file mode 100755
index 0000000..f767cd8
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/simcard_detected.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/simcard_undetected.png b/ap/app/zte_webui_min/pic/simcard_undetected.png
new file mode 100755
index 0000000..2fa4c5b
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/simcard_undetected.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/tickbox.png b/ap/app/zte_webui_min/pic/tickbox.png
new file mode 100755
index 0000000..7c77973
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/tickbox.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/tickbox_disable.png b/ap/app/zte_webui_min/pic/tickbox_disable.png
new file mode 100755
index 0000000..8fdddaa
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/tickbox_disable.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/tickbox_in.png b/ap/app/zte_webui_min/pic/tickbox_in.png
new file mode 100755
index 0000000..468b5fd
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/tickbox_in.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/tickbox_in_disable.png b/ap/app/zte_webui_min/pic/tickbox_in_disable.png
new file mode 100755
index 0000000..d192d8c
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/tickbox_in_disable.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan.png b/ap/app/zte_webui_min/pic/wlan.png
new file mode 100755
index 0000000..41741c3
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_connected.png b/ap/app/zte_webui_min/pic/wlan_connected.png
new file mode 100755
index 0000000..29d6d8e
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_connected.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_lock_connected.png b/ap/app/zte_webui_min/pic/wlan_lock_connected.png
new file mode 100755
index 0000000..6462f80
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_lock_connected.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_lock_signal_0.png b/ap/app/zte_webui_min/pic/wlan_lock_signal_0.png
new file mode 100755
index 0000000..6a9e6ce
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_lock_signal_0.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_lock_signal_1.png b/ap/app/zte_webui_min/pic/wlan_lock_signal_1.png
new file mode 100755
index 0000000..7e0f216
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_lock_signal_1.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_lock_signal_2.png b/ap/app/zte_webui_min/pic/wlan_lock_signal_2.png
new file mode 100755
index 0000000..42a0c42
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_lock_signal_2.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_lock_signal_3.png b/ap/app/zte_webui_min/pic/wlan_lock_signal_3.png
new file mode 100755
index 0000000..aaf110c
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_lock_signal_3.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_lock_signal_4.png b/ap/app/zte_webui_min/pic/wlan_lock_signal_4.png
new file mode 100755
index 0000000..a99fa95
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_lock_signal_4.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_off.png b/ap/app/zte_webui_min/pic/wlan_off.png
new file mode 100755
index 0000000..2fd353b
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_off.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_signal_0.png b/ap/app/zte_webui_min/pic/wlan_signal_0.png
new file mode 100755
index 0000000..243d65b
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_signal_0.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_signal_1.png b/ap/app/zte_webui_min/pic/wlan_signal_1.png
new file mode 100755
index 0000000..559373f
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_signal_1.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_signal_2.png b/ap/app/zte_webui_min/pic/wlan_signal_2.png
new file mode 100755
index 0000000..4ed5495
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_signal_2.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_signal_3.png b/ap/app/zte_webui_min/pic/wlan_signal_3.png
new file mode 100755
index 0000000..42e22c8
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_signal_3.png
Binary files differ
diff --git a/ap/app/zte_webui_min/pic/wlan_signal_4.png b/ap/app/zte_webui_min/pic/wlan_signal_4.png
new file mode 100755
index 0000000..e6dd043
--- /dev/null
+++ b/ap/app/zte_webui_min/pic/wlan_signal_4.png
Binary files differ
diff --git a/ap/app/zte_webui_min/subpg/adm_lan.html b/ap/app/zte_webui_min/subpg/adm_lan.html
new file mode 100755
index 0000000..96272db
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/adm_lan.html
@@ -0,0 +1,106 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='advanced_settings'></h1>

+            </div>

+        </div>

+    </div>

+<div class="row">

+<div class="col-xs-2">

+    <div class="nav_right">

+		<ul>

+			<li><a href="#wlan_sleep" data-trans="sleep_mode"></a></li>

+			<li class="active"><a href="#route_set" data-trans="router_setting"></a></li>

+			<li><a href="#filter_main" data-trans="firewall"></a></li>

+			<li data-bind="visible:hasUpdateCheck"><a href="#fota" data-trans="update_settings"></a></li>

+			<li data-bind="visible:hasUssd"><a href="#usat" data-trans="USSD"></a></li>

+			<li data-bind="visible:hasDdns"><a href="#dynamic_dns" data-trans="DDNS"></a></li>

+			<li><a href="#more" data-trans="others"></a></li>

+		</ul>

+	</div>

+</div>

+

+<div class="col-xs-10">

+<form id="frmLan" role="form">

+    <h3 class="form-title" data-trans="router_setting"></h3>

+    <div class="form-body margin-top-20">

+        <div class="content">

+            <div class="row form-group">

+                <label data-trans="ip_address" for="txtIpAddress" class="col-xs-4 side-right"></label>

+                <div class="col-xs-3">

+                    <input id="txtIpAddress" name="txtIpAddress" data-bind="value: ipAddress" maxlength="15" type="text" class="required form-control"/>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label data-trans="subnet_mask" for="txtSubnetMask" class="col-xs-4 side-right"></label>

+                <div class="col-xs-3">

+                <input id="txtSubnetMask" name="txtSubnetMask" data-bind="value: subnetMask" maxlength="15"  type="text" class="required form-control"/>

+                </div>

+            </div>

+            <div class="row form-group" data-bind="visible: showMacAddress() && hasWifi()">

+                <label data-trans="mac_address" class="col-xs-4 side-right"></label>

+                <div class="col-xs-3">

+                <label id="txtMacAddress" data-bind="text: macAddress" class="label-content"></label>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label class="col-xs-4 side-right" data-trans="dhcp_server"></label>

+                <div class="col-xs-8">

+                    <div class="row">

+                        <div class="col-xs-3">

+                            <input id="dhcpEnable" name="dhcpServer" data-bind="checked: dhcpServer,click: dhcpServerHandler" type="radio" value="1"/>

+                            <label data-trans="enable" for="dhcpEnable"></label>

+                        </div>

+                        <div class="col-xs-3">

+                            <input id="dhcpDisable" name="dhcpServer" data-bind="checked: dhcpServer,click: dhcpServerHandler" type="radio" value="0"/>

+                            <label data-trans="disable" for="dhcpDisable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div data-bind='visible: dhcpServer() == "1"'>

+                <div class="row form-group">

+                    <label data-trans='dhcp_ip_pool' for="txtDhcpIpPoolStart" class="col-xs-4 side-right"></label>

+                    <div class="col-xs-8 form-inline">

+                        <input id='txtDhcpIpPoolStart' name="txtDhcpIpPoolStart" data-bind="value: dhcpStart" maxlength="15" type="text" class="required rangeInput form-control"/>

+                        -

+                        <input id='txtDhcpIpPoolEnd' name="txtDhcpIpPoolEnd" data-bind="value: dhcpEnd" maxlength="15" type="text" class="required rangeInput form-control"/>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtDhcpLease" data-trans="dhcp_lease" class="col-xs-4 side-right"></label>

+                    <div class="col-xs-3">

+                        <div class="input-group">

+                            <input id="txtDhcpLease" name="txtDhcpLease" data-bind="value: dhcpLease" maxlength="5"  type="text" class="required form-control"/>

+                            <div data-trans="hours" id="leaseLabel" class="input-group-addon"></div>

+

+                        </div>

+                        <div id="errorHolder"></div>

+                    </div>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input type="submit" formmethod="post" data-trans="apply" class="btn btn-primary"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="lan_note_ip_address"></li>

+                <li data-trans="lan_note_subnet_mask"></li>

+                <li data-trans="lan_note_dhcp_server_enable"></li>

+                <li data-trans="lan_note_dhcp_server_disable"></li>

+                <li data-trans="lan_note_dhcp_ip_pool"></li>

+                <li data-trans="lan_note_dhcp_lease_time"></li>

+            </ul></div>

+    </div>

+</form>

+    </div>

+    </div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/adm_management.html b/ap/app/zte_webui_min/subpg/adm_management.html
new file mode 100755
index 0000000..289786e
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/adm_management.html
@@ -0,0 +1,60 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='password_management'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+        <div class="col-xs-11">

+

+

+<form id="frmPassword" role="form">

+    <div class="form-body">

+        <div class="content">

+            <div class="row form-group">

+                <label data-trans="current_password" for="txtCurrent" class="col-xs-4 side-right"></label>

+                <div class="col-xs-4">

+                    <input id="txtCurrent" name="txtCurrent" data-bind="value: currentValue" maxlength="32" minlength="4" type="password" class="required form-control"/>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label data-trans="new_password" for="txtNew" class="col-xs-4 side-right"></label>

+                <div class="col-xs-4">

+                    <input id="txtNew" name="txtNew" data-bind="value: newValue" maxlength="32" minlength="4"  type="password" class="required form-control"/>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label class="col-xs-4 side-right" data-trans="confirm_password" for="txtConfirm"></label>

+                <div class="col-xs-4">

+                <input id="txtConfirm" name="txtConfirm" data-bind="value: confirmValue" maxlength="32" minlength="4" type="password" class="required form-control"/>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input id="btnPwdApply" type="submit" formmethod="post" class="btn btn-primary" data-trans="apply"/>

+        </div>

+        <div class="form-information">

+            <p class="bg-info" data-trans="pwd_note"></p>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="password_note_info"></li>

+                <li data-trans="password_note_valid"></li>

+                <li data-trans="password_note_input"></li>

+            </ul>

+        </div>

+    </div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/adm_others.html b/ap/app/zte_webui_min/subpg/adm_others.html
new file mode 100755
index 0000000..5ac83a0
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/adm_others.html
@@ -0,0 +1,180 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='advanced_settings'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		    <div class="nav_right">

+		    <ul>

+				<li><a href="#wlan_sleep" data-trans="sleep_mode"></a></li>

+				<li><a href="#route_set" data-trans="router_setting"></a></li>

+				<li><a href="#filter_main" data-trans="firewall"></a></li>

+				<li data-bind="visible:hasUpdateCheck"><a href="#fota" data-trans="update_settings"></a></li>

+				<li data-bind="visible:hasUssd"><a href="#usat" data-trans="USSD"></a></li>

+				<li data-bind="visible:hasDdns"><a href="#dynamic_dns" data-trans="DDNS"></a></li>      

+				<li class="active"><a href="#more" data-trans="others"></a></li>

+			</ul>

+			</div>

+		</div>

+        <div class="col-xs-10">

+        <form id="frmRestoreReset">

+            <div class="form-body">

+                <h3 data-trans="others_restart_reset" class="form-title"></h3>

+				<div class="row form-group">

+                    <div data-trans="others_note_info" class="col-xs-12"></div>

+                </div>

+                <div class="row form-group">				    

+                    <div class="col-xs-12 align-right">

+                        <input data-trans="restart_button" data-bind="click: restart" type="button" class="btn btn-primary margin-right-20"/>

+                        <input data-trans="restore_button" data-bind="visible: currentUserInChildGroup() == false, click: restore" type="button" class="btn btn-primary margin-right-20"/>

+                    </div>

+                </div>

+            </div>

+        </form>

+

+        <form id="frmtrunOffDevice" data-bind="visible: turnOffSupport">

+            <div class="form-body">

+                <h3 data-trans="others_turn_off" class="form-title"></h3>

+                <div class="row form-group">

+                    <div class="col-xs-12 align-right">

+                        <input data-bind="click: turnoff" data-trans="turnoff_button" type="button" class="btn btn-primary margin-right-20"/>

+                    </div>

+                </div>

+            </div>

+        </form>

+		

+        <form data-bind="visible: fastbootSupport">

+            <div class="form-body">

+                <h3 class="form-title" data-trans="fastboot_setting"></h3>

+                <div class="row form-group">

+                    <label data-trans="fastboot_setting" class="col-xs-4 side-right"></label>

+                    <div class="col-xs-8">

+                        <div class="row">

+                            <div class="col-xs-3">

+                                <input id="fastEnable" name="fastboot" data-bind="checked: fastbootSetting, enable: fastbootEnableFlag" type="radio" value="1"/>

+                                <label data-trans="enable" for="fastEnable"></label>

+                            </div>

+                            <div class="col-xs-3">

+                                <input id="fastDisable" name="fastboot" data-bind="checked: fastbootSetting, enable: fastbootEnableFlag" type="radio" value="0"/>

+                                <label data-trans="disable" for="fastDisable"></label>

+                            </div>

+                        </div>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <div class="col-xs-12" data-trans="fastboot_note"></div>

+                </div>

+                <div class="row form-group">

+                    <div class="col-xs-12 align-right">

+                        <input data-bind="click: saveFastBoot, enable: fastbootEnableFlag" data-trans="apply" type="button" class="btn btn-primary margin-right-20"/>

+                    </div>

+                </div>

+            </div>

+        </form>

+

+		

+		<form id="sntpForm" data-bind="visible: SNTPSupport">

+			<div class="form-body">

+				<h3 class="form-title">SNTP</h3>

+				<div class="content">

+					<div class="row form-group">

+						<label class="col-xs-4 side-right" data-trans='local_current_time'></label>

+						<div class="col-xs-8">

+							<span class="span3" data-bind="text: localTime"></span>

+							<span>&nbsp;</span>

+							<span id="weekday" data-bind="text: day"></span>

+						</div>

+					</div>

+					<div class="row form-group">

+						<label class="col-xs-4 side-right" data-trans='time_set_mode' for="sntpSetTimeMode"></label>

+						<div class="col-xs-4">

+							<select id="sntpSetTimeMode" class="form-control" data-transid="time_set_time" data-bind="options: timeSetModes, value: currentMode, optionsText: transOption('time_set_time'), optionsValue: 'value', event:{change: changeSetTimeMode}"></select>

+						</div>					

+					</div>

+					<div id="manualSetTime" data-bind="visible: isManualSetTime">

+						<div class="row form-group">

+							<label class="col-xs-4 side-right" data-trans='time_set_time_manual'></label>							

+						

+							<div class="col-xs-8">

+									<select id="manualYear" data-bind="options: years, value: currentYear, optionsText: 'text', optionsValue: 'value', event:{change: initDateList}" style="display:inline-block; width:auto; padding-right:5px; padding-left:5px"  class="form-control"></select> 

+								    <label data-trans="year" for="manualYear" style="display:inline-block; width:auto; padding-right:0"></label>

+								

+								    <select id="manualMonth" data-bind="options: months, value: currentMonth, optionsText: 'text', optionsValue: 'value', event: {change: initDateList}" style="display:inline-block; width:auto; padding-right:5px; padding-left:5px" class="form-control"></select> 

+								    <label data-trans="month" for="manualMonth" style="display:inline-block; width:auto; padding-right:0"></label>

+								

+									<select id="manualDate" data-bind="options: dates, value: currentDate, optionsText: 'text', optionsValue: 'value'" style="display:inline-block; width:auto; padding-right:5px; padding-left:5px" class="form-control"></select> 

+								    <label data-trans="date" for="manualDate" style="display:inline-block; width:auto; padding-right:0"></label>

+								

+									<select id="manualHour" data-bind="options: hours, value: currentHour, optionsText: 'text', optionsValue: 'value'" style="display:inline-block; width:auto; padding-right:5px; padding-left:5px" class="form-control"></select> 

+								    <label data-trans="hour" for="manualHour" style="display:inline-block; width:auto; padding-right:0"></label>

+								

+									<select id="manualMinute" data-bind="options: minutes, value: currentMinute, optionsText: 'text', optionsValue: 'value'" style="display:inline-block; width:auto; padding-right:5px; padding-left:5px" class="form-control"></select> 

+									<label data-trans="minute" for="manualMinute" style="display:inline-block; width:auto; padding-right:0"></label>

+							</div>

+                        </div>						

+					</div>

+					<div id="autoSntpTime" data-bind="visible: isAutoSntpTime">

+						<div id="sntp_server0" class="row form-group">

+							<label data-trans='stnp_server1' for="sntp_server1_select" class="col-xs-4 side-right"></label>

+							<div class="col-xs-4">

+								<select id="sntp_server1_select" data-bind="options: serverList, value: currentServer0, optionsText: 'text', optionsValue: 'value', event: {change: changeServerSelect}" class="form-control"></select>

+							</div>

+							<div class="col-xs-4">

+							    <input id="sntp_other_server0" name="sntp_other_server0" data-bind="value:customServer0, visible:isOther0" type="text" class="required form-control"/>

+							</div>

+						</div>

+						<div id="sntp_server1" class="row form-group">

+							<label class="col-xs-4 side-right" data-trans='stnp_server2' for="stnp_server2_select"></label>

+							<div class="col-xs-4">

+								<select id="stnp_server2_select" data-bind="options: serverList, value: currentServer1, optionsText: 'text', optionsValue: 'value', event: {change: changeServerSelect}" class="form-control"></select>

+	                        </div>

+							<div class="col-xs-4">						

+    							<input id="sntp_other_server1" name="sntp_other_server1"  data-bind="value:customServer1, visible:isOther1" type="text" class="required form-control"/>

+							</div>

+						</div>

+						<div id="sntp_server2" class="row form-group">

+							<label data-trans='stnp_server3' for="stnp_server3_select" class="col-xs-4 side-right"></label>

+							<div class="col-xs-4">

+								<select id="stnp_server3_select" class="form-control" data-bind="options: serverList, value: currentServer2, optionsText: 'text', optionsValue: 'value', event: {change: changeServerSelect}"></select>

+							</div>

+							<div class="col-xs-4">

+								<input id="sntp_other_server2" name="sntp_other_server2" data-bind="value:customServer2, visible:isOther2" type="text" class="required form-control"/>

+							</div>

+						</div>

+						<div class="row form-group">

+							<label data-trans='time_zone' for="time_zone_select" class="col-xs-4 side-right"></label>

+							<div class="col-xs-4">

+								<select id="time_zone_select" data-bind="options: timeZones, value: currentTimeZone, optionsText: transOption('time_zone'), optionsValue: 'value'" data-transid="time_zone" class="form-control"></select>

+							</div>

+						</div>

+	

+					</div>		

+				</div>

+				<div class="form-buttons">

+					<input data-bind="" data-trans="apply" type="submit" formmethod="post" class="btn btn-primary margin-right-20"/>

+				</div>

+			</div>

+		</form>

+		

+        <div class="form-body">

+            <div class="content margin-top-20 line-height-30">

+                <div class="row">

+                    <a href="#pin_mode">

+                        <div data-trans="pin_management" class="col-xs-3 arrow-right">

+                        </div>

+                    </a>

+                </div>

+            </div>

+        </div>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/adm_pin.html b/ap/app/zte_webui_min/subpg/adm_pin.html
new file mode 100755
index 0000000..090051f
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/adm_pin.html
@@ -0,0 +1,130 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a data-bind="attr: {href: isDataCard? '#main' : '#more'}">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-bind="attr: {'data-trans': isDataCard? 'advanced_settings' : 'pin_management'}"></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+        <div class="col-xs-11">

+

+        <ul class="nav nav-tabs nav-justified" role="tablist" data-bind="visible: isDataCard">

+            <li><a href="#demilitarized_zone" data-trans="dmz_setting"></a></li>

+            <li class="active"><a href="#pin_mode" data-trans="pin_management"></a></li>

+            <li><a href="#fota" data-trans="update_settings"></a></li>

+        </ul>

+

+<form id="frmPin" data-bind="css: {'margin-top-20': isDataCard}">

+    <div class="form-body">

+        <div data-bind="visible:pageState()!=4">

+            <div class="content">

+                <div id="showPinWhenPinStaueNEQ3" data-bind="visible:pageState()!=3">

+                    <div class="row form-group">

+                        <label data-trans="pin_status" class="col-xs-4 side-right"></label>

+                        <div class="col-xs-8">

+                            <div class="row">

+                                <div class="col-xs-4">

+                                    <input id="pinEnable" name="pinStatus"

+                                           data-bind="checked: pinStatus,disable:pageState()==2" type="radio" value="1"/>

+                                    <label data-trans="enable" for="pinEnable" class="marginright10"></label>

+                                </div>

+                                <div class="col-xs-8">

+                                    <input id="btnModifyPin" type="button" data-trans="modify_pin" data-bind="visible:pageState()<=1, enable:originPinStatus()==1,click: displayModifyPinPage,css:{disabled:originPinStatus()==0}" class="btn btn-primary"/>

+                                </div>

+                            </div>

+                       </div>

+                    </div>

+                    <div class="row form-group">

+                        <label class="col-xs-4 side-right" ></label>

+                        <div class="col-xs-8">

+                            <input id="pinDisable" name="pinStatus" data-bind="checked: pinStatus,disable:pageState()==2" type="radio" value="0"/>

+                            <label data-trans="disable" for="pinDisable"></label>

+

+                        </div>

+                    </div>

+                    <div class="row form-group">

+                        <label data-trans="current_pin" for="txtPin" class="col-xs-4 side-right"></label>

+                        <div class="col-xs-3">

+                            <input id="txtPin" name="txtPin" data-bind="value: currentPin,disable:pageState()==0,valueUpdate: 'keypress',css:{disabled:pageState()==0}" maxlength="8" type="password" class="required form-control"/>

+                        </div>

+                    </div>

+                </div>

+                <div id="showPukWhenPinStaueEQ3" data-bind="visible:pageState()==3">

+                    <div><p data-trans="enter_puk" class="prompt"></p></div>

+                    <div class="row form-group">

+                        <label data-trans="puk" for="txtPuk" class="col-xs-4 side-right"></label>

+                        <div class="col-xs-3">

+                            <input id="txtPuk" name="txtPuk" data-bind="value: puk, valueUpdate: 'keypress'" maxlength="8" type="password" class="required form-control"/>

+                        </div>

+                    </div>

+                </div>

+                <div data-bind="visible:pageState()==2 || pageState()==3">

+                    <div class="row form-group">

+                        <label data-trans="new_pin" for="txtNewPin" class="col-xs-4 side-right"></label>

+                        <div class="col-xs-3">

+                            <input id="txtNewPin" name="txtNewPin" data-bind="value: newPin" maxlength="8" type="password" class="required form-control"/>

+                        </div>

+                    </div>

+                    <div class="row form-group">

+                        <label data-trans="confirm_pin" for="txtConfirmPin" class="col-xs-4 side-right"></label>

+                        <div class="col-xs-3">

+                            <input id="txtConfirmPin" name="txtConfirmPin" data-bind="value: confirmPin" type="password"  class="required form-control" maxlength="8"/>

+                        </div>

+                    </div>

+                </div>

+                <div data-bind="visible:pageState()<3">

+                    <div id="pinLeftMsg" data-bind="visible:pinNumber()!=1" class="row form-group">

+                        <label class="col-xs-4 side-right"></label>

+                        <div class="col-xs-8">

+                            <p data-bind="visible:pinNumber()>1" class="important-prompt">

+                                <span data-trans="attempts_left"></span>

+                                <span data-bind='text:pinNumber'></span>

+                            </p>

+                        </div>

+                    </div>

+                    <div id="pinLastMsg" data-bind="visible:pinNumber()==1">

+                        <p class="important-prompt" data-trans="last_enter_pin"></p>

+                    </div>

+                </div>

+                <div data-bind="visible:pageState()==3">

+                    <div id="pukLeftMsg" data-bind="visible:pukNumber()!=1" class="row form-group">

+                        <label class="col-xs-4 side-right"></label>

+                        <div class="col-xs-8">

+                            <p class="important-prompt" data-bind="visible:pukNumber()>1">

+                                <span data-trans="attempts_left"></span>

+                                <span data-bind='text:pukNumber'></span>

+                            </p>

+                        </div>

+                    </div>

+                    <div id="pukLastMsg" data-bind="visible:pukNumber()==1">

+                        <p class="important-prompt" data-trans="last_enter_puk"></p>

+                    </div>

+                </div>

+            </div>

+            <div class="form-buttons">

+                <input id="btnPinApply" data-bind="disable:pageState()==0,css:{disabled:pageState()==0}" data-trans="apply" type="submit" formmethod="post" class="btn btn-primary"/>

+                <!--input type="button" data-bind="click: cancel,visible:pageState()==2" class="btn " data-trans="cancel"/-->

+            </div>

+        </div>

+        <div id="puk_locked" data-bind="visible:pageState()==4" data-trans="puk_locked" class="important-prompt"></div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="pin_note_info"></li>

+                <li data-trans="pin_note_operator"></li>

+                <li data-trans="pin_note_modify"></li>

+            </ul>

+        </div>

+    </div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/adm_quick_set.html b/ap/app/zte_webui_min/subpg/adm_quick_set.html
new file mode 100755
index 0000000..dd5fbfb
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/adm_quick_set.html
@@ -0,0 +1,307 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='quick_setting'></h1>

+				<p data-trans='step1_exp1'></p>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+        <div class="col-xs-11">

+

+<form id='quickSettingForm'>

+    <div class="form-body">

+        <div class="content">

+            <div class="row form-group side-right form-buttons">

+                <input id="btnBack" data-bind="visible:currentStep()>1,click:previous" data-trans="prev_step" type="button" class="btn btn-primary">

+                <input id="btnNext" data-bind="visible:currentStep()<5,disable: adBand()=='b' && adMode() == '2' && (selectedSecurityMode() == 'SHARED' || (selectedSecurityMode() == 'OPEN' && encryptType() == 'WEP'))" data-trans="next_step" type="submit" formmethod="post" class="btn btn-primary">

+                <input id="btnSave" data-bind="visible:currentStep()==5" data-trans="apply" type="submit" formmethod="post" class="btn btn-primary">

+            </div>

+            <div data-bind="visible:currentStep()==1" style="display: none" id="step1">

+                <h3 data-trans="apn_settings" class="form-title"></h3>

+                <div class="content">

+					<div class="row form-group">

+						<label data-trans="apn_settings" class="col-xs-3 side-right"></label>

+						<div class="col-xs-6">

+							<div class="row">

+								<div class="col-xs-4">

+									<input id="radAuto" name="apnMode" data-bind="checked: apnMode,disable: apnModeDisabled()" type="radio" value="auto"/>

+									<label data-trans="apn_auto_apn" for="radAuto"></label>

+								</div>

+								<div class="col-xs-4">						

+									<input id="radManual" name="apnMode" data-bind="checked: apnMode,disable: apnModeDisabled()" type="radio" value="manual"/>

+									<label data-trans="apn_manual_apn" for="radManual"></label>

+								</div>

+							</div>

+						</div>

+					</div>

+					<div id="apnSetting" data-bind="visible:apnMode()=='manual'">

+						<div class="row form-group">

+							<label data-trans="apn_profile_name" for="profile_name" class="col-xs-3 side-right"></label>

+							<div class="col-xs-6">

+								<input id="profile_name" name="txtProfileName" data-bind="value:profileName" disabled="disabled" maxlength="30" type="text" class=" form-control"/>

+							 </div>

+						</div>

+						<div data-bind="visible:showIPv4" class="row form-group">

+							<label for="txtAPN" data-bind="attr:{'data-trans':transAPN}" class="col-xs-3 side-right"></label>

+							<div class="col-xs-6">

+								<input id="txtAPN" name="txtAPN" data-bind="value:apn,disable: apnDisabled()" maxlength="64" type="text" class="form-control required"/>

+							</div>

+						</div>

+						<div data-bind="visible:showIPv6" class="row form-group">

+							<label for="txtIPv6APN" data-bind="attr:{'data-trans':transAPNIPv6}" class="col-xs-3 side-right"></label>

+							<div class="col-xs-6">

+								<input id="txtIPv6APN" name="txtIPv6APN" data-bind="value:ipv6_apn,disable: apnDisabled()" maxlength="64" type="text" class="form-control required"/>

+							</div>

+						</div>

+					</div>

+				</div>                

+				<div class="form-note">

+					<div class="notes-title">&nbsp;</div>

+					<ul class="notes-content">

+						<li data-trans="step2_auto_apn_explain"></li>

+						<li data-trans="step2_profile_name_explain"></li>

+					</ul>

+				</div>

+            </div>

+            <div id="step2" data-bind="visible:currentStep()==2" style="display: none">

+                <h3 data-trans="ppp_authentication" class="form-title"></h3>

+                <div class="content">

+					<div data-bind="visible:showIPv4" class="row form-group">

+						<label data-bind="attr:{'data-trans':transAuthMode}" for="selAuthMode" class="col-xs-3 side-right"></label>

+						<div class="col-xs-6">

+							<select id="selAuthMode" name="selAuthMode" 

+								data-bind="options: authModes, disable: apnDisabled(), value: selectedAuthMode, optionsText: 'text', optionsValue: 'value'" class="form-control"></select>

+						</div>

+					</div>

+					<div data-bind="visible:showIPv4" class="row form-group">

+						<label data-bind="attr:{'data-trans':transUserName}" for="txtUserName" class="col-xs-3 side-right"></label>

+						<div class="col-xs-6">

+							<input id="txtUserName" name="txtUserName"

+								   data-bind="value:username,disable: apnDisabled()" maxlength="64" type="text" class=" form-control"/>

+						</div>

+					</div>

+					<div data-bind="visible:showIPv4" class="row form-group">

+						<label data-bind="attr:{'data-trans':transPassword}" for="txtSecretCode" class="col-xs-3 side-right"></label>

+						<div class="col-xs-6">

+							<input id="txtSecretCode" name="txtSecretCode"

+							   data-bind="value:password,disable: apnDisabled()" maxlength="64" type="password" class=" form-control"/>

+						</div>

+					</div>

+					<div data-bind="visible:showIPv6" class="row form-group">

+						<label data-bind="attr:{'data-trans':transAuthModeIPv6}" for="selIPv6AuthMode" class="col-xs-3 side-right"></label>

+						<div class="col-xs-6">

+							<select id="selIPv6AuthMode" name="selIPv6AuthMode"

+									data-bind="options: authModes, disable: apnDisabled(), value: ipv6_selectedAuthMode, optionsText: 'text', optionsValue: 'value'"  class="form-control"></select>

+						</div>

+					</div>

+					<div data-bind="visible:showIPv6" class="row form-group">

+						<label class="col-xs-3 side-right" for="txtIPv6UserName" data-bind="attr:{'data-trans':transUserNameIPv6}"></label>

+						<div class="col-xs-6">

+							<input id="txtIPv6UserName" name="txtIPv6UserName"

+								   data-bind="value:ipv6_username,disable: apnDisabled()" maxlength="64" type="text" class=" form-control"/>

+						</div>

+					</div>

+					<div data-bind="visible:showIPv6" class="row form-group">

+						<label data-bind="attr:{'data-trans':transPasswordIPv6}" for="txtIPv6SecretCode" class="col-xs-3 side-right"></label>

+						<div class="col-xs-6">

+							<input id="txtIPv6SecretCode" name="txtIPv6SecretCode" data-bind="value:ipv6_password,disable: apnDisabled()" maxlength="64"

+								   type="password" class="form-control"/>

+						</div>

+					</div>

+                </div>

+                <div class="form-note">

+                    <div class="notes-title">&nbsp;</div>

+                    <ul class="notes-content">

+                        <li data-trans="step3_authentication_apn_explain1"></li>

+                        <li data-trans="step3_authentication_apn_explain2"></li>

+                        <li data-trans="step3_authentication_apn_explain3"></li>

+                    </ul>

+                </div>

+

+            </div>

+            <div id="step3" data-bind="visible:currentStep()==3" style="display: none">

+                <h3 class="form-title" data-trans="ssid_title"></h3>

+                <div class="content">

+                <div class="row form-group">

+                    <label data-trans="ssid_name" for="txtSSID" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="txtSSID" name="txtSSID" data-bind="disable:wifiDisabled,value:ssid" maxlength="32" type="text" class="form-control required"/>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label class="col-xs-3 side-right" data-trans="ssid_broadcast"></label>

+                    <div class="col-xs-6">

+                       <input id="radBroadcastEnable" data-bind="disable:wifiDisabled,checked: broadcast" name="radBroadcast"

+                           type="radio" value="0"/>

+                        <label for="radBroadcastEnable" data-trans="enable"></label>

+                        <input id="radBroadcastDisable" name="radBroadcast"

+                               data-bind="disable:wifiDisabled,checked: broadcast" type="radio" value="1"/>

+                        <label data-trans="disable" for="radBroadcastDisable"></label>

+                    </div>

+                </div>

+                </div>

+                <div class="form-note">

+                    <div class="notes-title">&nbsp;</div>

+                    <ul class="notes-content">

+                        <li data-trans="step4_ssid_explain"></li>

+                        <li data-trans="wifi_basic_note_network_name_input"></li>

+                        <li data-trans="step4_ssid_broadcast_explain1"></li>

+                    </ul>

+                </div>

+

+            </div>

+            <div data-bind="visible:currentStep()==4" style="display: none" id="step4">

+                <h3 class="form-title" data-trans="security_mode"></h3>

+                <div class="content">

+                <div class="row form-group">

+                    <label for="selSecurityMode" data-trans="security_mode" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <select id="selSecurityMode" name="selSecurityMode" data-transid='security_mode'

+                                data-bind="disable:wifiDisabled,options: securityModes, value: selectedSecurityMode, optionsText: transOption('security_mode'), optionsValue: 'value'"  class="form-control"></select>

+                    </div>

+                </div>

+				

+				<div data-bind='visible: selectedSecurityMode() == "OPEN" && hasWifiWep' class="row form-group">

+					<label for='selEncryptType' data-trans='ap_station_encrypt_type' class="col-xs-3 side-right"></label>

+					<div class="col-xs-6">

+						<select id="selEncryptType" data-bind="value: encryptType,optionsValue: 'value'" class="form-control">

+							<option data-trans="ap_station_encrypt_type_none" value="NONE"></option>

+							<option data-trans="ap_station_encrypt_type_wep" value="WEP"></option>

+						</select>

+					</div>

+				</div>

+				<div data-bind='visible:  (selectedSecurityMode() == "OPEN" && encryptType() == "WEP" && hasWifiWep) || (selectedSecurityMode() == "SHARED" && hasWifiWep)' class="row form-group">

+					<label data-trans='ap_station_wep_default_key' for='selWepKeyType' class="col-xs-3 side-right"></label>

+					<div class="col-xs-6">

+						<select id="selWepKeyType" data-bind="value: keyID,optionsValue: 'value', event:{ change: profileChangeHandler}" class="form-control">

+							<option data-trans="ap_station_wep_key_0" value="0"></option>

+							<option data-trans="ap_station_wep_key_1" value="1"></option>

+							<option data-trans="ap_station_wep_key_2" value="2"></option>

+							<option data-trans="ap_station_wep_key_3" value="3"></option>

+						</select>

+					</div>

+				</div>

+				<div data-bind='visible: (selectedSecurityMode() == "OPEN" && encryptType() == "WEP" && hasWifiWep) || (selectedSecurityMode() == "SHARED" && hasWifiWep)' class="row form-group">

+					<label data-trans='ap_station_wep_key' for='pwdWepKey' class="col-xs-3 side-right"></label>

+					<div class="col-xs-6">

+						<input id='pwdWepKey' name="pwdWepKey" type="password"

+											   data-bind="value: wepPassword,visible:!showWifiPassword()" maxlength='26' class="required form-control"/>

+						<input id='txtWepKey' name="txtWepKey" type="text"

+											   data-bind="value: wepPassword,visible:showWifiPassword()" maxlength='26' class="required form-control"/>

+						<div class="margin-top-10">

+							<p data-bind="css:{'checkbox_selected': showWifiPassword()}, click: showWifiPasswordHandler"

+										   manualControl="true" class="checkbox">

+								<input id="showWepPassword" data-bind="checked:showWifiPassword" type="checkbox"/>

+							</p>

+							<label data-trans="display_password" for="showWepPassword" class="floatleft margintop5 lineheight25"/>

+						</div>

+						<div id="lblShowWepPassword" class="clear"></div>

+					</div>

+				</div>

+				

+                <div data-bind="visible:selectedSecurityMode() == 'WPA2PSK' || selectedSecurityMode() == 'WPAPSKWPA2PSK' || selectedSecurityMode() == 'WPA3Personal' || selectedSecurityMode() == 'WPA2WPA3'" class="row form-group">

+                    <label data-trans="pass_phrase" for="txtWPAKey" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="codeWPAKey" name="codeWPAKey" data-bind="disable:wifiDisabled,value:WPAKey,visible:!showWifiPassword()" maxlength='63' minlength='8' type="password" class="form-control required"/>

+                        <input id="txtWPAKey" name="txtWPAKey" data-bind="disable:wifiDisabled,value:WPAKey,visible:showWifiPassword()" maxlength='63' minlength='8' type="text" class="form-control required"/>

+                        <p data-bind="css:{'checkbox_selected': showWifiPassword()}, click: showWifiPasswordHandler" manualControl="true" class="checkbox floatleft margintop10 marginleft5 marginright5">

+                            <input id="showWifiPassword" data-bind="checked:showWifiPassword" type="checkbox"/>

+                        </p>

+                        <label data-trans="display_password" for="showWifiPassword" class="floatleft margintop5 lineheight25"/>

+                        <div id="lblShowWifiPassword" class="clear"></div>

+                    </div>

+                </div>

+                </div>

+                <div class="form-note">

+                    <div class="notes-title">&nbsp;</div>

+                    <ul class="notes-content">

+                        <li data-trans="step5_encryption_mode_info"></li>

+                        <li class="no-style">

+                            <ul>

+                                <li data-trans="step5_encryption_mode_explain1"></li>

+								<li data-bind='visible: hasWifiWep' data-trans="wifi_basic_note_shared"></li>

+                                <li data-trans="step5_encryption_mode_explain2"></li>

+                                <li data-trans="step5_encryption_mode_explain3"></li>

+                                <li data-bind='visible: hasWifiWpa3' data-trans="wifi_basic_note_wpa3"></li>

+                                <li data-bind='visible: hasWifiWpa23' data-trans="wifi_basic_note_wpa2_wpa3"></li>

+                            </ul>

+                        </li>

+                        <li data-trans="step5_encryption_mode_explain4"></li>

+                    </ul>

+                </div>

+

+            </div>

+            <div data-bind="visible:currentStep()==5" style="display: none" id="step5">

+                <h3 class="form-title" data-trans="step_name_6"></h3>

+				<div class="content">

+                <div class="row form-group">

+                    <label data-trans="apn_settings" class="col-xs-3 side-right"></label>

+                    <label data-bind="text:apnMode_display,attr:{'data-trans':apnMode_trans}" class="col-xs-6"></label>

+                </div>

+                <div data-bind="visible:apnMode()=='manual'">

+                    <div class="row form-group">

+                        <label data-trans="apn_profile_name" class="col-xs-3 side-right"></label>

+                        <label data-bind="text:profileName" class="col-xs-6"></label>

+                    </div>

+                    <div class="row form-group" data-bind="visible:showIPv4">

+                        <label data-bind="attr:{'data-trans':transAPN}" class="col-xs-3 side-right"></label>

+                        <label data-bind="text: apn,attr:{title:apn}" class="col-xs-6 ellipsis"></label>

+                    </div>

+                    <div class="row form-group" data-bind="visible:showIPv4">

+                        <label data-bind="attr:{'data-trans':transAuthMode}" class="col-xs-3 side-right"></label>

+                        <label data-bind="text:selectedAuthMode_display" class="col-xs-6"></label>

+                    </div>

+                    <div class="row form-group" data-bind="visible:showIPv4">

+                        <label data-bind="attr:{'data-trans':transUserName}" class="col-xs-3 side-right"></label>

+                        <label  data-bind="text:username,attr:{title:username}" class="col-xs-6 ellipsis"></label>

+                    </div>

+                    <div class="row form-group" data-bind="visible:showIPv6">

+                        <label data-bind="attr:{'data-trans':transAPNIPv6}" class="col-xs-3 side-right"></label>

+                        <label data-bind="text:ipv6_apn" class="col-xs-6"></label>

+                    </div>

+                    <div class="row form-group" data-bind="visible:showIPv6">

+                        <label data-bind="attr:{'data-trans':transAuthModeIPv6}" class="col-xs-3 side-right"></label>

+                        <label data-bind="text:ipv6_selectedAuthMode_display" class="col-xs-6"></label>

+                    </div>

+                    <div class="row form-group" data-bind="visible:showIPv6">

+                        <label data-bind="attr:{'data-trans':transUserNameIPv6}" class="col-xs-3 side-right"></label>

+                        <label  data-bind="text:ipv6_username,attr:{title:ipv6_username}" class="col-xs-6 ellipsis"></label>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label data-trans="ssid_name" class="col-xs-3 side-right"></label>

+                    <label data-bind="text:ssid" class="col-xs-6"></label>

+                </div>

+                <div class="row form-group">

+                    <label data-trans="ssid_broadcast" class="col-xs-3 side-right"></label>

+                    <label data-bind="text:broadcast_display,attr:{'data-trans':broadcast_trans}" class="col-xs-6"></label>

+                </div>

+                <div class="row form-group">

+                    <label data-trans="security_mode" class="col-xs-3 side-right"></label>

+                    <label data-bind="text:selectedSecurityMode_display,attr:{'data-trans':selectedSecurityMode_trans}" class="col-xs-6"></label>

+                </div>

+                <div class="form-note">

+                    <div class="notes-title">&nbsp;</div>

+                    <ul class="notes-content">

+                        <li data-trans="step6_apply_explain"></li>

+                    </ul>

+                </div>

+                </div>

+            </div>      

+		    

+		</div>

+    </div>

+</form>		

+		

+        </div>

+    </div>

+</div>

diff --git a/ap/app/zte_webui_min/subpg/entry.html b/ap/app/zte_webui_min/subpg/entry.html
new file mode 100755
index 0000000..b293ae8
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/entry.html
@@ -0,0 +1,105 @@
+<div id="loginForms">

+    <div class="row margin-top-160 padding-bottom-50">

+        <div class="col-xs-3"></div>

+        <div class="col-xs-6" id="login-form-container">

+	<div id="loginContainer" class="login_frame form-horizontal margin-top-50 margin-bottom-50" data-bind="visible:pageState()!=4">

+		<form id="frmLogin" data-bind="visible:pageState()==0">

+            <div data-bind="visible: loginSecuritySupport() && accountLocked()" class="row form-group colorRed">

+                <div class="col-xs-12">

+                    <span data-trans="password_error_account_lock"></span> <span data-bind="text: leftUnlockTime"></span>

+                </div>

+            </div>

+            <div style="display: none;" class="row form-group">

+                <div class="col-xs-12">

+                    <label data-trans="password" for="txtAdmin"></label>

+                </div>

+			</div>

+            <div class="row form-group">

+                <div class="col-xs-8">

+                    <input id="txtAdmin" autocomplete="off" data-placeholder="password" data-bind="value:password, valueUpdate: 'keypress'"  maxlength="32" name="txtAdmin" style="border:2px solid rgb(221, 221, 221);" type="password" class="required form-control"/>

+                </div>

+                <div class="col-xs-4">

+                    <input id="btnLogin" class="btn btn-primary btn-block" data-trans="login" type="submit" formmethod="post" />

+                </div>

+            </div>

+            <div class="row form-group" data-bind="visible: showEntrance">

+                <div data-bind="visible: !sharePathInvalid()" class="col-xs-12">

+                    <span class="icon"><img src="pic/pic_red.png"></span>

+                    <span class="scan">

+                        <a data-trans="browse_sdcard" href="#httpshare_guest"></a>

+                    </span>

+                </div>

+                <div data-trans="sd_share_path_invalid" data-bind="visible: sharePathInvalid()" class="col-xs-12 colorRed"></div>

+                <div class="clear"></div>

+            </div>

+		</form>

+		<form id="frmPIN" data-bind="visible:pageState()==1">

+            <div class="row form-group">

+                <div class="prompt col-xs-6">

+                    <p data-trans="enter_pin"></p>

+                    <p data-bind="visible:pinNumber()>1" class="important-prompt marginbottom15">

+                        <span data-trans="attempts_left"></span> <span data-bind='text:pinNumber'></span>

+                    </p>

+                    <p class="important-prompt" data-bind="visible:pinNumber()==1" data-trans="last_enter_pin"></p>

+                </div>

+            </div>

+            <div class="row form-group">

+                <div class="col-xs-6">

+                    <label data-trans='pin' for='txtPIN'></label>

+                    <input id='txtPIN' name="txtPIN" autocomplete="off" data-bind="value:PIN, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control" />

+                </div>

+            </div>

+            <div class="row form-group">

+                <div class="col-xs-6">

+                    <input id="btnPinApply" data-trans="next_step" type="submit" formmethod="post" class="btn btn-primary" />

+                </div>

+            </div>

+		</form>

+		<form id="frmPUK" data-bind="visible:pageState()==2">

+            <div class="row form-group">

+                <div class="prompt col-xs-6">

+                    <p data-trans="enter_puk"></p>

+                    <p data-bind="visible:pukNumber()>1" class="important-prompt">

+                        <span data-trans="attempts_left"></span> <span data-bind='text:pukNumber'></span>

+                    </p>

+                    <p data-bind="visible:pukNumber()==1" data-trans="last_enter_puk" class="important-prompt"></p>

+                </div>

+            </div>

+			<div class="row form-group">

+                <div class="col-xs-6">

+                    <label data-trans='puk' for='txtPUK'></label>

+					<input id='txtPUK' name="txtPUK" autocomplete="off" data-bind="value:PUK, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control" />

+                </div>

+			</div>

+			<div class="row form-group">

+                <div class="col-xs-6">

+                    <label data-trans='new_pin' for='txtNewPIN'></label>

+					<input id='txtNewPIN' name="txtNewPIN" autocomplete="off" data-bind="value:newPIN, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control" />

+                </div>

+			</div>

+			<div class="row form-group">

+                <div class="col-xs-6">

+                    <label data-trans='confirm_pin' for='txtConfirmPIN'></label>

+					<input id='txtConfirmPIN' name="txtConfirmPIN" autocomplete="off"

+						data-bind="value:confirmPIN, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control"

+					/>

+                </div>

+			</div>

+			<div class="row form-group">

+                <div class="col-xs-6">

+					<input id="btnPUKApply" data-trans="next_step" type="submit" formmethod="post" class="btn btn-primary" />

+                </div>

+			</div>

+		</form>

+        <div data-bind="visible:pageState()==5" style="text-align: center;">

+            <img id="loadingImg" src="pic/res_loading.gif"/>

+        </div>

+		<div id="puk_locked" data-trans="puk_locked" data-bind="visible:pageState()==3" class="important-prompt prompt"></div>

+		<div class="login_bottom"></div>

+	</div>

+

+

+        </div>

+        <div class="col-xs-3"></div>

+    </div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/firewall.html b/ap/app/zte_webui_min/subpg/firewall.html
new file mode 100755
index 0000000..fb0e453
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/firewall.html
@@ -0,0 +1,69 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='advanced_settings'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+			<div class="nav_right">

+				<ul>

+					<li><a data-trans="sleep_mode" href="#wlan_sleep"></a></li>

+					<li><a data-trans="router_setting" href="#route_set"></a></li>

+					<li class="active"><a data-trans="firewall" href="#filter_main"></a></li>

+					<li data-bind="visible:hasUpdateCheck"><a data-trans="update_settings" href="#fota"></a></li>

+					<li data-bind="visible:hasUssd"><a data-trans="USSD" href="#usat"></a></li>

+					<li data-bind="visible:hasDdns"><a data-trans="DDNS" href="#dynamic_dns"></a></li>

+					<li><a data-trans="others" href="#more"></a></li>

+				</ul>

+			</div>

+		</div>

+

+    <div class="col-xs-10">

+        <div class="form-body">

+            <div class="content margin-top-20">

+                <div class="col-xs-4">

+                    <div class="row">

+                        <a href="#filter_port">

+                            <div data-trans="port_filter" class="line-height-40 arrow-right cursorhand"></div>

+                        </a>

+                    </div>

+                    <div class="row">

+                        <a href="#map_port">

+                            <div data-trans="port_map" class="line-height-40 arrow-right cursorhand"></div>

+                        </a>

+                    </div>

+                    <div class="row">

+                        <a href="#foward_port">

+                            <div data-trans="port_forward" class="line-height-40 arrow-right cursorhand"></div>

+                        </a>

+                    </div>

+                    <div data-bind="visible: hasUrlFilter" class="row">

+                        <a href="#filter_url">

+                            <div data-trans="url_filter" class="line-height-40 arrow-right cursorhand"></div>

+                        </a>

+                    </div>

+                    <div data-bind="visible: hasUpnp" class="row">

+                        <a href="#universal_plug_and_play">

+                            <div data-trans="upnp" class="line-height-40 arrow-right cursorhand"></div>

+                        </a>

+                    </div>

+                    <div class="row">

+                        <a href="#demilitarized_zone">

+                            <div data-trans="dmz" class="line-height-40 arrow-right cursorhand"></div>

+                        </a>

+                    </div>

+                </div>

+            </div>

+        </div>

+    </div>

+    </div>

+</div>

+

diff --git a/ap/app/zte_webui_min/subpg/firewall_dmz_set.html b/ap/app/zte_webui_min/subpg/firewall_dmz_set.html
new file mode 100755
index 0000000..a20dd29
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/firewall_dmz_set.html
@@ -0,0 +1,64 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a data-bind="attr: {href: isDataCard? '#main' : '#filter_main'}">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-bind="attr: {'data-trans': isDataCard? 'advanced_settings' : 'dmz_setting'}"></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+        <div class="col-xs-11">

+

+        <ul role="tablist" data-bind="visible: isDataCard" class="nav nav-tabs nav-justified">

+            <li class="active"><a data-trans="dmz_setting" href="#demilitarized_zone"></a></li>

+            <li><a data-trans="pin_management" href="#pin_mode"></a></li>

+            <li><a data-trans="update_settings" href="#fota"></a></li>

+        </ul>

+

+<form id="dmzSettingForm" data-bind="css: {'margin-top-20': isDataCard}">

+    <div class="form-body">

+        <div class="content">

+            <div class="row form-group">

+                <label data-trans="dmz_setting" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="dmzEnable" type="radio" name="dmzGrp" data-bind="checked: dmzSetting" value="1"/>

+                            <label for="dmzEnable" data-trans="enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="dmzDisable" type="radio" name="dmzGrp" data-bind="checked: dmzSetting" value="0"/>

+                            <label for="dmzDisable" data-trans="disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div data-bind='visible: dmzSetting() == "1"' class="row form-group">

+                <label for="txtIpAddress" data-trans="ip_address" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+                    <input id="txtIpAddress" name="txtIpAddress" type="text" data-bind="value: ipAddress, valueUpdate: 'keypress'" class="required form-control" maxlength="15"/>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input type="submit" formmethod="post" data-trans="apply" class="btn btn-primary"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="dmz_note_info"></li>

+                <li data-trans="dmz_note_function"></li>

+            </ul>

+        </div>

+    </div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/firewall_parental_control.html b/ap/app/zte_webui_min/subpg/firewall_parental_control.html
new file mode 100755
index 0000000..40efe8a
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/firewall_parental_control.html
@@ -0,0 +1,268 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='parental_control'></h1>

+            </div>

+        </div>

+    </div>

+    

+	<div class="row">

+	<div class="col-xs-2">

+		<div class="nav_right">

+			<ul>

+				<li data-bind="css:{ active : currentPage() == pages.MAIN}"><a data-bind="click: backToMainHandler" data-trans="pc_children_group" href="javascript: void(0)"></a></li>

+				<li data-bind="css:{ active : currentPage() == pages.MANAGE}"><a data-bind="click: manageHandler" data-trans="pc_children_group_manage" href="javascript: void(0)"></a></li>

+				<li data-bind="css:{ active : currentPage() == pages.RULE}"><a data-bind="click: openRulePage" data-trans="pc_internet_rule" href="javascript: void(0)"></a></li>

+			</ul>

+		</div>

+	</div>

+	<div class="col-xs-10">

+	

+	    <form id="pc_main_form" data-bind="visible: currentPage() == pages.MAIN">

+		    <h3 data-trans='pc_children_group' class="form-title"></h3>

+            <div class="form-body">

+                <div class="content">

+                    <div data-trans="pc_no_children_device" data-bind="visible: childGroupList().length == 0" class="expend-desc"></div>

+                    <div data-bind="foreach: childGroupList">

+                        <div class="device-block">

+                            <span data-bind="text: hostname, attr: {title: hostname}" class="device-block-desc"></span>

+                        </div>

+                    </div>

+                    <p data-trans="pc_children_group_desc" class="text-info expend-desc"></p>

+                </div>

+                <div class="form-note">

+                    <div class="notes-title">&nbsp;</div>

+                    <ul class="notes-content">

+                        <li data-trans="parent_control_note_kids"></li>

+                    </ul>

+                </div>

+            </div>

+        </form>

+	

+	    <form id="pc_children_group_form" style="display: none;" data-bind="visible: currentPage() == pages.MANAGE">

+            <div class="form-body">

+                <div class="row">

+                    <div class="col-md-6">

+                        <h2 data-trans="pc_children_group" style="margin-top: 6px;"></h2>

+                    </div>

+                    <!--div class="col-md-6 text-right">

+                        <a class="btn btn-default" data-trans="back" data-bind="click: backToMainHandler"></a>

+                    </div-->

+                </div>

+                <div class="content">

+                    <div>

+                        <table class="table table-striped table-hover">

+                            <thead>

+                            <tr>

+                                <th width="60" data-trans="station_number"></th>

+                                <th data-trans="host_name"></th>

+                                <th width="100"></th>

+                                <th width="200" data-trans="mac_address"></th>

+                                <th width="150" data-trans="pc_action"></th>

+                            </tr>

+                            </thead>

+                            <tbody data-bind="foreach: childGroupList">

+                            <tr data-bind="css: {odd: $index() % 2 == 0, even: $index() % 2 != 0}">

+                                <td data-bind="text: $index()+1"></td>

+                                <td>

+                                    <span data-bind="text: hostname, attr: {id: 'hostname_txt_'+$index()}"></span>

+                                    <input type="text" data-bind="attr: {id: 'hostname_input_'+$index()}" maxlength="32" style="display: none;" class="form-control">

+                                </td>

+                                <td>

+                                    <a data-bind="click: $root.editHostNameHandler, attr: {id: 'edit_btn_'+$index()}" class="cursorhand"><img src="./pic/res_edit.png" height="25"></a>

+                                    <a data-bind="click: $root.saveHostNameHandler, attr: {id: 'save_btn_'+$index()}" style="display: none;" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                                    <a data-bind="click: $root.cancelEditHostNameHandler, attr: {id: 'cancel_btn_'+$index()}" class="cursorhand" style="display: none;"><img height="25" src="./pic/res_cancel.png"></a>

+                                </td>

+                                <td data-bind="text: mac"></td>

+                                <td><a data-trans="pc_remove" data-bind="click: $root.removeChildGroupHandler" class="btn btn-primary btn-sm"></a></td>

+                            </tr>

+                            </tbody>

+                        </table>

+                    </div>

+                    <div data-trans="pc_no_children_device" data-bind="visible: childGroupList().length == 0" class="expend-desc"></div>

+                </div>

+

+                <div class="row">

+                    <div class="col-md-12">

+                        <h2 data-trans="pc_current_attached_devices"></h2>

+                    </div>

+                </div>

+                <div class="content">

+                    <table class="table table-striped table-hover">

+                        <thead>

+                        <tr>

+                            <th width="60" data-trans="station_number"></th>

+                            <th data-trans="host_name"></th>

+                            <th width="200" data-trans="mac_address"></th>

+                            <th width="150" data-trans="pc_action"></th>

+                        </tr>

+                        </thead>

+                        <tbody data-bind="foreach: attachedDevices">

+                        <tr data-bind="css: {odd: $index() % 2 == 0, even: $index() % 2 != 0}">

+                            <td data-bind="text: $index()+1"></td>

+                            <td data-bind="text: hostName"></td>

+                            <td data-bind="text: macAddress"></td>

+                            <td>

+                                <div data-bind="visible: inChildGroup" data-trans="pc_in_child_group"></div>

+                                <div data-bind="visible: !inChildGroup"><a data-trans="pc_add" data-bind="click: $root.addChildGroupHandler" class="btn btn-primary btn-sm"></a></div>

+                            </td>

+                        </tr>

+                        </tbody>

+                    </table>

+                    <div trans="no_data" data-bind="visible: attachedDevices().length == 0" class="expend-desc"></div>

+                </div>

+                <div class="form-note">

+                    <div class="notes-title">&nbsp;</div>

+                    <ul class="notes-content">

+                        <li data-trans="parent_control_note_manage"></li>

+                    </ul>

+                </div>

+			</div>

+        </form>

+	

+	    <form id="pc_time_limited_form" style="display: none;" data-bind="visible: currentPage() == pages.RULE">

+		    <h3 data-trans='pc_time_limited' class="form-title"></h3>

+            <div class="form-body">

+                <div class="content">

+                    <table class="table header-center">

+                        <thead>

+                        <tr>

+                            <td>&nbsp;</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td>

+                            <td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td>

+                        </tr>

+                        </thead>

+                        <tbody id="pc_time_limited_tbody">

+                        <tr>

+                            <td data-trans="sun" class="col-head"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                            <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                        </tr>

+                        <tr>

+                            <td data-trans="mon" class="col-head"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                            <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                        </tr>

+                        <tr>

+                            <td data-trans="tues" class="col-head"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                            <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                        </tr>

+                        <tr>

+                            <td data-trans="wed" class="col-head"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                            <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                        </tr>

+                        <tr>

+                            <td data-trans="thur" class="col-head"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                            <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                        </tr>

+                        <tr>

+                            <td data-trans="fri" class="col-head"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                            <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                        </tr>

+                        <tr>

+                            <td data-trans="sat" class="col-head"></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                            <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>

+                        </tr>

+                        </tbody>

+                    </table>

+                </div>

+                <div class="row-fluid expend-desc">

+                    <div style="line-height: 20px">

+                        <span class="pc_time_block forbid_time">&nbsp;</span><span data-trans="pc_forbid_time" class="margin-left-10 margin-right-20"></span>

+                        <span class="pc_time_block margin-left-15">&nbsp;</span><span data-trans="pc_allow_time" class="margin-left-10"></span>

+                    </div>

+                    <p data-trans="pc_setting_desc" class="text-info"></p>

+                    <p data-trans="pc_not_save" data-bind="visible: notSave" class="text-danger"></p>

+                </div>

+                <div class="form-buttons">

+                    <input type="button" data-trans="save" id="save_time_limited" data-bind="visible: currentUserInChildGroup() == false, click: saveTimeLimitedHandler" class="btn btn-primary">

+                </div>

+            </div>

+        </form>

+		

+	    <form id="pc_site_white_list_form" style="display: none;" data-bind="visible: currentPage() == pages.RULE">

+		    <h3 data-trans='pc_site_white_list' class="form-title"></h3>

+            <div class="form-body">

+                <div class="content">

+                        <div data-bind="visible: currentUserInChildGroup() == false">

+                        <input id="openAddSiteBtn" type="button" data-trans="add" data-bind="disable: disableAdd, click: openAddSitePopoverHandler" class="btn btn-primary">

+                        <input id="deleteSelectedBtn" type="button" data-trans="pc_remove" data-bind="disable: selectedIds().length == 0, click: removeSelectedWhiteSite" class="btn btn-primary">

+                    <input type="button" data-trans="pc_remove_all" data-bind="disable: siteList().length == 0, click: removeAllWhiteSite" class="btn btn-primary">

+                    </div>

+                    <div class="">

+                        <table style="table-layout: fixed; word-wrap: break-word; word-break: break-all;" class="table table-striped table-hover">

+                            <thead>

+                            <tr>

+                                <th width="40" align="center" data-bind="visible: currentUserInChildGroup() == false">

+                                    <p id="pc_white_list_check_all" target="pb_white_list" data-bind="click: checkboxClickHandler" class="checkbox checkboxToggle">

+                                        <input type="checkbox" name="siteId" value="1" />

+                                    </p>

+                                </th>

+                                <th width="170" data-trans="pc_name"></th>

+                                <th data-trans="pc_link"></th>

+                                <!--th width="150" data-trans="pc_action" data-bind="visible: currentUserInChildGroup() == false"></th-->

+                            </tr>

+                            </thead>

+                            <tbody id="pb_white_list" data-bind="foreach: siteList">

+                            <tr data-bind="css: {odd: $index() % 2 == 0, even: $index() % 2 != 0}">

+                                <td data-bind="visible: $root.currentUserInChildGroup() == false">

+                                    <p data-bind="click: $root.checkboxClickHandler" class="checkbox">

+                                        <input type="checkbox" target="pc_white_list_check_all" name="siteId" data-bind="value: id, checked: $root.selectedIds"/>

+                                    </p>

+                                </td>

+                                <td data-bind="text: name"></td>

+                                <td data-bind="text: site"></td>

+                                <!--td data-bind="visible: $root.currentUserInChildGroup() == false"><a class="btn btn-primary btn-sm" data-trans="pc_remove" data-bind="click: $root.removeWhiteSite"></a></td-->

+                            </tr>

+                            </tbody>

+                        </table>

+                    </div>

+                    <div data-trans="no_data" data-bind="visible: siteList().length == 0" class="expend-desc"></div>

+                </div>

+                <div class="form-note">

+                    <div class="notes-title">&nbsp;</div>

+                    <ul class="notes-content">                        

+                        <li data-trans="parent_control_note_time"></li>

+                        <li data-trans="parent_control_note_whitelist"></li>

+						<ul>                        

+                            <li data-trans="parent_control_note_siteName"></li>

+                            <li data-trans="parent_control_note_siteLink"></li>

+                        </ul>

+						<li data-trans="firewal_note"></li>

+                    </ul>

+                </div>

+			</div>

+        </form>	

+		

+	</div>

+	</div>

+	

+</div>

+<script id="addNewSiteTmpl" type="text/x-jquery-tmpl">

+<div>

+    <div class="popover_title" data-trans="pc_add_white_site"></div>

+    <div class="popover_content content">

+        <form id="whiteSiteAddForm" role="form" class="form-horizontal">

+            <div class="popover_row form-group">

+                <label data-trans="pc_name" for="siteName" class="col-xs-4 control-label"></label>

+                <div class="col-xs-8">

+                    <input id="siteName" type="text" maxlength="20" class="form-control" name="siteName">

+                </div>

+            </div>

+            <div class="popover_row form-group">

+                <label data-trans="pc_link" for="siteLink" class="col-xs-4 control-label"></label>

+                <div class="col-xs-8">

+                    <input id="siteLink" type="text" name="siteLink" maxlength="100" class="form-control required">

+                </div>

+            </div>

+            <div class="popover_row text-right">

+                <input type="submit" formmethod="post" data-trans="save"  class="btn btn-primary"/>

+                <a data-trans="pc_leave" class="btn btn-primary popover-close"></a>

+            </div>

+        </form>

+    </div>

+</div>

+</script>

diff --git a/ap/app/zte_webui_min/subpg/firewall_port_filter.html b/ap/app/zte_webui_min/subpg/firewall_port_filter.html
new file mode 100755
index 0000000..d06df34
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/firewall_port_filter.html
@@ -0,0 +1,253 @@
+<div id="innerContainer">

+<div class="row header-row">

+    <div class="col-xs-1">

+        <a href="#filter_main">

+            <img alt="" src="pic/direct-back.png">

+        </a>

+    </div>

+    <div class="col-xs-11">

+        <div class="form-title">

+            <h1 data-trans='port_filter'></h1>

+        </div>

+    </div>

+</div>

+<div class="row">

+<div class="col-xs-1 margin-top-15">

+</div>

+<div class="col-xs-11">

+

+

+<div class="form-body">

+    <form id="filterBasicForm">

+        <div class="content">

+            <div class="row form-group">

+                <label data-trans="port_filter_enabled" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="filterEnable" type="radio" name="filterGrp" data-bind="checked: portFilterEnable" value="1"/>

+                            <label for="filterEnable" data-trans="enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="filterDisable" type="radio" name="filterGrp" data-bind="checked: portFilterEnable" value="0"/>

+                            <label for="filterDisable" data-trans="disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div data-bind="visible: portFilterEnable() == '1' " class="row form-group">

+                <label data-trans="default_policy" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="defaultPolicyAccept" type="radio" name="defaultPolicyGrp" data-bind="checked: defaultPolicy, event: {click: policyChangeHandler}" value="0"/>

+                            <label for="defaultPolicyAccept" data-trans="accepted"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="defaultPolicyDrop" type="radio" name="defaultPolicyGrp" data-bind="checked: defaultPolicy, event: {click: policyChangeHandler}" value="1"/>

+                            <label for="defaultPolicyDrop" data-trans="dropped"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input type="submit" formmethod="post" data-trans="apply" class="btn btn-primary"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="default_policy_note"></li>

+                <li data-trans="default_policy_note_filter"></li>

+            </ul>

+        </div>

+    </form>

+    <div data-bind="visible: oriPortFilterEnable() == '1' && portFilterEnable() == '1' ">

+        <form id="portFilterForm">

+            <div class="form-title">

+                <h2 data-trans="port_filter_setting"></h2>

+            </div>

+            <div class="content">

+                <div data-bind="visible: ipv6Support" class="row form-group">

+                    <label data-trans="filter_ip_setting" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <div class="row">

+                            <div class="col-xs-4">

+                                <input id="filterIpv4" type="radio" name="ipTypeGrp" data-bind="checked: ipType, event: {click: ipTypeChangeHandler}" value="ipv4"/>

+                                <label for="filterIpv4" data-trans="filter_ipv4"></label>

+                            </div>

+                            <div class="col-xs-4">

+                                <input id="filterIpv6" type="radio" name="ipTypeGrp" data-bind="checked: ipType, event: {click: ipTypeChangeHandler}" value="ipv6"/>

+                                <label for="filterIpv6" data-trans="filter_ipv6"></label>

+                            </div>

+                        </div>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtMacAddress" data-trans="mac_address" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-9">

+                        <div class="row">

+                            <div class="col-xs-8">

+                                <input id="txtMacAddress" type="text" name="txtMacAddress" data-bind="value: macAddress"  maxlength="17" class="form-control"/>

+                            </div>

+                            <label id="macExamLabel" data-trans="macExam" class="col-xs-4"></label>

+                        </div>

+                    </div>

+                    <div id="macErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+                <div data-bind="visible: ipType() =='ipv4'">

+                    <div class="row form-group">

+                        <label for="txtSourceIpAddress" data-trans="source_ip_address" class="col-xs-3 side-right"></label>

+                        <div class="col-xs-6">

+                            <input id="txtSourceIpAddress" type="text" name="txtSourceIpAddress" data-bind="value: sourceIpAddress"  maxlength="15" class="form-control"/>

+                        </div>

+                    </div>

+                    <div class="row form-group">

+                        <label for="txtDestIpAddress" data-trans="dest_ip_address" class="col-xs-3 side-right"></label>

+                        <div class="col-xs-6">

+                            <input id="txtDestIpAddress" type="text" name="txtDestIpAddress" data-bind="value: destIpAddress"  maxlength="15" class="form-control"/>

+                        </div>

+                    </div>

+                </div>

+                <div data-bind="visible: ipType() =='ipv6'">

+                    <div class="row form-group">

+                        <label for="txtSourceIpv6Address" data-trans="source_ipv6_address" class="col-xs-3 side-right"></label>

+                        <div class="col-xs-6">

+                            <input id="txtSourceIpv6Address" type="text" name="txtSourceIpv6Address" data-bind="value: sourceIpv6Address" class="form-control"/>

+                        </div>

+                    </div>

+                    <div class="row form-group">

+                        <label class="col-xs-3 side-right" for="txtDestIpv6Address" data-trans="dest_ipv6_address"></label>

+                        <div class="col-xs-6">

+                            <input id="txtDestIpv6Address" type="text" name="txtDestIpv6Address" data-bind="value: destIpv6Address" class="form-control"/>

+                        </div>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label class="col-xs-3 side-right" for="protocol" data-trans="protocol"></label>

+                    <div class="col-xs-6">

+                        <select id="protocol" data-transid="protocol" data-bind="options: modes, value: selectedMode, optionsText: transOption('protocol'), optionsValue: 'value', event:{ change: protocolChangeHandler}" class="form-control"></select>

+                    </div>

+                </div>

+                <!--根据protocol显示或隐藏-->

+                <div id="portRangeArea" data-bind="visible: selectedMode() != 'ICMP' && selectedMode() != 'None' ">

+                    <div class="row form-group">

+                        <label for="txtSourcePortStart" data-trans='source_port_range' class="col-xs-3 side-right"></label>

+                        <div class="col-xs-9">

+                            <div class="row">

+                                <div class="col-xs-3">

+                                    <input id='txtSourcePortStart' name="txtSourcePortStart" type="text" data-bind="value: sourcePortStart"

+                                          maxlength="5"  class="required rangeInput form-control"/>

+                                </div>

+                                <div class="col-xs-2 text-center">

+                                    -

+                                </div>

+                                <div class="col-xs-3">

+                                    <input id='txtSourcePortEnd' name="txtSourcePortEnd" type="text" data-bind="value: sourcePortEnd"

+                                           maxlength="5" class="required rangeInput form-control"/>

+                                </div>

+                                <label id='sourceRangeLabel' class="col-xs-4">(1~65535)</label>

+                            </div>

+                        </div>

+                        <div id="sourcePortErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                    </div>

+                    <div class="row form-group">

+                        <label for="txtDestPortStart" data-trans='dest_port_range' class="col-xs-3 side-right"></label>

+                        <div class="col-xs-9">

+                            <div class="row">

+                                <div class="col-xs-3">

+                                    <input id='txtDestPortStart' name="txtDestPortStart" type="text" data-bind="value: destPortStart"  maxlength="5" class="required rangeInput form-control"/>

+                                </div>

+                                <div class="col-xs-2 text-center">

+                                    -

+                                </div>

+                                <div class="col-xs-3">

+                                    <input id='txtDestPortEnd' name="txtDestPortEnd" type="text" data-bind="value: destPortEnd"

+                                           maxlength="5" class="required rangeInput form-control"/>

+

+                                </div>

+                                <label id='destRangeLabel' class="col-xs-4">(1~65535)</label>

+                            </div>

+                        </div>

+                        <div id="destPortErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                    </div>

+                </div>

+

+                <div class="row form-group">

+                    <label data-trans="port_filter_action" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <div class="row">

+                            <div class="col-xs-4">

+                                <input id="portFilterAccept" type="radio" name="portFilterActionGrp" data-bind="checked: portFilterAction" value="Accept"/>

+                                <label for="portFilterAccept" data-trans="filter_accept"></label>

+                            </div>

+                            <div class="col-xs-4">

+                                <input id="portFilterDrop" type="radio" name="portFilterActionGrp" data-bind="checked: portFilterAction" value="Drop"/>

+                                <label for="portFilterDrop" data-trans="filter_drop"></label>

+                            </div>

+                        </div>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtComment" data-trans="comment" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="txtComment" type="text" name="txtComment" data-bind="value: comment" maxlength="32" class="required form-control"/>

+                    </div>

+                </div>

+            </div>

+            <div class="form-buttons">

+                <input type="submit" formmethod="post" data-trans="apply" class="btn btn-primary"/>

+            </div>

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="port_filter_note_mac_address"></li>

+                    <li data-trans="port_filter_note_source_ip_address"></li>

+                    <li data-trans="port_filter_note_dest_ip_address"></li>

+                    <li data-trans="port_filter_note_protocol"></li>

+                    <li data-trans="port_filter_note_source_port_range"></li>

+                    <li data-trans="port_filter_note_dest_port_range"></li>

+                    <li data-trans="port_filter_note_action"></li>

+                    <li data-trans="port_filter_note_comment"></li>

+                    <li data-trans="port_filter_note_info"></li>

+                    <li data-trans="rule_max_note_v4v6" data-bind="visible: ipv6Support"></li>

+                    <li data-trans="rule_max_note" data-bind="visible: !ipv6Support()"></li>

+                </ul>

+            </div>

+        </form>

+        <form id="portFilterListForm">

+            <div class="form-title">

+                <h2 data-trans="port_filter_list"></h2>

+            </div>

+            <div class="content">

+                <div>

+                    <div id="portFilters" data-bind="simpleGrid: gridTemplate" class="fixTableScroll"></div>

+                </div>

+            </div>

+

+            <div class="form-buttons">

+                <input type="submit" formmethod="post" data-trans="delete" data-bind="enable: gridTemplate.checkedCount() > 0" class="btn btn-primary"/>

+            </div>

+

+            <!-- ko if: oriDefaultPolicy() == '0' -->

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="filter_accept_note"></li>

+                </ul>

+            </div>

+            <!-- /ko -->

+            <!-- ko if: oriDefaultPolicy() == '1' -->

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="filter_drop_note"></li>

+                </ul>

+            </div>

+            <!-- /ko -->

+        </form>

+    </div>

+</div>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/firewall_port_forward.html b/ap/app/zte_webui_min/subpg/firewall_port_forward.html
new file mode 100755
index 0000000..c41d3b7
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/firewall_port_forward.html
@@ -0,0 +1,130 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#filter_main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='port_forward'></h1>

+            </div>

+        </div>

+    </div>

+<div class="row">

+    <div class="col-xs-1 margin-top-15">

+

+    </div>

+    <div class="col-xs-11">

+

+<div class="form-body">

+    <form id="virtualServerForm">

+

+        <div class="content">

+            <div class="row form-group">

+                <label class="col-xs-3 side-right" data-trans="virtual_server_setting"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="serverEnable" type="radio" name="serverGrp" data-bind="checked: portForwardEnable" value="1"/>

+                            <label for="serverEnable" data-trans="enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="serverDisable" type="radio" name="serverGrp" data-bind="checked: portForwardEnable" value="0"/>

+                            <label for="serverDisable" data-trans="disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input type="submit" formmethod="post" data-trans="apply" class="btn btn-primary"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="port_forward_note_info"></li>

+            </ul>

+        </div>

+    </form>

+    <div data-bind="visible: oriPortForwardEnable() == '1' && portForwardEnable() == '1' ">

+        <form id="portForwardForm">

+            <div class="form-title">

+                <h2 data-trans="port_forward_setting"></h2>

+            </div>

+            <div class="content">

+                <div class="row form-group">

+                    <label for="txtIpAddress" data-trans="ip_address" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-9">

+                        <div class="row">

+                            <div class="col-xs-8">

+                                <input id="txtIpAddress" type="text" name="txtIpAddress" data-bind="value: ipAddress" maxlength="15" class="required form-control"/>

+                            </div>

+                            <label id="ipExamLabel" data-trans="ipExam" class="col-xs-4"></label>

+                        </div>

+                    </div>

+                    <div id="ipErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtPortStart" data-trans='port_range' class="col-xs-3 side-right"></label>

+                    <div class="col-xs-9">

+                        <div class="row">

+                            <div class="col-xs-3">

+                                <input id='txtPortStart' name="txtPortStart" type="text" data-bind="value: portStart"

+                                       maxlength="5" class="required rangeInput form-control"/>

+                            </div>

+                            <div class="col-xs-2 text-center">

+                                -

+                            </div>

+                            <div class="col-xs-3">

+                                <input id='txtPortEnd' name="txtPortEnd" type="text" data-bind="value: portEnd"

+                                       maxlength="5" class="required rangeInput form-control"/>

+                            </div>

+                            <label id='rangeLabel' class="col-xs-4">(1~65535)</label>

+                        </div>

+                    </div>

+                    <div id="portRangeErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+                <div class="row form-group">

+                    <label class="col-xs-3 side-right" for="protocol" data-trans="protocol"></label>

+                    <div class="col-xs-6">

+                        <select id="protocol" data-transid="protocol" data-bind="options: modes, value: selectedMode, optionsText: transOption('protocol'), optionsValue: 'value'" class="form-control"></select>

+                     </div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtComment" data-trans="comment" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="txtComment" type="text" name="txtComment" data-bind="value: comment" maxlength="32" class="required form-control"/>

+                   </div>

+                </div>

+            </div>

+            <div class="form-buttons">

+                <input type="submit" formmethod="post" data-trans="apply" class="btn btn-primary"/>

+            </div>

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">  

+                    <li data-trans="port_forward_note_ip_address"></li>

+					<li data-trans="port_forward_note_port"></li>

+                    <li data-trans="port_forward_note_protocol"></li>

+                    <li data-trans="port_forward_note_comment"></li>

+                    <li data-trans="rule_max_note"></li>

+                </ul>

+            </div>

+        </form>

+        <form id="portForwardListForm">

+            <div class="form-title">

+                <h2 data-trans="port_forward_list"></h2>

+            </div>

+            <div class="content">

+                <div id="portForwards" data-bind="simpleGrid: gridTemplate" class="fixTableScroll"></div>

+            </div>

+            <div class="form-buttons">

+                <input type="submit" formmethod="post" data-trans="delete" data-bind="enable: gridTemplate.checkedCount() > 0" class="btn btn-primary"/>

+            </div>

+        </form>

+    </div>

+</div>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/firewall_port_map.html b/ap/app/zte_webui_min/subpg/firewall_port_map.html
new file mode 100755
index 0000000..ec7c838
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/firewall_port_map.html
@@ -0,0 +1,120 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#filter_main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='port_map'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+        <div class="col-xs-11">

+

+<div class="form-body">

+    <form id="mapBasicForm">

+        <div class="content">

+            <div class="row form-group">

+                <label data-trans="port_map_setting" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="mapEnable" type="radio" name="mapGrp" data-bind="checked: portMapEnable" value="1"/>

+                            <label for="mapEnable" data-trans="enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="mapDisable" type="radio" name="mapGrp" data-bind="checked: portMapEnable" value="0"/>

+                            <label for="mapDisable" data-trans="disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input class="btn btn-primary" type="submit" formmethod="post" data-trans="apply"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="port_map_note_info"></li>

+            </ul>

+        </div>

+    </form>

+    <div data-bind="visible: oriPortMapEnable() == '1' && portMapEnable() == '1' ">

+        <form id="portMapForm">

+            <div class="form-title">

+                <h2 data-trans="port_map_setting"></h2>

+            </div>

+            <div class="content">

+                <div class="row form-group">

+                    <label for="txtSourcePort" data-trans="source_port" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="txtSourcePort" type="text" name="txtSourcePort" data-bind="value: sourcePort" maxlength="5" class="required form-control"/>

+                    </div>

+                    <label id="sourcePortExamLabel" class="col-xs-3">(1~65000)</label>

+                    <div id="txtSourcePortErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtDestIpAddress" data-trans="dest_ip_address" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="txtDestIpAddress" type="text" name="txtDestIpAddress" data-bind="value: destIpAddress" maxlength="15" class="required form-control"/>

+                    </div>

+                    <label id="ipExamLabel" data-trans="ipExam" class="col-xs-3"></label>

+                    <div id="txtDestIpAddressErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtDestPort" data-trans="dest_port" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="txtDestPort" type="text" name="txtDestPort" data-bind="value: destPort" maxlength="5" class="required form-control"/>

+                    </div>

+                    <label id="destPortExamLabel" class="col-xs-3">(1~65000)</label>

+                    <div id="txtDestPortErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+                <div class="row form-group">

+                    <label for="protocol" data-trans="protocol" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <select id="protocol" data-transid="protocol" data-bind="options: modes, value: selectedMode, optionsText: transOption('protocol'), optionsValue: 'value'" class="form-control"></select>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label for="txtComment" data-trans="comment" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <input id="txtComment" type="text" name="txtComment" data-bind="value: comment" maxlength="32" class="required form-control"/>

+                    </div>

+                </div>

+            </div>

+            <div class="form-buttons">

+                <input class="btn btn-primary" type="submit" formmethod="post" data-trans="apply"/>

+            </div>

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="port_map_note_port"></li>

+                    <li data-trans="port_map_note_dest_ip_address"></li>

+                    <li data-trans="port_map_note_protocol"></li>

+                    <li data-trans="port_map_note_comment"></li>

+                    <li data-trans="rule_max_note"></li>

+                </ul>

+            </div>

+        </form>

+        <form id="portMapListForm">

+            <div class="form-title">

+                <h2 data-trans="port_map_list"></h2>

+            </div>

+            <div class="content">

+                <div id="portMaps" data-bind="simpleGrid: gridTemplate" class="fixTableScroll"></div>

+            </div>

+            <div class="form-buttons">

+                <input type="submit" formmethod="post" data-trans="delete" data-bind="enable: gridTemplate.checkedCount() > 0" class="btn btn-primary"/>

+            </div>

+        </form>

+    </div>

+</div>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/firewall_url_filter.html b/ap/app/zte_webui_min/subpg/firewall_url_filter.html
new file mode 100755
index 0000000..c404151
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/firewall_url_filter.html
Binary files differ
diff --git a/ap/app/zte_webui_min/subpg/main.html b/ap/app/zte_webui_min/subpg/main.html
new file mode 100755
index 0000000..c5f8c00
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/main.html
@@ -0,0 +1,216 @@
+

+<div class="row margin-top-20">

+<div class="type_items">

+	<ul>

+		<li><a href="#child_ctl" data-bind="visible: hasParentalControl" data-trans="parental_control" class="c0EC6DC"></a></li>

+		<li><a href="#msg_main"  data-bind="visible: hasSms" data-trans="sms" class="cF53A58"></a></li>

+		<li><a href="#pb_main" data-bind="visible: hasPhonebook" data-trans="phonebook" class="c00AEFF"></a></li>

+		<li><a href="#sdcard" data-bind="visible: isSupportSD" data-trans="sd" class="c2175FF"></a></li>

+		<li><a data-bind="attr: {href: notDataCard? '#wlan_sleep' : '#demilitarized_zone'}" data-trans="advanced_settings" class="cFFCE2B"></a></li>

+		<li><a href="#fast_set" data-bind="visible: isSupportQuicksetting()" data-trans="quick_setting" class="cFFCE2B"></a></li>

+	</ul>

+</div>

+</div>

+

+<div class="row margin-top-20" id="home_image">

+

+<div class="row">

+    <div style="position: relative">	

+        <div class="internet_status_container">

+		    <div data-bind=" css: {'item_icon_connect': cStatus()== 1, 'item_icon_disconnect': cStatus() != 1}"></div>

+			<h3 data-trans="net_surfing" class="home_h3"></h3>

+			<div class="net_surfing_list">

+				<ul>

+					<li><a id="h_connect_btn" href="javascript: void(0)" data-bind="visible: canConnect() && isShowHomeConnect(), click: connectHandler , css: {'h_connect_on': cStatus()== 1, 'h_connect_off': cStatus() != 1}" style="display: none;"></a></li>

+					<li><i class="up"></i><span data-bind="text: up_Speed"></span></li>

+					<li><i class="down"></i><span data-bind="text: down_Speed"></span></li>

+					<li><span data-bind="text: connected_Time"></span></li>

+				</ul>

+			</div>

+        </div>

+		

+		<div class="network_control_container">

+		    <div class="item_icon"></div>

+			<h3 data-trans="my_router" class="home_h3"></h3>			

+			<!--div id="h_network_type" data-bind="text: networkType, css: {'no-btn': !(canConnect() && isShowHomeConnect())}"></div-->

+			<div class="my_router_list">

+				<ul>

+					<li data-bind="visible: hasRj45"><a id="opmode" data-bind="click: showOpModeWindow, css: {'not-allowed': enableFlag}" href="javascript:void(0)"></a></li>

+					<li><a data-bind="click: showNetworkSettingsWindow" data-trans="settings_internet" href="javascript:void(0)"></a></li>

+					<!--li><div id="h_ssid"></div></li-->

+					<li data-bind="visible: notDataCard"><a data-trans="settings_wireless" href="#wlan_main"></a></li>

+				</ul>

+			</div>

+		</div>

+		        

+        <!--div id="h_connect_status" data-bind="visible:notDataCard, css: {'h_status_connected': cStatus()== 1, 'h_status_disconnected': cStatus()== 2, 'h_status_connecting': cStatus()== 3, 'h_status_disconnecting': cStatus()== 4, }">

+        </div-->

+        

+		<div data-bind="visible: notDataCard" onclick="window.location.hash='#conn_device'" class="connected_devices_container">

+		    <div class="item_icon"></div>

+			<h3 data-trans="station_info" class="home_h3" ></h3>

+            <div style="text-align:center;display:inline" class="margin-top-20">

+				<div id="h_wire_device" data-bind="visible: hasRj45 && isCPE">

+					<span data-bind="text: wireDeviceNum" style="font-size:70px;"><em></em></span><sub data-trans="device_unit" style="font-size: 16px;"></sub>

+					<span data-trans="cable" style="font-size:15px;text-align:center;display:block"></span>

+				</div>

+				<div id="h_wireless_device" style="display-block">

+					<span data-bind="text: wirelessDeviceNum" style="font-size:70px"></span><sub data-trans="device_unit" style="font-size: 16px;"></sub>

+					<span data-trans="wireless" style="font-size:15px;text-align:center;display:block"></span>

+				</div>

+			</div>	

+            <!--a href="#conn_device" id="h_attached_device_link">

+            </a-->

+        </div>

+    </div>

+</div>

+</div>

+

+

+<div class="row margin-top-20 label-font-normal margin-bottom-20">

+    <div class="text-center traffic_control_container" data-bind="visible: showTraffic()">

+        <h4 data-trans="traffic_data_plan" style="font-size:14px;text-align:right;padding-right:15px"></h4>

+        <div style="display:inline-block">

+            <div id="traffic_graphic" style="width: 200px; height: 165px; visibility: visible;"></div>

+        </div>		

+        <div style="text-align: left;padding-left:20px;font-size:18px">

+			<span style="background-color: #8CC916;" class="color_block"></span>

+			<span data-trans="traffic_used" class="color_block_desc"></span>

+			<span class="color_block_desc">:</span>

+			<span data-bind="text: trafficUsed" class="color_block_desc"></span>

+	    </div>

+		<div class="statistics_list">

+			<ul>

+				<li><a href="#flow_ctl">

+				    <div data-bind="visible: trafficAlertEnable">

+                        <span data-bind="text: trafficLimited" class="line-height-20"></span>

+                        <span data-trans="traffic_limit_data" class="line-height-20"></span>

+                    </div>

+                    <div data-bind="visible: trafficAlertEnable() == false">

+                        <div data-trans="traffic_not_set_limited" class="line-height-20"></div>

+                    </div>

+				</a></li>

+			</ul>

+		</div>

+    </div>

+    	

+		

+	<div data-bind="css:{'device_info_container_hastraffic':showTraffic(),'device_info_container_notraffic':!showTraffic()}" class="device_info_container">

+        <h4 data-trans="device_info" style="font-size:14px;text-align:left;padding-left:15px;color:#fff"></h4>

+        <div style="color:#fff;position: relative;height: 210px;font-size: 18px;line-height: 1.5em;padding:20px 0px 0px 15px;">

+			<div class="row">

+				<label data-trans="sim_serial_number" class="col-xs-5"></label>

+				<label data-bind="text: simSerialNumber" class="col-xs-7"></label>

+			</div>

+			<div class="row">

+				<label data-trans="imei" class="col-xs-5"></label>

+				<label data-bind="text: imei" class="col-xs-7"></label>

+			</div>

+			<div class="row">

+				<label data-trans="imsi" class="col-xs-5"></label>

+				<label data-bind="text: imsi" class="col-xs-7"></label>

+			</div>

+			<!--div class="row" data-bind="visible: notDataCard">

+				<label class="col-xs-5" data-trans="wifi_range"></label>

+				<label class="col-xs-7" data-bind="attr: {'data-trans': wifiLongMode}"></label>

+			</div-->

+			<div class="row">

+				<label data-trans="signal_strength_label" class="col-xs-5"></label>

+				<label id="fresh_signal_strength" class="col-xs-7"></label>

+			</div>

+			<div class="row" data-bind="visible: hasWifi && showMultiSsid()">

+				<label data-trans="network_name_ssid1" class="col-xs-5"></label>

+				<label data-bind="text: ssid" style="word-wrap: break-word;" class="col-xs-7"></label>

+			</div>

+			<div class="row" data-bind="visible: hasWifi && !showMultiSsid()">

+				<label data-trans="network_name" class="col-xs-5"></label>

+				<label data-bind="text: ssid" style="word-wrap: break-word;" class="col-xs-7"></label>

+			</div>

+		</div>

+        <div style="text-align:right;">

+		    <a href="javascript: void(0)" data-trans="detail_info" id="showDetailInfo" tabindex="0"></a>

+        </div>

+    </div>

+</div>

+

+

+<div id="h_qrcode" data-bind="visible: showQRCode" style="float:right" class="text-center">

+    <img id="qrcode_img" data-bind="attr: {src: qrcodeSrc}" src="./pic/res_blacktrans.png" width="111"/>

+</div>

+

+<script type="text/x-jquery-tmpl" id="detailInfoTmpl">

+<div class="row">

+    <label class="col-xs-6" data-trans="sim_serial_number" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= simSerialNumber %></label>

+</div>

+<div class="row">

+    <label data-trans="imei" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= imei %></label>

+</div>

+<div class="row">

+    <label data-trans="imsi" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= imsi %></label>

+</div>

+<div class="row">

+    <label data-trans="signal_strength_label" class="col-xs-6"></label>

+    <label class="col-xs-6" id="popoverSignalTxt"><%= signal %></label>

+</div>

+<% if(hasWifi){ %>

+<div class="row">

+    <label data-trans="<%= showMultiSsid ? 'network_name_ssid1': 'network_name' %>" class="col-xs-6"></label>

+    <label style="word-wrap: break-word; word-break: break-all;" class="col-xs-6"><%= ssid %></label>

+</div>

+<div class="row">

+    <label data-trans="<%= showMultiSsid ? 'max_access_num_ssid1': 'max_access_num' %>" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= max_access_num %></label>

+</div>

+    <% if(showMultiSsid){ %>

+        <div class="row">

+            <label data-trans="network_name_ssid2" class="col-xs-6"></label>

+            <label style="word-wrap: break-word; word-break: break-all;" class="col-xs-6"><%= m_ssid %></label>

+        </div>

+        <div class="row">

+            <label data-trans="max_access_num_ssid2" class="col-xs-6"></label>

+            <label class="col-xs-6"><%= m_max_access_num %></label>

+        </div>

+    <% } %>

+<div class="row">

+    <label data-trans="wifi_range" class="col-xs-6"></label>

+    <label data-trans="<%= wifi_long_mode %>" class="col-xs-6"></label>

+</div>

+<% } %>

+<div class="row">

+    <label data-trans="lan_domain" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= lanDomain %></label>

+</div>

+<div class="row">

+    <label data-trans="ip_address" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= ipAddress %></label>

+</div>

+<% if(showMacAddress){ %>

+<div class="row">

+    <label data-trans="mac_address" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= macAddress %></label>

+</div>

+<% } %>

+<% if(showIpv4WanIpAddr){ %>

+<div class="row">

+    <label data-trans="wan_ip_address" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= wanIpAddress %></label>

+</div>

+<% } %>

+<% if(showIpv6WanIpAddr){ %>

+<div class="row">

+    <label data-trans="ipv6_wan_ip_address" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= ipv6WanIpAddress %></label>

+</div>

+<% } %>

+<div class="row">

+    <label data-trans="software_version" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= sw_version %></label>

+</div>

+<div class="row">

+    <label data-trans="hardware_version" class="col-xs-6"></label>

+    <label class="col-xs-6"><%= hw_version %></label>

+</div>

+</script>

diff --git a/ap/app/zte_webui_min/subpg/network_apn_set.html b/ap/app/zte_webui_min/subpg/network_apn_set.html
new file mode 100755
index 0000000..c308b85
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/network_apn_set.html
@@ -0,0 +1,220 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='net_setting'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		<div class="nav_right">

+			<ul>

+			    <li><a data-trans="dial_mode" href="#conn_set"></a></li>

+				<li><a data-trans="net_select" href="#network_choose"></a></li>

+				<li class="active"><a data-trans="apn_setting" href="#cgdcont_set"></a></li>

+			</ul>

+		</div>

+	    </div>

+

+	    <div class="col-xs-10">

+

+<form id="apn_setting_form">

+	<div class="form-body">

+	    <h3 data-trans="apn_setting" class="form-title"></h3>

+		<div class="content">

+            <!-- 当前APN -->

+			<div class="row form-group">

+				<label data-trans="apn_currentApn" class="col-xs-3 side-right"></label>

+				<label data-bind="text: defApn" class="col-xs-6"></label>

+			</div>

+            <!-- 模式  手动、自动 -->

+			<div class="row form-group">

+				<label data-trans="apn_mode" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="apnMode_auto" type="radio" name="apnMode" data-bind="checked: apnMode, event: {click: apnModeChangeHandler}, disable: autoApnChecked() == false && disableProfile() == true" value="auto"/>

+                            <label for="apnMode_auto" data-trans="apn_auto_apn"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="apnMode_manual" type="radio" name="apnMode" data-bind="checked: apnMode, event: {click: apnModeChangeHandler}, disable: autoApnChecked() == false && disableProfile() == true" value="manual"/>

+                            <label for="apnMode_manual" data-trans="apn_manual_apn"></label>

+                        </div>

+                    </div>

+                </div>

+			</div>

+			<div id="apn_form_container" data-bind="visible: showAutoApnDetail()">

+				<div class="row form-group">

+					<label class="col-xs-3 side-right" for="profile" data-trans="apn_profile"></label>

+	                <div class="col-xs-4">

+	                    <select id="autoProfile" name="autoProfile" data-bind="options: autoProfiles, value: selectedAutoProfile, optionsText: 'text', optionsValue: 'value', disable: disableProfile, event:{ change: autoProfileChangeHandler}, visible: apnMode() == 'auto'" class="form-control"></select>

+	                    <select id="profile" name="profile" data-bind="options: profiles, value: selectedProfile, optionsText: 'text', optionsValue: 'value', disable: disableProfile, event:{ change: profileChangeHandler}, visible: apnMode() == 'manual'" class="form-control"></select>

+	                </div>

+

+                    <div class="col-xs-2">

+                        <input type="button" data-bind="click: addAct, visible: autoApnChecked() == false && disableProfile() == false && hasCapacity() == true" data-trans="add_new" class="btn btn-primary"/>

+                        <input type="button" data-bind="click: cancelAddAct, visible: autoApnChecked() == false && disableProfile() == true && hasCapacity() == true" data-trans="cancel" class="btn btn-primary"/>

+                    </div>

+				</div>

+				<div data-bind="visible: supportIPv6()" class="row form-group">

+					<label for="apn_pdp_type" data-trans="apn_pdp_type" class="col-xs-3 side-right"></label>

+	                <div class="col-xs-6">

+	                    <select id="apn_pdp_type" name="apn_pdp_type" data-bind="options: pdpTypes, value: selectedPdpType, optionsText: 'text', optionsValue: 'value', disable: checkInputDisable, event:{ change: pdpTypeChangeAlert}" class="form-control"></select>&nbsp;

+	                </div>

+				</div>

+				<div class="row form-group">

+					<label for="profile_name" data-trans="apn_profile_name" class="col-xs-3 side-right"></label>

+	                <div class="col-xs-6">

+	                    <input id="profile_name" type="text" name="profile_name" data-bind="value: profileName, disable: checkInputDisable" maxlength="15" class="required form-control"/>

+	                </div>

+				</div>

+				<div id="ipv4_section" data-bind="visible: selectedPdpType() != 'IPv6'">

+					<div class="row form-group">

+						<label for="apn_ipv4_apn" data-bind="attr:{'data-trans': transApn}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+							<input id="apn_ipv4_apn" type="text" name="apn_ipv4_apn" data-bind="value: apn, disable: checkInputDisable" maxlength="64" class="required form-control"/>

+		                </div>

+					</div>

+					<div class="row form-group" data-bind="visible: showApnDns()">

+						<label data-bind="attr:{'data-trans': transDnsMode}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+		                    <input id="apn_auto_dns_ipv4" type="radio" name="apn_auto_dns_ipv4" data-bind="checked: dnsMode, disable: checkInputDisable" value="auto"/>

+		                    <label for="apn_auto_dns_ipv4" data-trans="apn_auto_dns"></label>

+		                    <input id="apn_manual_dns_ipv4" type="radio" name="apn_manual_dns_ipv4" data-bind="checked: dnsMode, disable: checkInputDisable" value="manual"/>

+		                    <label for="apn_manual_dns_ipv4" data-trans="apn_manual_dns"></label>

+		                </div>

+					</div>

+					<div data-bind="visible: showDns() && showApnDns()" class="row form-group">

+						<label for="apn_dns1_ipv4" data-bind="attr:{'data-trans': transDns1}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+		                    <input id="apn_dns1_ipv4" type="text" name="apn_dns1_ipv4" data-bind="value: dns1, disable: checkInputDisable" maxlength="15" class="required ipv4 form-control"/>

+		                </div>

+					</div>

+					<div data-bind="visible: showDns() && showApnDns()" class="row form-group">

+						<label for="apn_dns2_ipv4" data-bind="attr:{'data-trans': transDns2}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+		                    <input id="apn_dns2_ipv4" type="text" name="apn_dns2_ipv4" data-bind="value: dns2, disable: checkInputDisable" maxlength="15" class="ipv4 form-control"/>

+		                </div>

+					</div>

+					<div class="row form-group">

+						<label for="apn_authentication_ipv4" data-bind="attr:{'data-trans': transAuth}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+		                    <select id="apn_authentication_ipv4" name="apn_authentication_ipv4" data-bind="options: authModes, disable: checkInputDisable, value: selectedAuthentication, optionsText: 'text', optionsValue: 'value'" class="form-control"></select>

+		                </div>

+					</div>

+					<div class="row form-group">

+						<label for="apn_user_name_ipv4" data-bind="attr:{'data-trans': transUserName}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+							<input id="apn_user_name_ipv4" type="text" name="apn_user_name_ipv4" data-bind="value: username, disable: checkInputDisable" maxlength="64" class="form-control"/>

+		                </div>

+					</div>

+					<div class="row form-group">

+						<label class="col-xs-3 side-right" for="apn_secretcode_ipv4" data-bind="attr:{'data-trans': transPassword}"></label>

+						<div class="col-xs-6">

+							<input id="apn_secretcode_ipv4" type="password" name="apn_secretcode_ipv4" data-bind="value: password,visible:!showPassword(), disable: checkInputDisable" maxlength="64" class="form-control"/>

+							<input id="apn_secretcode_ipv4_show" type="text" name="apn_secretcode_ipv4" data-bind="value: password,visible:showPassword(), disable: checkInputDisable" maxlength="64" class="form-control"/>

+							<div class="margin-top-10">

+								<p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler" manualControl="true" class="checkbox">

+									<input id="showPassword" data-bind="checked:showPassword" type="checkbox"/>

+								</p>

+								<label data-trans="display_password" class="floatleft lineheight25 margintop5"></label>

+							</div>

+						</div>

+					</div>

+				</div>

+				

+				<!-- 以下是ipv6 -->

+				

+				<div data-bind="visible: (selectedPdpType() == 'IPv4v6' && supportIpv4AndIpv6()) || selectedPdpType() == 'IPv6'">

+					<div class="row form-group">

+						<label for="apn_ipv6_apn" data-bind="attr:{'data-trans': transApnV6}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+							<input id="apn_ipv6_apn" type="text" name="apn_ipv6_apn" data-bind="value: apnV6, disable: checkInputDisable" maxlength="64" class="required form-control"/>

+		                </div>

+					</div>

+					<div data-bind="visible: showApnDns()" class="row form-group">

+						<label data-bind="attr:{'data-trans': transDnsModeV6}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+		                    <input id="apn_auto_dns_ipv6" type="radio" name="dns_ipv6" data-bind="checked: dnsModeV6, disable: checkInputDisable" value="auto"/>

+		                    <label for="apn_auto_dns_ipv6" data-trans="apn_auto_dns"></label>

+		                    <input id="apn_manual_dns_ipv6" type="radio" name="dns_ipv6" data-bind="checked: dnsModeV6, disable: checkInputDisable" value="manual"/>

+		                    <label for="apn_manual_dns_ipv6" data-trans="apn_manual_dns"></label>

+		                </div>

+					</div>

+					<div data-bind="visible: showDnsV6() && showApnDns()" class="row form-group">

+						<label for="apn_dns1_ipv6" data-bind="attr:{'data-trans': transDns1V6}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+		                    <input id="apn_dns1_ipv6" type="text" name="apn_dns1_ipv6" data-bind="value: dns1V6, disable: checkInputDisable" class="required ipv6 form-control"/>

+		                </div>

+					</div>

+					<div class="row form-group" data-bind="visible: showDnsV6() && showApnDns()">

+						<label class="col-xs-3 side-right" for="apn_dns2_ipv6" data-bind="attr:{'data-trans': transDns2V6}"></label>

+		                <div class="col-xs-6">

+		                    <input id="apn_dns2_ipv6" type="text" name="apn_dns2_ipv6" data-bind="value: dns2V6, disable: checkInputDisable" class="ipv6 form-control"/>

+		                </div>

+					</div>

+					

+					<div class="row form-group">

+						<label for="authentication_ipv6" data-bind="attr:{'data-trans': transAuthV6}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+		                    <select id="authentication_ipv6" name="authentication_ipv6" data-bind="options: authModes, disable: checkInputDisable, value: selectedAuthenticationV6, optionsText: 'text', optionsValue: 'value'" class="form-control"></select>

+		                </div>

+					</div>

+					<div class="row form-group">

+						<label for="apn_user_name_ipv6" data-bind="attr:{'data-trans': transUserNameV6}" class="col-xs-3 side-right"></label>

+		                <div class="col-xs-6">

+							<input id="apn_user_name_ipv6" type="text" name="apn_user_name_ipv6" data-bind="value: usernameV6, disable: checkInputDisable" maxlength="64" class="form-control"/>

+		                </div>

+					</div>

+					<div class="row form-group">

+						<label for="apn_secretcode_ipv6" data-bind="attr:{'data-trans': transPasswordV6}" class="col-xs-3 side-right"></label>

+						<div class="col-xs-6">

+							<input id="apn_secretcode_ipv6" type="password" name="apn_secretcode_ipv6" data-bind="value: passwordV6,visible:!showPassword(), disable: checkInputDisable" maxlength="64" class="form-control"/>

+							<input id="apn_secretcode_ipv6_show" type="text" name="apn_secretcode_ipv6" data-bind="value: passwordV6,visible:showPassword(), disable: checkInputDisable" maxlength="64" class="form-control"/>

+							<div class="margin-top-10">

+								<p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler" manualControl="true" class="checkbox">

+									<input id="showV6Password" data-bind="checked:showPassword" type="checkbox"/>

+								</p>

+								<label data-trans="display_password" class="floatleft lineheight25 margintop5"></label>

+							</div>

+						</div>

+					</div>

+				</div>

+			    <div class="row form-group">

+					<label for="apn_secretcode_ipv6" data-trans="dial_num" class="col-xs-3 side-right"></label>

+		            <label class="col-xs-6" data-bind="text: wanDial"></label>

+				</div>

+			</div>

+		</div>

+		<div class="form-buttons">

+			<input type="button" data-bind="click: setDefaultAct, visible: disableProfile() == false && setDefaultVisible() && !defaultCfg()" data-trans="set_default" class="btn btn-primary"/>

+			<input type="submit" formmethod="post" data-bind="visible: (!autoApnChecked() && !predeterminedCfg()) || disableProfile() == true" data-trans="apply" class="btn btn-primary"/>

+			<input type="button" data-bind="click: deleteAct, visible: !autoApnChecked() && !defaultCfg() && !predeterminedCfg() && !disableProfile()" data-trans="delete" class="btn btn-primary"/>

+		</div>

+		<div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+        		<li data-trans="apn_note_whole_page"></li>

+        		<li data-trans="apn_note_mode"></li>

+        		<li data-trans="apn_note_profile"></li>

+        		<li data-trans="apn_note_pdp_type" data-bind="visible: supportIPv6()"></li>

+        		<li data-trans="apn_note_profile_name"></li>

+        		<li data-trans="apn_note_apn"></li>

+        		<li data-trans="apn_note_dns_mode" data-bind="visible: showApnDns()"></li>

+        		<li data-trans="apn_note_authentication"></li>

+        		<li data-trans="apn_note_username"></li>

+        		<li data-trans="apn_note_password"></li>

+        		<li data-trans="apn_note_set_default"></li>

+        	</ul>

+		</div>

+	</div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/network_dial_set.html b/ap/app/zte_webui_min/subpg/network_dial_set.html
new file mode 100755
index 0000000..e59b1ca
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/network_dial_set.html
@@ -0,0 +1,68 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='net_setting'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		<div class="nav_right">

+			<ul>

+			    <li class="active"><a data-trans="dial_mode" href="#conn_set"></a></li>

+				<li><a data-trans="net_select" href="#network_choose"></a></li>

+				<li><a data-trans="apn_setting" href="#cgdcont_set"></a></li>

+			</ul>

+		</div>

+	    </div>

+

+	    <div class="col-xs-10">

+

+<form>

+<div class="form-body">

+	    <h3 data-trans="dial_mode" class="form-title"></h3>

+    <div class="content">

+            <div class="row form-group">

+                <label data-trans='dial_mode' class="col-xs-3 side-right"></label>

+                <div class="col-xs-2">

+                    <input id='auto_mode' type="radio" name="modeGroup" value="auto_dial" data-bind="checked: selectMode, enable: enableFlag" />

+                    <label for='auto_mode' data-trans='auto_select'></label>

+                </div>

+                <div class="col-xs-2">

+                    <input id='manual_mode' type="radio" name="modeGroup"  value="manual_dial" data-bind="checked: selectMode, enable: enableFlag" />

+                    <label for='manual_mode' data-trans='manual_select'></label>

+                </div>

+            </div>

+

+            <div data-bind="visible: selectMode() == 'auto_dial'" class="row form-group">

+                <div class="col-xs-3"></div>

+                <div class="col-xs-8 label-absolute">

+                    <p id="roamBtn" data-bind="css:{'checkbox_selected': isAllowedRoaming()=='on'}, click: setAllowedRoaming" manualControl="true"class="checkbox floatleft margintop5 checkboxToggle">

+                        <input type="checkbox" id="isAllowedRoaming" value="on" data-bind="checked:isAllowedRoaming()=='on'" />

+                    </p>

+                    <label for="isAllowedRoaming" data-trans="dial_roaming_remind" class="update_inline floatleft lineheight25"></label>

+                </div>

+            </div>

+    </div>

+    <div class="form-buttons">

+        <input type="button" data-bind='click: save, enable: enableFlag' data-trans="apply" class="btn btn-primary"/>

+    </div>

+    <div class="form-note">

+        <div class="notes-title">&nbsp;</div>

+        <ul class="notes-content">

+			<li data-trans="diconneted_operate_note"></li>

+            <li data-trans="dial_setting_note_automatic"></li>

+            <li data-trans="dial_setting_note_manual"></li>

+        </ul>

+    </div>

+</div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/network_dial_set_cpe.html b/ap/app/zte_webui_min/subpg/network_dial_set_cpe.html
new file mode 100755
index 0000000..c5b31d8
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/network_dial_set_cpe.html
@@ -0,0 +1,171 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='wan'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+        <div class="col-xs-11">

+

+<form id="pppoeForm">

+<input type="hidden" data-bind="value: action" />

+<div class="form-body">

+    <div class="content">

+		<div class="row form-group">

+			<label data-trans='dial_mode' class="col-xs-3 side-right"></label>

+			<div class="col-xs-6">

+				<select id='pppoe_mode' data-transid="pppoe_mode_type" name="pppoe_mode" data-bind="options: modes, value: currentMode, optionsText: transOption('pppoe_mode_type'), optionsValue: 'value', event: {change: changeModeDiv}" class="form-control">

+				</select>

+			</div>

+		</div>

+		<div id="pppoeMode" data-bind="visible: isPppoeMode">

+			<!--div class="form-title">PPPoE</div-->

+			<div class="row form-group">

+				<label data-trans='apn_user_name' class="col-xs-3 side-right"></label>

+				<div class="col-xs-6">

+					<input type="text" data-bind="value: user" maxlength="30" class="required form-control">

+				</div>

+			</div>

+			<div class="row form-group">

+				<label data-trans='apn_password' class="col-xs-3 side-right"></label>

+				<div class="col-xs-6">

+					<input type="password" data-bind="value: password,visible:!showPassword()" maxlength="30" class="required form-control"/>

+					<input type="text" data-bind="value: password,visible:showPassword()" maxlength="30" class="required form-control"/>

+					<div class="margin-top-10">

+						<p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler" manualControl="true" class="checkbox">

+							<input id="showPassword" data-bind="checked:showPassword" type="checkbox"/>

+						</p>

+						<label data-trans="display_password" class="floatleft lineheight25 margintop5"></label>

+					</div>

+				</div>

+			</div>

+			<div class="row form-group" data-bind="visible:pppoeNoticeShow">

+				<label data-trans="net_status" class="col-xs-3 side-right"></label>

+				<label data-bind="text:pppoeNoticeText,attr:{'data-trans':pppoeNotice}" class="col-xs-6 side-left"></label>

+			</div>			

+		</div>

+		

+		<div id="staticMode" data-bind="visible: isStaticMode">

+			<!--div class="form-title">Static</div-->

+			<div class="row form-group">

+                <label for="txtIpAddress" data-trans="ip_address" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+					<input id="txtIpAddress" name="txtIpAddress" type="text" data-bind="value: ipAddress" maxlength="15" class="required form-control"/>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label for="txtSubnetMask" data-trans="subnet_mask" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+					<input id="txtSubnetMask" name="txtSubnetMask"  type="text" data-bind="value: subnetMask" maxlength="15" class="required form-control"/>

+                </div>

+            </div>

+			<div class="row form-group">

+                <label for="txtDefaultGateway" data-trans="default_Gateway" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+					<input id="txtDefaultGateway" name="txtDefaultGateway" type="text" data-bind="value: defaultGateway" maxlength="15" class="required form-control"/>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label for="txtPrimaryDNS" data-trans="primary_dns" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+					<input id="txtPrimaryDNS" name="txtPrimaryDNS"  type="text" data-bind="value: primaryDNS" maxlength="15" class="required form-control"/>

+                </div>

+            </div>

+			<div class="row form-group">

+                <label for="txtSecondaryDNS" data-trans="secondary_dns" class="col-xs-3 side-right"></label>

+                <div class="col-xs-6">

+					<input id="txtSecondaryDNS" name="txtSecondaryDNS"  type="text" data-bind="value: secondaryDNS" maxlength="15" class="required form-control"/>

+                </div>

+            </div>

+			<div class="row form-group" data-bind="visible:staticNoticeShow">

+				<label data-trans="net_status" class="col-xs-3 side-right"></label>

+				<label data-bind="text:staticNoticeText,attr:{'data-trans':staticNotice}" class="col-xs-6 side-left"></label>

+			</div>

+		</div>	

+

+        <div id="autoMode" data-bind="visible: isAutoMode()">

+			<div class="row form-group">

+				<label data-trans='apn_user_name' class="col-xs-3 side-right"></label>

+				<div class="col-xs-6">

+					<input type="text" data-bind="value: autoUser" maxlength="30" class="required form-control">

+				</div>

+			</div>

+			<div class="row form-group">

+				<label data-trans='apn_password' class="col-xs-3 side-right"></label>

+				<div class="col-xs-6">

+					<input type="password" data-bind="value: autoPassword,visible:!showPassword()" maxlength="30" class="required form-control"/>

+					<input type="text" data-bind="value: autoPassword,visible:showPassword()" maxlength="30" class="required form-control"/>

+					<div class="margin-top-10">

+						<p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler" manualControl="true" class="checkbox">

+							<input data-bind="checked:showPassword" type="checkbox"/>

+						</p>

+						<label data-trans="display_password" class="floatleft lineheight25 margintop5"></label>

+					</div>

+				</div>

+			</div>

+			<div data-bind="visible:autoNoticeShow" class="row form-group">

+				<label data-trans="net_status" class="col-xs-3 side-right"></label>

+				<label data-bind="text:autoNoticeText,attr:{'data-trans':autoNotice}" class="col-xs-6 side-left"></label>

+			</div>

+        </div>		

+		

+		<div class="row form-group">

+				<label data-trans='dial_mode_cpe' class="col-xs-3 side-right"></label>

+				<div class="col-xs-3">

+					<input id="autoDial" type="radio" name="pppMode"  data-bind="checked: pppMode, enable: enableFlag" value="auto_dial" class=""/>

+					<label for="autoDial" data-trans="auto_select"></label>

+				</div>

+				<div class="col-xs-3">

+					<input id="manualMode" type="radio" name="pppMode" data-bind="checked: pppMode" value="manual_dial" class=""/>

+					<label for="manualMode" data-trans="manual_select"></label>

+				</div>

+		</div>

+		

+		<div class="row form-group" data-bind="visible:dhcpNoticeShow">

+			<label data-trans="net_status" class="col-xs-3 side-right"></label>

+			<label data-bind="attr:{'data-trans':dhcpNotice},text:dhcpNoticeText" class="col-xs-6 side-left"></label>

+		</div>		

+	</div>

+	<div class="form-buttons">

+		<input id="pppoeApply" type="submit" formmethod="post" data-bind='attr: {"data-trans": btnTrans}' class="btn btn-primary"/>

+		<input id="cancelConnect" type="button" data-trans="cancelconnect" data-bind='click: cancelConnect, visible: isShowCancelbtn' class="btn btn-primary"/>

+		<input id="disconnectConnect" type="button" data-trans="disconnect" data-bind='click: cancelConnect, visible: isShowDisbtn' class="btn btn-primary"/>

+	</div>

+    

+    <div class="form-note">

+        <div class="notes-title">&nbsp;</div>

+        <ul class="notes-content">

+            <li data-trans="wan_note_connection_mode"></li>

+            <li class="no-style">

+                <ul>

+                    <li data-trans="wan_note_connection_mode_pppoe"></li>

+                    <li data-trans="wan_note_connection_mode_dhcp"></li>

+                    <li data-trans="wan_note_connection_mode_static"></li>

+					<li data-trans="wan_note_connection_mode_auto"></li>

+                </ul>

+            </li>

+            <li data-bind="visible: isPppoeMode || isAutoMode()" data-trans="wan_note_user_name"></li>

+            <li data-bind="visible: isPppoeMode || isAutoMode()" data-trans="wan_note_password"></li>

+            <li data-bind="visible: isPppoeMode" data-trans="wan_note_dial"></li>

+            <li data-bind="visible: isPppoeMode" class="no-style">

+                <ul>

+                    <li data-trans="dial_setting_note_automatic"></li>

+                    <li data-trans="dial_setting_note_manual"></li>

+                </ul>

+            </li>

+        </ul>

+    </div>

+</div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/network_net_select.html b/ap/app/zte_webui_min/subpg/network_net_select.html
new file mode 100755
index 0000000..c7bb48c
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/network_net_select.html
@@ -0,0 +1,106 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='net_setting'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		<div class="nav_right">

+			<ul>

+			    <li><a data-trans="dial_mode" href="#conn_set"></a></li>

+				<li class="active"><a data-trans="net_select" href="#network_choose"></a></li>

+				<li><a data-trans="apn_setting" href="#cgdcont_set"></a></li>

+			</ul>

+		</div>

+	    </div>

+

+	    <div class="col-xs-10">

+

+<form role="form">

+<div class="form-body">

+	    <h3 data-trans="net_select" class="form-title"></h3>

+    <div class="content">

+        <div class="row form-group">

+            <label data-trans='net_select' class="col-xs-4 side-right"></label>

+            <div class="col-xs-8">

+                <div class="row">

+                    <div class="col-xs-4">

+                        <input id='auto_select' type="radio" name="selectGroup" value="auto_select" data-bind="checked: selectMode, enable: enableFlag" />

+                        <label for='auto_select' data-trans='auto_select'></label>

+                    </div>

+                    <div class="col-xs-6">

+                        <select id="type" data-transid='auto_select_type' data-bind="options: types, value: selectedType, optionsText: transOption('auto_select_type'), optionsValue: 'value', enable: enableFlag() && selectMode() == 'auto_select'" class="form-control"></select>

+                    </div>

+                </div>

+            </div>

+        </div>

+        <div class="row form-group">

+            <label class="col-xs-4 side-right"></label>

+            <div class="col-xs-8">

+                <input id='manual_select' type="radio" name="selectGroup"  value="manual_select" data-bind="checked: selectMode, enable: enableFlag" />

+                <label for='manual_select' data-trans='manual_select'></label>

+            </div>

+        </div>

+    </div>

+    <div class="form-buttons">

+        <input type="button" data-bind='click: save, visible: selectMode() == "auto_select", enable: enableFlag, css: {disabled: !enableFlag()}' data-trans='apply' class="btn btn-primary"/>

+        <input type="button" data-bind='click: search, visible: selectMode() != "auto_select", enable: enableFlag, css: {disabled: !enableFlag()}' data-trans='search' class="btn btn-primary"/>

+    </div>

+    

+    <div data-bind='visible: networkList().length > 0 && selectMode() == "manual_select"' class="content">

+        <div class="form-title">

+            <h2 data-trans='network_list'></h2>

+        </div>

+        <div class="content">

+            <div class="ko-grid-container marginnone">

+                <table cellspacing="0" cellpadding="0" class="table table-striped table-hover">

+                    <thead>

+                    <tr>

+                        <th width="12%" data-trans="option"></th>

+                        <th width="16%" data-trans="net_status"></th>

+                        <th width="21%" data-trans="network_provider"></th>

+                        <th width="18%" data-trans="mccmnc"></th>

+                        <th width="18%" data-trans="networktype"></th>

+                        <th width="15%" data-trans="subnet"></th>

+                    </tr>

+                    </thead>

+                    <tbody data-bind='foreach: networkList'>

+                    <tr data-bind="css:{odd:$index()%2==1, even:$index()%2==0}">

+                        <td><input type="radio" name="networkGroup"

+                                   data-bind='value: $root.networkValue($data), checked: $root.selectNetwork, attr: {id: $root.networkValue($data)}, enable: $root.enableFlag'/>

+                        </td>

+                        <td data-bind='attr: {"data-trans": $root.networkStatusId($data)}, text: $root.networkStatus($data)'></td>

+                        <td data-bind='text: $root.operatorName($data)'></td>

+                        <td data-bind='text: $root.networkText($data)'></td>

+                        <td data-bind='attr: {"data-trans": $root.networkTypeId($data)}, text: $root.networkType($data)'></td>

+                        <td data-bind='attr: {"data-trans": $root.subnetTypeId($data)}, text: $root.subnetworkType($data)'></td>

+                    </tr>

+                    </tbody>

+                </table>

+            </div>

+        </div>

+	     <div class="form-buttons">

+		     <input type="button" data-bind='click: register, enable: selectNetwork() != "" && enableFlag, css: {disabled: selectNetwork() == "" || !enableFlag()}' data-trans='register' class="btn btn-primary"/>

+		 </div>

+     </div>

+    <div class="form-note">

+        <div class="notes-title">&nbsp;</div>

+        <ul class="notes-content">

+			<li data-trans="diconneted_operate_note"></li>

+            <li data-trans="net_select_note_automatic"></li>

+            <li data-trans="net_select_note_manual"></li>

+        </ul>

+    </div>

+</div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/opmode_popup.html b/ap/app/zte_webui_min/subpg/opmode_popup.html
new file mode 100755
index 0000000..08a5074
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/opmode_popup.html
@@ -0,0 +1,41 @@
+<form id="opmode_form">

+	<div class="form-body">

+		<div data-trans="opmode" class="form-title"></div>

+		<div class="content">

+			<!--<div class="row form-group">-->

+                <!--<div class="col-xs-1"></div>-->

+                <!--<div class="col-xs-10">-->

+                    <!--<input id="opMode_bridge" name="opMode" data-bind="checked: selectedMode" type="radio" value="BRIDGE">-->

+                    <!--<label data-trans="opmode_bridge" for="opMode_bridge"></label>-->

+                <!--</div>-->

+			<!--</div>-->

+			<div class="row form-group">

+                <div class="col-xs-1"></div>

+                <div class="col-xs-10">

+                    <input id="opMode_cable" name="opMode" data-bind="checked: selectedMode" type="radio" value="PPPOE" />

+				    <label data-trans="opmode_cable" for="opMode_cable"></label>

+                </div>

+			</div>

+			<div class="row form-group">

+                <div class="col-xs-1"></div>

+                <div class="col-xs-10">

+                    <input id="opMode_gateway" name="opMode" data-bind="checked: selectedMode" type="radio" value="PPP" />

+                    <label data-trans="opmode_gateway" for="opMode_gateway"></label>

+                </div>

+			</div>

+			<div class="row form-group">

+                <div class="col-xs-1"></div>

+                <div class="col-xs-10">

+                    <input id="opMode_auto" name="opMode" data-bind="checked: selectedMode" type="radio" value="AUTO" />

+                    <label data-trans="auto_select" for="opMode_auto"></label>

+                </div>

+			</div>

+			<!--div>

+				<span data-trans="opmode_msg1" class="op_msg help-block" />

+			</div-->

+			<div style="margin-right: 0;" class="form-buttons">

+				<input data-trans="apply" type="submit" formmethod="post" class="btn btn-default"/>

+			</div>		

+		</div>

+	</div>

+</form>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/ota_update.html b/ap/app/zte_webui_min/subpg/ota_update.html
new file mode 100755
index 0000000..f7a84de
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/ota_update.html
@@ -0,0 +1,148 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='advanced_settings'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+			<div class="nav_right">

+				<ul>

+					<li data-bind="visible: isDataCard"><a href="#demilitarized_zone" data-trans="dmz_setting"></a></li>

+					<li data-bind="visible: isDataCard"><a href="#pin_mode" data-trans="pin_management"></a></li>

+					<li data-bind="visible: !isDataCard"><a href="#wlan_sleep" data-trans="sleep_mode"></a></li>

+					<li data-bind="visible: !isDataCard"><a href="#route_set" data-trans="router_setting"></a></li>

+					<li data-bind="visible: !isDataCard"><a href="#filter_main" data-trans="firewall"></a></li>

+					<li data-bind="visible:hasUpdateCheck" class="active"><a href="#fota" data-trans="update_settings"></a></li>

+					<li data-bind="visible:hasUssd"><a href="#usat" data-trans="USSD"></a></li>

+					<li data-bind="visible:hasDdns"><a href="#dynamic_dns" data-trans="DDNS"></a></li>

+					<li data-bind="visible: !isDataCard"><a href="#more" data-trans="others"></a></li>

+				</ul>

+			</div>

+		</div>

+

+<div class="col-xs-10">

+<form id="frmOTAUpdate" role="form" data-bind="visible: updateType() == 'mifi_fota'">

+    <h3 data-trans="ota_update_manual" class="form-title"></h3>

+    <div class="form-body margin-top-20">

+        <div class="content">

+            <div class="row">

+                <div class="col-xs-6">

+                    <!--span data-trans="ota_last_update_check"></span>

+                    <span data-bind="text: lastCheckTime"></span-->

+                </div>

+                <div class="col-xs-6 align-right">

+                    <input id="btnCheckNewVersion" data-bind="click:checkNewVersion" data-trans="ota_check_new_version" type="button" class="btn btn-primary margin-right-20"/>

+                </div>

+            </div>

+			<div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="ota_check_new_version_desc"></li>

+                </ul>

+		    </div>

+        </div>

+

+        <!--div class="form-title" data-trans='ota_update_manual'></div>

+        <div class="content">

+            <span class="paddingleft25" data-trans="ota_check_new_version_desc"></span>

+        </div>

+        <div class="form-buttons">

+            <input id="btnCheckNewVersion" type="button" class="btn btn-primary" data-trans="ota_check_new_version"

+                   data-bind="click:checkNewVersion"/>

+        </div>

+        <div class="form-title" data-trans='ota_update_setting'></div-->

+        <div class="content">

+            <h3 data-trans="ota_update_setting" class="form-title"></h3>

+            <div class="row">

+                <label data-trans="ota_auto_update_switch" class="col-xs-4 side-right"></label>

+                <div class="col-xs-8">

+                    <div class="row form-group">

+                        <div class="col-xs-3">

+                            <input id="auto_update_enable" name="updateMode" data-bind="checked: updateMode" type="radio" value="1"/>

+                            <label data-trans="enable" for="auto_update_enable"></label>

+                        </div>

+                        <div class="col-xs-3">

+                            <input id="auto_update_disable" name="updateMode" data-bind="checked: updateMode" type="radio" value="0"/>

+                            <label data-trans="disable" for="auto_update_disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div class="row form-group" data-bind="visible: false">

+                <label data-trans="ota_update_interval_day" for="selInterValDay" class="col-xs-4 side-right"></label>

+

+                <div class="col-xs-3">

+                    <select id="selInterValDay" name="selInterValDay" data-bind="value: updateIntervalDay" class="form-control">

+                        <option data-trans="ota_update_every_day" value="1"></option>

+                        <option data-trans="ota_update_15_day" value="15"></option>

+                        <option data-trans="ota_update_30_day" value="30"></option>

+                    </select>

+                </div>

+            </div>

+            <div class="row form-group" data-bind="visible: updateMode()=='1'">

+                <div class="col-xs-12 padding-top-10">

+                    <p class="checkbox" data-bind="css:{'checkbox_selected': allowRoamingUpdate()=='1'}, click: clickAllowRoamingUpdate"

+                       manualControl="true">

+                        <input id="chkUpdateRoamPermission" name="chkUpdateRoamPermission" data-bind="checked:allowRoamingUpdate()=='1'" type="checkbox" value="1"/>

+                    </p>

+                    <label data-trans="ota_update_roaming_remind" class="update_inline floatleft"></label>

+                </div>

+            </div>

+

+            <div class="form-buttons">

+                <input id="btnApply" data-trans="apply" type="submit" formmethod="post" class="btn btn-primary"/>

+            </div>

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="fota_note1"></li>

+                </ul>

+		    </div>

+		</div>

+        

+	</div>

+</form>

+<!--form id="frmNativeUpdate" data-bind="visible: updateType() == 'mifi_local'" method="post" name="UploadFile" id="UploadFile" action="../../cgi-bin/upload.cgi" enctype="multipart/form-data" target="ifr"> 

+	<div class="form-body">

+		<h3 class="form-title" data-trans="software_upload"></h3>

+		<table style="width:100%">  

+			<input type="text" id="upfile" size="20" style="height:35px; width:200px; display:inline-block;" readonly />

+			<input type="button" class="btn btn-primary" data-trans='browse_btn' style="height:34px; width:81px;" />

+			<input id="fileName" class="form-control" type="file" name="fileName" style="margin-left: 15px;background-color:#E3E3E3;opacity:0;filter:alpha(opacity=0);position:absolute;left:0px; width:280px; display:inline-block;" /> 

+			<input class="btn btn-primary" id="fileuploadsubmit" type="submit" formmethod="post" data-trans="ota_title" style="float:right; margin-top:8px; margin-right: 20px;" /> 

+		</table>  

+		<iframe name="ifr" id="ifr" style="display:none;"></iframe>

+	</div>

+</form-->

+    <div id="uploadSection" data-bind="visible: updateType() == 'mifi_local'">

+        <h3 class="form-title" data-trans="software_upload"></h3>

+        <iframe id="fileUploadIframe" name="fileUploadIframe" frameborder="0" height="0" scrolling="no" style="height:0px;width:0px;" width="0"></iframe>

+        <form id="fileUploadForm" name="fileUploadForm" action="../../cgi-bin/upload/upload.cgi" enctype="multipart/form-data" method="post" target="fileUploadIframe">

+            <input id="fileField" name="filename" dir="ltr" maxlength="200" type="file"/>

+            <div class="fileUploadDiv">

+                <input id="fileUploadApplyBtn" name="fileUploadApplyBtn" data-trans="ota_title" type="button" onclick="fileUploadSubmitClickHandler();" class="btn btn-primary margin-left-5 margin-top-2"/>

+            </div>

+            <div class="clear"></div>

+        </form>

+    </div>

+	<form data-bind="visible: updateType() == 'mifi_local'">

+	    <div class="form-body">

+	    <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="local_note"></li>

+            </ul>

+		</div>

+		</div>

+	</form>

+</div>

+</div>

+</div>

diff --git a/ap/app/zte_webui_min/subpg/sim_abnormal.html b/ap/app/zte_webui_min/subpg/sim_abnormal.html
new file mode 100755
index 0000000..324787e
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/sim_abnormal.html
@@ -0,0 +1,123 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a data-bind="visible: !isHomePage()" href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='no_sim_card_title'></h1>

+            </div>

+        </div>

+    </div>

+    <div style="margin-top:-15px;margin-bottom:30px;color:#428bca;" class="row">   

+	    <div style="position: relative;" class="col-xs-7"></div>

+		<div id="currentOpMode" data-bind="visible: hasRj45" class="col-xs-5 text-right">

+			<label data-trans="current_mode"></label>

+			<span id="opmode"></span>

+			<input id="change" data-trans="change" data-bind="click: showOpModeWindow, visible: isLoggedIn, enable: enableFlag" style="display:none" type="button" class="btn btn-primary" />

+		</div>

+	</div> 

+	<div id="div-nosimcard" class="row form-group">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+

+    <!--div data-bind="visible: !isHomePage()" class="col-xs-1 margin-top-15">

+        <a href="#main">

+            <img alt="" src="pic/direct-back.png">

+        </a>

+    </div-->

+    <div class="col-xs-11">

+        <div data-bind="visible:page()==pageState.NO_SIM" class="content">

+            <div data-trans="no_sim_card_message" class="colorRed font18"></div>

+        </div>

+        <form id="frmPIN" data-bind="visible:page()==pageState.WAIT_PIN">

+            <div class="form-body">

+                <div class="content">

+                    <div class="prompt">

+                        <p data-trans="enter_pin"></p>

+

+                        <p data-bind="visible:pinNumber()>1" class="important-prompt">

+                            <span data-trans="attempts_left"></span> <span data-bind='text:pinNumber'></span>

+                        </p>

+

+                        <p data-bind="visible:pinNumber()==1" data-trans="last_enter_pin" class="important-prompt"></p>

+                    </div>

+                    <div class="row form-group">

+                        <label for='txtPIN' data-trans='pin' class="col-xs-3 side-right"></label>

+

+                        <div class="col-xs-6">

+                            <input id='txtPIN' name="txtPIN" autocomplete="off" data-bind="value:PIN, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control"/>

+                        </div>

+                    </div>

+                    <div class="form-buttons">

+                        <input id="btnPinApply" data-trans="apply" type="submit" formmethod="post" class="btn btn-primary "/>

+                    </div>

+                </div>

+            </div>

+        </form>

+        <form id="frmPUK" data-bind="visible:page()==pageState.WAIT_PUK">

+            <div class="form-body">

+                <div class="content">

+                    <div class="prompt">

+                        <p data-trans="enter_puk"></p>

+

+                        <p class="important-prompt" data-bind="visible:pukNumber()>1">

+                            <span data-trans="attempts_left"></span> <span data-bind='text:pukNumber'></span>

+                        </p>

+

+                        <p data-bind="visible:pukNumber()==1" data-trans="last_enter_puk" class="important-prompt"></p>

+                    </div>

+                    <div class="row form-group">

+                        <label data-trans='puk' for='txtPUK' class="col-xs-3 side-right"></label>

+

+                        <div class="col-xs-6">

+                            <input id='txtPUK' name="txtPUK" autocomplete="off" data-bind="value:PUK, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control"/>

+                        </div>

+                    </div>

+                    <div class="row form-group">

+                        <label data-trans='new_pin' for='txtNewPIN' class="col-xs-3 side-right"></label>

+

+                        <div class="col-xs-6">

+                            <input id='txtNewPIN' name="txtNewPIN" autocomplete="off" data-bind="value:newPIN, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control"/>

+                        </div>

+                        <div class="clear"></div>

+                    </div>

+                    <div class="row form-group">

+                        <label data-trans='confirm_pin' for='txtConfirmPIN' class="col-xs-3 side-right"></label>

+

+                        <div class="col-xs-6">

+                            <input id='txtConfirmPIN' name="txtConfirmPIN" autocomplete="off" data-bind="value:confirmPIN, valueUpdate: 'keypress'" maxlength='8' type="password" class="required form-control"/>

+                        </div>

+                        <div class="clear"></div>

+                    </div>

+                    <div class="form-buttons">

+                        <input id="btnPUKApply" data-trans="apply" type="submit" formmethod="post" class="btn btn-primary"/>

+                    </div>

+                </div>

+            </div>

+        </form>

+        <div class="content" data-bind="visible:page()==pageState.PUK_LOCKED">

+            <div data-trans="no_sim_card_message" class="colorRed font18"></div>

+        </div>

+    </div>

+</div>

+<div data-bind="visible: isHomePage" class="row margin-top-50">

+    <div class="type_items" style="margin:0px 0px 0px 35px">

+		<ul>

+			<li><a data-trans="station_info" href="#conn_device"></a></li>

+			<li><a data-trans="wifi_wireless_settings" href="#wlan_main"></a></li>

+			<li><a data-bind="visible: hasParentalControl()" data-trans="parental_control" href="#child_ctl"></a></li>

+			<li><a data-bind="visible: hasSms" data-trans="sms" href="#msg_main"></a></li>

+			<li><a data-bind="visible: hasPhonebook" data-trans="phonebook" href="#pb_main"></a></li>

+			<li><a data-bind="visible: isSupportSD" data-trans="sd" href="#sdcard"></a></li>

+			<li><a data-trans="advanced_settings" href="#wlan_sleep"></a></li>

+			<!--li data-bind="visible: showNetSettings"><a href="#network_set" data-trans="settings_internet"></a></li-->

+		</ul>

+	</div>

+	<div id="h_qrcode" data-bind="visible: showQRCode" style="float:right" class="text-center margin-top-15">

+		<img id="qrcode_img" data-bind="attr: {src: qrcodeSrc}" src="./pic/res_blacktrans.png" width="111"/>

+	</div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/sms_list.html b/ap/app/zte_webui_min/subpg/sms_list.html
new file mode 100755
index 0000000..9c84dd5
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/sms_list.html
@@ -0,0 +1,348 @@
+<div id="innerContainer">

+<div class="row header-row">

+    <div class="col-xs-1">

+        <a id="sms_nav_home" href="#main">

+            <img alt="" src="pic/direct-back.png">

+        </a>

+        <!--a href="javascript: void(0)" onclick="chatCancelClickHandler();" style="display: none;" id="sms_nav_back">

+            <img alt="" src="pic/direct-back.png">

+        </a-->

+    </div>

+    <div class="col-xs-11">

+        <div class="form-title">

+            <h1><span data-trans="smslist"></span> <span id="smsCapability"></span></h1>

+        </div>

+    </div>

+</div>

+<div class="row">

+<div class="col-xs-2">

+    <div class="nav_right">

+		<ul>

+		    <li class="active"><a data-trans="device" href="#msg_main"></a></li>

+			<li><a data-trans="sim" href="javascript: void(0)" onclick="toOtherClickHandler('#msg_sim');"></a></li>

+			<li><a data-trans="setting" href="javascript: void(0)" onclick="toOtherClickHandler('#msg_set');"></a></li>

+		</ul>

+	</div>

+</div>

+<div class="col-xs-10">

+

+<script type="text/x-jquery-tmpl" id="smsMeTmpl">

+    <div id="talk-item-${id}" class="talk-item talk-b">

+        <div class="layout grid-talk">

+            <div class="col-main">

+                <div class="info-talk">

+                    {{if tag == 3}}

+                    <div class="msg_container msg_fail">

+                        <s class="arrow"></s>

+                        <div class="J_content"><pre>{{html dealContent(content, id)}}</pre></div>

+                    </div>

+                    {{else}}

+                    <div class="msg_container msg">

+                        <s class="arrow"></s>

+                        <div class="J_content"><pre>{{html dealContent(content, id)}}</pre></div>

+                    </div>

+                    {{/if}}

+                    <div class="time padding-top-10">

+                        <div class="smslist-item-time pull-right paddingTop4 padding-right-10">${time}</div>

+                        <div class="hiddenButton">

+                            <div onclick="forwardClickHandler('${id}')" class="smslist-item-repeat cursorhand pull-right marginRight6 padding-right-10">

+                                <span class="sms-forward-icon padding-right-10"></span>

+                            </div>

+                            <div onclick="deleteSingleItemClickHandler('${id}')" target="${number}" class="smslist-item-delete padding-right-10 pull-right cursorhand  marginRight6">

+                                <span class="trash-icon cursorhand  padding-right-10"></span>

+                            </div>

+                        </div>

+                        {{if tag == 3}}

+                        <div onclick="resendClickHandler('${id}')" target="${target}" class="smslist-item-resend cursorhand pull-right marginRight6">

+                            <span class="sms-resend-icon cursorhand padding-right-10 marginbottom5"></span>

+                        </div>

+                        {{/if}}

+                        <div class="pull-right marginRight6 paddingTop4 error padding-right-10">${errorText}</div>

+						{{if targetName}}

+                        <div class="pull-right marginRight6 paddingTop4 padding-right-10"><span data-trans="sms_to"></span> ${targetName}</div>

+						{{/if}}

+                    </div>

+                </div>

+            </div>

+        </div>

+    </div>

+</script>

+<script type="text/x-jquery-tmpl" id="smsOtherTmpl">

+<div id="talk-item-${id}" class="talk-item talk-a">

+	<div class="layout grid-talkf">

+		<div class="col-main">

+			<div class="info-talk">

+				<div class="msg_container msg">

+					<s class="arrow"></s>

+					<div class="J_content"><pre>{{html dealContent(content)}}</pre></div>

+				</div>

+				<div class="time padding-top-10">

+					<div class="smslist-item-time pull-left paddingleft10 marginRight6 paddingTop4">${time}</div>

+					<div class="hiddenButton">

+						<div onclick="forwardClickHandler('${id}')" class="smslist-item-repeat paddingleft10 cursorhand pull-left">

+							<span class="sms-forward-icon pull-left paddingleft10"></span>

+						</div>

+						<div onclick="deleteSingleItemClickHandler('${id}')" target="${number}" class="smslist-item-delete cursorhand pull-left  marginRight6">

+							<span class="trash-icon smslist-item-delete cursorhand"></span>

+						</div>

+					</div>

+					<div class="pull-left paddingTop4 error">

+					</div>

+				</div>

+			</div>

+		</div>

+	</div>

+</div>

+</script>

+<script type="text/x-jquery-tmpl" id="addPhonebookTmpl">

+<div class="tagPopup">

+	<div id="innerTagPopup" class="popup tag-popup">

+		<div class="popup-wrapper">

+			<p class="tag-popup-close">

+				<a href="javascript:hidePopup();"></a>

+			</p>

+			<form id="quickSaveContactForm">

+				<p><span data-trans="name"></span><i class='text-danger'>&nbsp;*</i></p><p><input id="name" name="name" type="text" value="" class="required"/></p>

+				<p><span data-trans="send_numbers"></span><i class='text-danger'>&nbsp;*</i></p><p><input id="number" name="number" type="text" value="${number}" maxlength="40" class="required"/></p>

+				<p class="text-right"><input data-trans="save" type="submit" formmethod="post" class="btn btn-primary"/></p>

+			</form>

+		</div>

+	</div>

+</div>

+</script>

+<div id="smsChatRoom">

+	<div id="chosenUser">

+		<div id="chosenUserList">

+			<select id="chosenUserSelect" multiple class="chosen-select-deselect"></select>

+

+	    </div>

+    </div>

+    <h2 id="chosenUser1" class="hide"></h2>

+	<div id="chatpanel">

+		<div class="clear-container">

+			<div id="chatlist">

+				

+			</div>

+		</div>

+	</div>

+	<div id="inputpanel">

+		<div class="chatform">

+			<div class="chattextinput">

+				<textarea id="chat-input" data-trans="chat_input_placehoder" class="form-control"></textarea>

+			</div>

+			<div class="chatfun row">

+				<div id="toolbar" class="ext col-xs-8">

+					<span><em id="inputcount">(0/765)</em> <em id="inputItemCount">(1/5)</em></span>

+					<span id="sendSmsErrorLi" data-action="sendimage" class="error"></span>

+				</div>

+				<div class="col-xs-4 text-right">

+                    <span><input id="btn-send" data-trans="send" onclick="sendSmsClickHandler()" type="button" class="btn btn-primary"/></span>

+					<span><input id="btn-back" data-trans="back" onclick="chatCancelClickHandler()" type="button" class="btn btn-primary"/></span>

+				</div>

+			</div>

+		</div>

+	</div>

+</div>

+<script type="text/x-jquery-tmpl" id="smsTableTmpl">

+{{each(i, sms) data }}

+    <tr class="smslist-item ${!hasDraft && newCount > 0 ? 'font-weight-bold':''}" {{if hasDraft && groupId != ''}}id="smslist-item-${groupId}"{{else}}id="smslist-item-${itemId}"{{/if}}>

+        <td>

+            <div class="smslist-item-checkbox">

+                <p class="checkbox" id="${id}">

+                    <input type="checkbox" target="smslist-checkAll" name="smsid" id="checkbox${id}" value="${id}" groupid="${groupId}" number="${number}"/>

+                </p>

+            </div>

+        </td>

+        <td {{if hasDraft && groupId != ''}} 1onclick="draftSmsItemClickHandler('${groupId}')" {{else}} 1onclick="smsItemClickHandler('${number}')" class="${hasDraft && newCount > 0 ? 'font-weight-bold':''}"{{/if}} style="padding:8px 0px;">

+            {{if hasDraft && groupId != ''}}

+                <div class="smslist-item-name" title="${draftShowNameTitle}">

+                    <div class="smslist-item-name-draftShowName">${draftShowName}</div>

+                    <span class="smslist-item-total-count">(${totalCount})</span>

+                </div>

+            {{else}}

+                {{if name.length == 0}}

+                    {{if number.length > 13}}

+                        <span class="smslist-item-name2">${number.substring(0,13)+"..."}</span> 

+						<span id="listNumber${itemId}" onclick="openPhoneBook(null, '${number}')" class="sms-add-contact-icon cursorhand"></span>

+                    {{else}}

+                        <span class="smslist-item-name2">${number}</span> 

+						<span id="listNumber${itemId}" onclick="openPhoneBook(null, '${number}')" class="sms-add-contact-icon cursorhand"></span>

+                    {{/if}}

+                {{else}}

+				    {{if name.length > 11}}

+					    <span class="smslist-item-name2">${name.substring(0,11)+"..."}</span>

+					{{else}}

+					    <span class="smslist-item-name2">${name}</span>

+					{{/if}}                    

+                {{/if}}

+                <span class="smslist-item-total-count">(${totalCount})</span>

+            {{/if}}

+        </td>

+        <td class="cursorhand" {{if hasDraft && groupId != ''}}onclick="draftSmsItemClickHandler('${groupId}')" title='${content}'{{else}}onclick="smsItemClickHandler('${number}')" title='${latestSms}'{{/if}}>

+            {{if hasDraft && groupId != ''}}

+                <div class="sms-table-content smslist-item-msg"><span data-trans="draft" class="smslist-item-draft-flag colorRed"></span>: ${content}</div>

+            {{else}}

+                <div class="sms-table-content smslist-item-msg">{{if hasDraft}}<span data-trans="draft" class="smslist-item-draft-flag colorRed"></span>: {{/if}}${latestSms}</div>

+            {{/if}}

+        </td>

+        <td><span class="clock-time" style="white-space: nowrap;">${latestTime}</span></td>

+    </tr>

+{{/each}}

+</script>

+<script type="text/x-jquery-tmpl" id="smsListTmpl">

+	{{each(i, sms) data }}

+        {{if hasDraft && groupId != ''}}

+        <div class="height115 width100p smslist-item" id="smslist-item-${groupId}">

+            <table class="width100p height100p">

+                <tbody>

+                <tr>

+                    <td class="vMiddle width20">

+                        <div class="smslist-item-checkbox">

+                            <p class="checkbox" id="${id}">

+                                <input type="checkbox" target="smslist-checkAll" name="smsid" id="checkbox${id}" value="${id}" groupid="${groupId}" />

+                            </p>

+                        </div>

+                    </td>

+                    <td  style="width:823px;">

+                        <table width="100%">

+                            <tr>

+                                <td style="width:740px;">

+                                    <div onclick="draftSmsItemClickHandler('${groupId}')" title="${draftShowNameTitle}" class="smslist-item-name  side-left txtBold  cursorhand">

+                                        <div class="smslist-item-name-draftShowName"><span>${draftShowName}</span></div>

+                                        <div class="smslist-item-total-count smslist-item-total-count-style">(${totalCount})</div>

+                                    </div>

+                                </td>

+                                <td><div data-trans="draft" class="smslist-item-draft-flag pull-right padding-right-10  text-right text-danger"></div></td>

+                            </tr>

+                        </table>

+                    </td>

+                </tr>

+                <tr class="margin-top-10">

+                    <td class="vMiddle width20">&nbsp;</td>

+                    <td onclick="draftSmsItemClickHandler('${groupId}')" class="font10px lh20px">

+                        <div class="smslist-item-msg cursorhand">

+                            <pre class="lh20px">${content}</pre>

+                        </div>

+                    </td>

+                </tr>

+                <tr class="margin-top-10">

+                    <td class="vMiddle width20">&nbsp;</td>

+                    <td class="height30 clock-time">

+                        <div class="margin-top-10 height30 pull-left margin-right-5">

+                            <span class="clock-icon pull-left margin-right-5"></span>

+                            <span class="clock-time">${latestTime}</span>

+                        </div>

+                    </td>

+                </tr>

+                </tbody>

+            </table>

+        </div>

+        {{else}}

+        <div id="smslist-item-${itemId}" class="height115 width100p smslist-item">

+            <table class="width100p height100p">

+                <tbody>

+                    <tr>

+                        <td class="vMiddle width20">

+                            <div class="smslist-item-checkbox">

+                                <p id="${id}" class="checkbox">

+                                    <input id="checkbox${id}" name="smsid" type="checkbox" target="smslist-checkAll" value="${id}" number="${number}" ${checked ? "checked=checked" : ""} />

+                                </p>

+                            </div>

+                        </td>

+                        <td>

+                            {{if name.length == 0}}

+                            <div onclick="smsItemClickHandler('${number}')" class="smslist-item-name pull-left txtBold cursorhand"><span>${number}</span></div>

+                            <div style="float:left;" onclick="smsItemClickHandler('${number}')" class="smslist-item-total-count pull-left txtBold">(${totalCount})</div>

+                            <div id="listNumber${itemId}" style="line-height: 35px; width:30px;" class="pull-left cursorhand padding-top-10"><span onclick="openPhoneBook(null, '${number}')" class="sms-add-contact-icon"></span></div>

+                            <div class="smslist-item-new-count cursorhand pull-right ${newCount > 0?'':'hide'}" onclick="smsItemClickHandler('${number}')"><span>${newCount}</span></div>

+                            {{else}}

+                            <div class="smslist-item-name pull-left txtBold cursorhand" onclick="smsItemClickHandler('${number}')"><span>${name}/${number}</span></div><div onclick="smsItemClickHandler('${number}')" class="smslist-item-total-count pull-left txtBold">(${totalCount})</div><div class="smslist-item-new-count cursorhand pull-right ${newCount > 0?'':'hide'}" onclick="smsItemClickHandler('${number}')"><span>${newCount}</span></div>

+                            {{/if}}

+                            <div class="smslist-item-draft-flag padding-right-10 pull-right text-danger ${hasDraft?'':'hide'}"><span data-trans="draft"></span></div>

+                        </td>

+                    </tr>

+                    <tr class="margin-top-10">

+                        <td class="vMiddle width20">&nbsp;</td>

+                        <td onclick="smsItemClickHandler('${number}')" class="font10px lh20px">

+                            <div class="smslist-item-msg cursorhand">

+                                <pre class="lh20px ${newCount > 0?'txtBold':''}">${latestSms}</pre>

+                            </div>

+                        </td>

+                    </tr>

+                    <tr class="margin-top-10">

+                        <td class="vMiddle width20">&nbsp;</td>

+                        <td class="height30 clock-time">

+                            <div style="display:none;" class="smslist-item-repeat margin-top-10 cursorhand pull-left marginright30">

+                                <span onclick="forwardClickHandler(${latestId})" class="sms-forward-icon pull-left"></span>

+                            </div>

+                            <div style="display:none;" class="smslist-item-delete margin-top-10 height30 cursorhand pull-left marginright30">

+                                <span onclick="deletePhoneMessageClickHandler('${number}')" class="trash-icon pull-left"></span>

+                            </div>

+                            <div class="margin-top-10 height30 pull-left margin-right-5">

+                                <span class="clock-icon pull-left margin-right-5"></span>

+                                <span class="clock-time">${latestTime}</span>

+                            </div>

+                        </td>

+                    </tr>

+                </tbody>

+            </table>

+        </div>

+        {{/if}}

+	{{/each}}

+</script>

+<div id="smslist-main">

+    <!--div class="form-title">

+        <h1><span data-trans="smslist"></span> <span id="smsCapability"></span></h1>

+    </div-->

+	<form id="smsListForm">

+		<div class="smslist-btns">

+            <div class="row">

+                <div class="col-xs-6">

+                    <!--div class="pull-left padding-right-15 margin-top-10">

+                        <p id="smslist-checkAll" target="smslist_container" class="checkbox checkboxToggle pull-left margin-top-10">

+                            <input id="checkbox-all" type="checkbox" />

+                        </p>

+                    </div-->

+                    <div class="margin-left-10">

+                        <input id="smslist-new-sms" onclick="newMessageClickHandler()" type="button" data-trans="new" class="btn btn-primary"/>

+                        <input id="smslist-delete" disabled="disabled" data-trans="delete" onclick="deleteSelectClickHandler()" type="button" class="btn btn-primary disabled"/>

+                        <input id="smslist-delete-all" disabled="disabled" data-trans="delete_all" onclick="deleteAllClickHandler()" style="display: none;" type="button" class="btn  disabled marginright10"/>

+                        <input id="smslist-refresh" data-trans="refresh" onclick="refreshClickHandler()" type="button" class="btn btn-primary"/>

+                        <!--a href="#msg_set" id="smslist-setting" class="btn btn-primary" data-trans="setting"></a-->

+                    </div>

+                </div>

+                <div class="col-xs-6 text-right" style="display:none">

+					<div class="row">

+							<div class='ko-grid-search'>

+								<img src='./pic/res_search.png'>

+								<input id='searchInput' autocomplete='off' data-trans='search' maxlength="20" onclick="searchTextClick()" type='text' class='ko-grid-search-txt-default width102 noDefaultFocus form-control'/>

+								<img id="clearSearchKey" onclick="clearSearchKey()" src='./pic/res_delete.png' class='cursor-pointer'/>

+							</div>

+				    </div>	

+                </div>

+            </div>

+		</div>

+		<div id="addPhonebookContainer" style="position: relative;" class="width100p overflow-only-y">

+			<div id="smslist_container" class="jspContainer width100p height100p"></div>

+            <table class="table table-striped table-hover ko-grid table-fixed">

+                <thead>

+                <tr>

+                    <th width="20" class="text-center">

+                        <p id="smslist-checkAll" target="smslist-table" class="checkbox checkboxToggle">

+                            <input id="checkbox-all" type="checkbox"/>

+                        </p>

+                    </th>

+                    <th data-trans="phone_number" class="text-center"></th>

+                    <th width="450" data-trans="content" class="text-center"></th>

+                    <th width="150" data-trans="time" class="text-center"></th>

+                </tr>

+                </thead>

+                <tbody id="smslist-table">

+                </tbody>

+            </table>

+		</div>

+	</form>

+</div>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/sms_set.html b/ap/app/zte_webui_min/subpg/sms_set.html
new file mode 100755
index 0000000..038bf97
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/sms_set.html
@@ -0,0 +1,75 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1 data-trans='sms_setting'></h1>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+			<div class="nav_right">

+				<ul>

+					<li><a data-trans="device" href="#msg_main"></a></li>

+					<li><a data-trans="sim" href="#msg_sim"></a></li>

+					<li class="active"><a data-trans="setting" href="#msg_set"></a></li>

+				</ul>

+			</div>

+		</div>

+		<div class="col-xs-10">

+

+

+<form id='smsSettingForm'>

+    <div class="form-body">

+        <div class="content">

+		    <h3 data-trans="sms_setting" class="form-title"></h3>

+            <div class="row form-group">

+                <label data-trans='sms_validity' for='txtValidity' class="col-xs-3 side-right"></label>

+                <div class="col-xs-5">

+                    <select id="txtValidity" data-transid='sms_validity' data-bind="options: modes, value: selectedMode, optionsText: transOption('sms_validity'), optionsValue: 'value'" class="form-control"></select>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label data-trans='center_number' for='txtCenterNumber' class="col-xs-3 side-right"></label>

+                <div class="col-xs-5">

+                    <input id='txtCenterNumber' data-bind="value: centerNumber" maxlength='40' name="txtCenterNumber" type="text" class="required form-control"/>

+                </div>

+            </div>

+            <div class="row form-group">

+                <label data-trans='delivery_report' class="col-xs-3 side-right"></label>

+                <div class="col-xs-5">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="reportOn" data-bind="checked: deliveryReport" name="deliveryReport" type="radio" value="1"/>

+                            <label data-trans="enable" for="reportOn"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="reportOff" data-bind="checked: deliveryReport" name="deliveryReport" type="radio" value="0"/>

+                            <label data-trans="disable" for="reportOff"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+            <!--input type="button" class="btn" data-bind='click: clear' data-trans='cancel'/-->

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="sms_setting_note_validity"></li>

+                <li data-trans="sms_setting_note_center_number"></li>

+                <li data-trans="sms_setting_note_delivery_report"></li>

+            </ul>

+        </div>

+    </div>

+</form> 

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/sms_sim_messages.html b/ap/app/zte_webui_min/subpg/sms_sim_messages.html
new file mode 100755
index 0000000..f35b55d
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/sms_sim_messages.html
@@ -0,0 +1,99 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title">

+                <h1><span data-trans="sim_messages"></span> <span id="simSmsCapability"></span></h1>                

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+			<div class="nav_right">

+				<ul>

+					<li><a data-trans="device" href="#msg_main"></a></li>

+					<li class="active"><a data-trans="sim" href="#msg_sim"></a></li>

+					<li><a data-trans="setting" href="#msg_set"></a></li>

+				</ul>

+			</div>

+		</div>

+		<div class="col-xs-10">

+

+

+<div id="simMsglist-main">

+    <form id="simMsgListForm">

+        <div class="simMsgList-btns smslist-btns">

+            <div class="row">

+                <div class="col-xs-6">

+                    <input id="simMsgList-delete" disabled="disabled" data-trans="delete" onclick="deleteSelectedSimMsgClickHandler()" type="button" class="btn btn-primary disabled"/>

+                </div>

+				<div style="display:none" class="col-xs-6 text-right">

+					<div class="row">

+							<div class='ko-grid-search'>

+								<img src='./pic/res_search.png'>

+								<input id='searchInput' autocomplete='off' data-trans='search' maxlength="20" onclick="searchTextClick()" type='text' class='ko-grid-search-txt-default width102 noDefaultFocus form-control'/>

+								<img id="clearSearchKey" onclick="clearSearchKey()" src='./pic/res_delete.png' class='cursor-pointer'/>

+							</div>

+				    </div>	

+                </div>

+            </div>

+        </div>

+        <div id="simMsgTableContainer" class="width100p overflow-only-y">

+            <table class="table table-striped table-hover ko-grid table-fixed">

+                <thead>

+                <tr>

+                    <th width="20" class="text-center">

+                        <p id="simMsgList-checkAll" target="simMsgList_container" class="checkbox checkboxToggle">

+                            <input id="checkbox-all" type="checkbox"/>

+                        </p>

+                    </th>

+                    <th data-trans="phone_number" class="text-center"></th>

+                    <th data-trans="content" width="450" class="text-center"></th>

+                    <th data-trans="time" width="150" class="text-center"></th>

+                </tr>

+                </thead>

+                <tbody id="simMsgList_container">

+                </tbody>

+            </table>

+        </div>

+    </form>

+</div>

+    </div>

+</div>

+</div>

+<script id="simMsgListTmpl" type="text/x-jquery-tmpl">

+{{each(i, sms) data }}

+    <tr class="smslist-item simMsgList-item-class-${id} ${tag == "1" ? 'font-weight-bold':''}" id="simMsgList-item-${itemId}">

+        <td>

+            <div class="smslist-item-checkbox">

+                <p class="checkbox" id="${id}">

+                    <input type="checkbox" target="simMsgList-checkAll" name="msgId" id="checkbox${id}" value="${id}" number="${number}" number="${number}" />

+                </p>

+            </div>

+        </td>

+        <td>

+            {{if name.length == 0}}

+                {{if number.length > 13}}

+                    <div class="smslist-item-name pull-left">${number.substring(0,13)+"..."}</div>

+                {{else}}

+                     <div class="smslist-item-name pull-left">${number}</div>

+                {{/if}}

+            {{else}}

+                {{if name.length > 11}}

+                    <div class="smslist-item-name pull-left">${name.substring(0,11)+"..."}</div>

+                {{else}}

+                    <div class="smslist-item-name pull-left">${name}</div>

+                {{/if}}                

+            {{/if}}

+        </td>

+        <td class="cursorhand" title="${content}" onclick="simsmsItemClickHandler('${tag}','${id}','${itemId}')">

+            <div class="sms-table-content smslist-item-msg">${content}</div>

+        </td>

+        <td style="padding:8px 0px;"><span class="clock-time ${tag==2||tag==3?'hide':''}" style="white-space: nowrap;">${time}</span></td>

+    </tr>

+{{/each}}

+</script>

diff --git a/ap/app/zte_webui_min/subpg/status.html b/ap/app/zte_webui_min/subpg/status.html
new file mode 100755
index 0000000..a53b32c
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/status.html
@@ -0,0 +1,3 @@
+<p>

+status

+</p>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/status_traffic_alert.html b/ap/app/zte_webui_min/subpg/status_traffic_alert.html
new file mode 100755
index 0000000..83ec78b
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/status_traffic_alert.html
@@ -0,0 +1,236 @@
+<div id="innerContainer">

+<div class="row header-row">

+    <div class="col-xs-1">

+        <a href="#main">

+            <img alt="" src="pic/direct-back.png">

+        </a>

+    </div>

+    <div class="col-xs-11">

+        <div class="form-title form-title-multi">

+            <h1 data-trans='traffic_alert'></h1>

+            <p data-trans="traffic_sub_title"></p>

+        </div>

+    </div>

+</div>

+<div class="row">

+<div class="col-xs-1 margin-top-15">

+</div>

+<div class="col-xs-11">

+

+<form id="trafficAlertForm">

+<div id="traffic_alert" class="form-body">

+	<div class="content">

+		<div class="row form-group">

+			<label data-trans="traffic_apply_volume_limit" class="col-xs-3 side-right"></label>

+            <div class="col-xs-6">

+                <div class="row">

+                    <div class="col-xs-4">

+                        <input id="dataLimitEnable" name="dataLimitEnable" data-bind="checked: dataLimitChecked" type="radio" value="1"/>

+                        <label data-trans="enable" for="dataLimitEnable"></label>

+                    </div>

+                    <div class="col-xs-4">

+                        <input id="dataLimitDisable" name="dataLimitEnable" data-bind="checked: dataLimitChecked" type="radio" value="0"/>

+                        <label data-trans="disable" for="dataLimitDisable"></label>

+                    </div>

+                </div>

+            </div>

+		</div>

+        <div data-bind='visible: dataLimitChecked() == "1"' class="row form-group">

+			<label data-trans="traffic_data_limit_type" class="col-xs-3 side-right"></label>

+            <div class="col-xs-6">

+                <div class="row">

+                    <div class="col-xs-4">

+                        <input id="dataLimitTypeData" name="dataLimitType" data-bind="checked: dataLimitTypeChecked" type="radio" value="1"/>

+                        <label data-trans="traffic_data" for="dataLimitTypeData"></label>

+                    </div>

+                    <div class="col-xs-4">

+                        <input id="dataLimitTypeTime" name="dataLimitType" data-bind="checked: dataLimitTypeChecked" type="radio" value="0"/>

+                        <label data-trans="traffic_time" for="dataLimitTypeTime"></label>

+                    </div>

+                </div>

+            </div>

+		</div>

+        <div class="row form-group" data-bind='visible: dataLimitChecked() == "1"'>

+            <div class="col-xs-4">

+                <div id="traffic_graphic" style="width: 200px; height: 200px; visibility: visible;"></div>

+            </div>

+            <div class="col-xs-8 line-height-40 form-inline form-group-sm">

+                <div data-bind="visible: dataLimitTypeChecked() == 1">

+                    <div>

+                        <div data-bind="visible: viewEditUsedData() == false">

+                            <span style="background-color: #8CC916;" class="color_block"></span>

+                            <span data-trans="traffic_used_text" data-bind="html: usedDataTextDesc, attr:{'data-trans-data': usedDataTextDescData}"></span>

+                            <a id="editUsedData" data-bind="click: editUsedDataHandler" class="margin-left-3em cursorhand"><img src="./pic/res_edit.png"></a>

+                        </div>

+                        <div data-bind="visible: viewEditUsedData" id="viewEditUsedData">

+                            <span class="color_block" style="background-color: #8CC916;"></span>

+                            <input id='dataUsed' name="dataUsed"  data-bind="value: dataUsed" maxlength='7' minlength='1' style="width: 100px;" type="text" class="required form-control border-color-transition"/>

+                            <select name="selectedDataUsedUnit" id="selectedDataUsedUnit" data-bind="value: selectedDataUsedUnit" class="width60 form-control" style="width: 80px;">

+                                <option value="1">MB</option>

+                                <option value="1024">GB</option>

+                                <option value="1048576">TB</option>

+                            </select>

+                            <a id="editUsedDataSave" data-bind="click: editUsedDataSaveHandler" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a id="editUsedDataCancel" data-bind="click: editUsedDataCancelHandler" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                            <div id="editUsedDataDiv"></div>

+                        </div>

+                    </div>

+                    <div>

+                        <span style="background-color: #ccc;" class="color_block"></span>

+                        <span data-trans="traffic_data_left_text" data-bind="text: leftDataDesc, attr:{'data-trans-data': leftDataDescData}"></span>

+                    </div>

+                    <div>

+                        <div data-bind="visible: viewEditAlertData() == false">

+                            <span data-trans="traffic_alert_reach_text" data-bind="text: alertDataReachDesc, attr:{'data-trans-data': alertDataReachDescData}"></span>

+                            <a id="editAlertData" data-bind="click: editAlertDataHandler" class="margin-left-3em cursorhand"><img src="./pic/res_edit.png"></a>

+                        </div>

+                        <div id="viewEditAlertData" data-bind="visible: viewEditAlertData">

+                            <span data-trans="traffic_when"></span>

+                            <input id='alertDataReach' name="alertDataReach" data-bind="value: alertDataReach" max="100" maxlength='3' min="1" minlength='1' style="width: 60px;" type="text" class="required form-control border-color-transition"/>

+                            <span data-trans="traffic_remind_me"></span>

+                            <a id="save_btn_2" data-bind="click: editAlertDataSaveHandler" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a id="editAlertDataCancel" data-bind="click: editAlertDataCancelHandler" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                            <div id="editAlertDataDiv"></div>

+                        </div>

+                    </div>

+                    <div>

+                        <div data-bind="visible: viewEditTotalData() == false">

+                            <span data-trans="traffic_limit_data_text" data-bind="html: limitDataMonthDesc, attr:{'data-trans-data': limitDataMonthDescData}"></span>

+                            <a class="margin-left-3em cursorhand" id="editTotalData" data-bind="click: editTotalDataHandler"><img src="./pic/res_edit.png"></a>

+                        </div>

+                        <div data-bind="visible: viewEditTotalData" id="viewEditTotalData">

+                            <input id='limitDataMonth' name="limitDataMonth" data-bind="value: limitDataMonth" maxlength='7' minlength='1' style="width: 100px;" type="text" class="required form-control border-color-transition"/>

+                            <select id="selectedDataUnit" name="dataUnit" data-bind="value: selectedDataUnit" style="width: 80px;" class="width60 form-control">

+                                <option value="1">MB</option>

+                                <option value="1024">GB</option>

+                                <option value="1048576">TB</option>

+                            </select>

+                            <a id="save_btn_1" data-bind="click: editTotalDataSaveHandler" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a id="editTotalDataCancel" data-bind="click: editTotalDataCancelHandler" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                            <div id="editTotalDataDiv"></div>

+                        </div>

+                    </div>

+                </div>

+                <div data-bind="visible: dataLimitTypeChecked() == 0">

+                    <div>

+                        <div data-bind="visible: viewEditUsedTime() == false">

+                            <span style="background-color: #8CC916;" class="color_block"></span>

+                            <span data-trans="traffic_used_text" data-bind="html: usedTimeTextDesc, attr:{'data-trans-data': usedTimeTextDescData}"></span>

+                            <a id="editUsedTime" data-bind="click: editUsedTimeHandler" class="margin-left-3em cursorhand"><img src="./pic/res_edit.png"></a>

+                        </div>

+                        <div data-bind="visible: viewEditUsedTime">

+                            <span class="color_block" style="background-color: #8CC916;"></span>

+                            <!--div class="input-group"-->

+                                <input id='usedTime' name="usedTime" data-bind="value: usedTime" maxlength='7' minlength='1' style="width: 100px;" type="text" class="required form-control border-color-transition"/>

+                                <!--div class="input-group-addon" data-trans="hours"></div-->

+								<select id="selectedTimeUsedUnit" name="selectedTimeUsedUnit" data-bind="value: selectedTimeUsedUnit" style="width: 100px;" class="width60 form-control">

+                                    <option data-trans="minutes" value="60"></option>

+                                    <option data-trans="hours" value="3600"></option>

+                                </select>

+                            <!--/div-->

+                            <a data-bind="click: editUsedTimeSaveHandler" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a id="editUsedTimeCancel" data-bind="click: editUsedTimeCancelHandler" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                            <div id="editUsedTimeDiv"></div>

+                        </div>

+                    </div>

+                    <div>

+                        <span style="background-color: #ccc;" class="color_block"></span>

+                        <span data-trans="traffic_data_left_text" data-bind="text: leftTimeDesc, attr:{'data-trans-data': leftTimeDescData}"></span>

+                    </div>

+                    <div>

+                        <div data-bind="visible: viewEditAlertTime() == false">

+                            <span data-trans="traffic_alert_reach_text" data-bind="text: alertTimeReachDesc, attr:{'data-trans-data': alertTimeReachDescData}"></span>

+                            <a id="editAlertTime" data-bind="click: editAlertTimeHandler" class="margin-left-3em cursorhand"><img src="./pic/res_edit.png"></a>

+                        </div>

+                        <div data-bind="visible: viewEditAlertTime">

+                            <span data-trans="traffic_when"></span>

+                            <div class="input-group">

+                                <input id='alertTimeReach' name="alertTimeReach" type="text" data-bind="value: alertTimeReach" max="100" maxlength='3' min="1" minlength='1' style="width: 60px;" class="required form-control border-color-transition"/>

+                                <div data-trans="traffic_percent" class="input-group-addon"></div>

+                            </div>

+                            <span data-trans="traffic_remind_me_time"></span>

+                            <a data-bind="click: editAlertTimeSaveHandler" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a id="editAlertTimeCancel" data-bind="click: editAlertTimeCancelHandler" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                            <div id="editAlertTimeDiv"></div>

+                        </div>

+                    </div>

+                    <div>

+                        <div data-bind="visible: viewEditTotalTime() == false">

+                            <span  data-bind="text: limitTimeMonthDesc, attr:{'data-trans':limitTimeMonthDescText,'data-trans-data': limitTimeMonthDescData}"></span>

+                            <a id="editTotalTime" data-bind="click: editTotalTimeHandler" class="margin-left-3em cursorhand"><img src="./pic/res_edit.png"></a>

+                        </div>

+                        <div data-bind="visible: viewEditTotalTime">

+                            <!--div class="input-group"-->

+                                <input id='limitTimeMonth' name="limitTimeMonth" data-bind="value: limitTimeMonth" maxlength='7' minlength='1' style="width: 100px;" type="text" class="required form-control border-color-transition"/>

+                                <!--div class="input-group-addon" data-trans="hours"></div-->

+							<select id="selectedTimeUnit" name="timeUnit" data-bind="value: selectedTimeUnit" style="width: 100px;" class="width60 form-control">

+                                <option data-trans="minutes" value="60"></option>

+                                <option data-trans="hours" value="3600"></option>

+                            </select>

+                            <!--/div-->

+                            <a data-bind="click: editTotalTimeSaveHandler" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a id="editTotalTimeCancel" data-bind="click: editTotalTimeCancelHandler" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                            <div id="editTotalTimeDiv"></div>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <!--div style="display: none;" class="col-xs-8">

+                <div data-bind='visible: dataLimitChecked() == "1" && dataLimitTypeChecked() != "0"' class="row">

+                    <label for='limitDataMonth' data-trans='traffic_limit_data_month' class="span4 side-right"></label>

+                    <div class="span8">

+                        <input id='limitDataMonth' name="limitDataMonth" data-bind="value: limitDataMonth" maxlength='4' minlength='1' type="text" class="required"/>

+                        <select id="dataUnit" name="dataUnit" data-bind="value: selectedDataUnit" class="width60">

+                            <option value="1">MB</option>

+                            <option value="1024">GB</option>

+                            <option value="1048576">TB</option>

+                        </select>

+                    </div>

+                </div>

+                <div class="row" data-bind='visible: dataLimitChecked() == "1" && dataLimitTypeChecked() != "0"'>

+                    <label data-trans='traffic_alert_when_data_reach' for='alertDataReach' class="span4 side-right"></label>

+                    <div class="span8">

+                        <input id='alertDataReach' name="alertDataReach" data-bind="value: alertDataReach" maxlength='3' minlength='1' type="text" class="required"/>

+                        <label id="traffic_data_percent" data-trans="traffic_percent"></label>

+                    </div>

+                </div>

+                <div data-bind='visible: dataLimitChecked() == "1" && dataLimitTypeChecked() != "1"' class="row">

+                    <label data-trans='traffic_limit_time_month' for='limitTimeMonth' class="span4 side-right"></label>

+                    <div class="span8">

+                        <input id='limitTimeMonth' name="limitTimeMonth" data-bind="value: limitTimeMonth" maxlength='4' minlength='1' type="text" class="required"/>

+                        <label id="hours" data-trans="hours"></label>

+                    </div>

+                </div>

+                <div data-bind='visible: dataLimitChecked() == "1" && dataLimitTypeChecked() != "1"' class="row">

+                    <label for='alertTimeReach' data-trans='traffic_alert_when_time_reach' class="span4 side-right"></label>

+                    <div class="span8">

+                        <input id='alertTimeReach' name="alertTimeReach" data-bind="value: alertTimeReach" maxlength='3' minlength='1' type="text" class="required"/>

+                        <label id="traffic_time_percent" data-trans="traffic_percent"></label>

+                    </div>

+                </div>

+            </div-->

+        </div>

+        <div class="row form-group">

+            <!--span id="noteinfo" data-trans="traffic_data_approximated"></span-->

+            <label id="noteinfo" data-trans="traffic_data_approximated" class="col-xs-12"></label>

+        </div>

+        <div class="row form-group">

+            <div class="col-xs-6"></div>

+            <div class="col-xs-6 align-right">

+                <input data-trans='apply' type="submit" formmethod="post" class="btn btn-primary margin-right-20"/>

+            </div>

+        </div>

+	</div>

+    <div class="form-note">

+        <div class="notes-title">&nbsp;</div>

+        <ul class="notes-content">

+            <li data-trans="traffic_calibrate_note"></li>

+            <li data-trans="traffic_note"></li>

+			<li data-trans="traffic_over_note"></li>

+        </ul>

+    </div>

+</div>

+</form>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/wifi_advance.html b/ap/app/zte_webui_min/subpg/wifi_advance.html
new file mode 100755
index 0000000..926baa2
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_advance.html
@@ -0,0 +1,170 @@
+<link type="text/css" href="./css/jqui.css" rel="stylesheet" />

+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title form-title-multi">

+                <h1 data-trans='wifi_wireless_settings'></h1>

+                <p data-trans="wifi_main_sub_title"></p>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		    <div class="nav_right">

+				 <ul data-bind="visible: isShowSSIDInfoDiv">

+					<li><a data-trans="multi_ssid_1" data-bind="attr:{'data-trans': hasMultiSSID ? 'multi_ssid_1':'ssid_title'}" href="#wlan_main"></a></li>

+					<li data-bind="visible: hasMultiSSID"><a data-trans="multi_ssid_2" href="#wlan_guset"></a></li>

+					<li><a data-trans="wps" href="#wlan_wps"></a></li>

+					<li data-bind="visible: hasAPStation"><a data-trans="ap_station" href="#wlan_station"></a></li>

+					<li class="active"><a data-trans="wifi_advance" href="#wlan_adv"></a></li>

+					<li data-bind="visible: hasWlanMacfilter"><a data-trans="mac_filter" href="#filter_mac"></a></li>

+				</ul>

+			</div>

+		</div>

+        <div class="col-xs-10">

+

+<div class="form-body">

+    <form id="frmWifiSwitch" role="form">

+        <div class="content margin-top-20">

+            <div data-bind="visible: hasWifiSwitch" class="row form-group">

+                <label data-trans="wifi_switch" class="col-xs-4 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_enable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="wifi_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_disable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="wifi_switch_disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div data-bind="visible: wifi_enable() == '1' && hasMultiSSID" class="row form-group">

+                <label data-trans="multi_ssid_enable" class="col-xs-4 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_enable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="multi_ssid_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_disable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="multi_ssid_switch_disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div data-bind="visible: hasWifiSwitch || (wifi_enable() == '1' && hasMultiSSID)" class="form-buttons">

+                <input id="wifi_switch_apply" data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+                <!--input id="wifi_switch_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("switch");}' data-trans='cancel'/-->

+            </div>

+        </div>

+    </form>

+

+   

+

+    <form id="wifi_advance_form" data-bind="visible: isShowSSIDInfoDiv">

+	<h3 data-bind="attr:{'data-trans': 'wifi_advance'}" class="form-title"></h3>

+	<div class="content">

+        <!--<div data-bind="visible: hasMultiSSID && origin_multi_ssid_enable == '1'">-->

+            <!--<div class="row margin-bottom-20">-->

+                <!--<div class="col-xs-12">-->

+                    <!--<span data-trans="max_station_number"></span>(<span data-bind="text: maxStationNumber"></span>)-->

+                <!--</div>-->

+            <!--</div>-->

+            <!--<div class="row">-->

+                <!--<div class="col-xs-2">-->

+                <!--</div>-->

+                <!--<div class="col-xs-8">-->

+                    <!--<div id="slider-range"></div>-->

+                <!--</div>-->

+                <!--<div class="col-xs-2">-->

+                <!--</div>-->

+            <!--</div>-->

+            <!--<div class="row margin-top-20 margin-bottom-20">-->

+                <!--<div class="col-xs-2">-->

+                <!--</div>-->

+                <!--<div class="col-xs-8">-->

+                    <!--<span class="color_block"></span>-->

+                    <!--<span class="color_block_desc margin-right-20" id="main_ssid_num"></span>-->

+                    <!--<span class="color_block" style="background-color: #4D9DF0"></span>-->

+                    <!--<span class="color_block_desc margin-right-20" id="guest_ssid_num"></span>-->

+                <!--</div>-->

+                <!--<div class="col-xs-2">-->

+                <!--</div>-->

+            <!--</div>-->

+            <!--<div class="row margin-top-20 margin-bottom-20">-->

+                <!--<div class="col-xs-12" data-trans="wifi_slider_desc">-->

+                <!--</div>-->

+            <!--</div>-->

+        <!--</div>-->

+		<div data-bind="visible: hasWifiBand()" class="row form-group">

+			<label data-trans="network_band_selection" for="band_select" class="col-xs-4 side-right"></label>

+            <div class="col-xs-6">

+                <label data-bind="visible: bands().length == 1, attr:{'data-trans': oneBandTrans}"></label>

+                <select id="band_select" data-bind="options: bands, value: selectedBand, optionsText: 'text', optionsValue: 'value', visible: bands().length > 1,event:{ change: bandChangeHandler}" name="band_select" required="true" class="form-control"></select>

+            </div>

+		</div>

+		<div class="row form-group">

+			<label id="modeLabel" data-trans="network_mode" for="mode" class="col-xs-4 side-right"></label>

+            <div class="col-xs-6">

+                <select id="mode" data-transid="network_mode_select" data-bind="options: modes, value: selectedMode, optionsText: transOption('network_mode_select'), optionsValue: 'value', event:{ change: modeChangeHandler}" name="mode" required="true" style="display:none" class="form-control"></select>

+                <label data-bind="visible: modes().length == 1, attr:{'data-trans': oneModeTrans}"></label>

+                <select id="modeFor5HZ" data-transid="network_modes_band_select" data-bind="options: modes, value: selectedMode, optionsText: transOption('network_modes_band_select'), optionsValue: 'value', event:{ change: modeChangeHandler}" name="mode" required="true" style="display:none" class="form-control"></select>

+            </div>

+		</div>

+		<div data-bind="visible: hasBandwidth()" class="row form-group">

+			<label data-trans="wifi_channel_bandwidth" for="wifi_channel_bandwidth" class="col-xs-4 side-right"></label>

+            <div class="col-xs-6">

+                <select id="wifi_channel_bandwidth" data-bind="options: channelBandwidths, value: selectedChannelBandwidth, optionsText: 'text', optionsValue: 'value'" name="channelBandwidth" required="true" class="form-control"></select>

+            </div>

+		</div>

+		<div class="row form-group">

+			<label data-trans="country_region_code" for="country" class="col-xs-4 side-right"></label>

+            <div class="col-xs-6">

+                <select id="country" data-bind="options: countries, value: selectedCountry, optionsText: 'text', optionsValue: 'value', event:{ change: countryChangeHandler}" name="country" class="form-control"></select>

+             </div>

+		</div>

+		<div class="row form-group">

+			<label data-trans="frequency_channel" class="col-xs-4 side-right" for="channel"></label>

+            <div class="col-xs-6">

+                <select id="channel" data-transid="frequency_channel" data-bind="options: channels, value: selectedChannel, optionsText: transOption('frequency_channel', true), optionsValue: 'value', visible: selectedBand() == 'b' || !hasWifiBand()" name="channel" class="form-control"></select>

+                <label data-trans='auto' data-bind="visible: selectedBand() == 'a' && hasWifiBand()"></label>

+            </div>

+		</div>

+		<div data-bind="visible: hasWifiBand() == false" class="row form-group">

+			<label data-trans="rate" for="rate" class="col-xs-4 side-right"></label>

+            <div class="col-xs-6">

+                <select id="rate" data-transid="rate" data-bind="options: rates, value: selectedRate, optionsText: transOption('rate'), optionsValue: 'value'" name="rate" class="form-control"></select>

+            </div>

+		</div>

+        <div class="form-buttons">

+            <input data-trans="apply" data-bind="disable:isF() == 1 && selectedMode() == '2'" type="submit" formmethod="post" class="btn btn-primary"/>

+        </div>

+	</div>

+

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="wifi_advanced_note_band_selection"></li>

+                <li data-trans="wifi_advanced_note_network_mode"></li>

+                <li data-trans="wifi_advanced_note_country_code"></li>

+                <li data-trans="wifi_advanced_note_frequency"></li>

+            </ul>

+        </div>

+    </form>

+</div>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/wifi_ap_station.html b/ap/app/zte_webui_min/subpg/wifi_ap_station.html
new file mode 100755
index 0000000..4e236df
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_ap_station.html
@@ -0,0 +1,237 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title form-title-multi">

+                <h1 data-trans='wifi_wireless_settings'></h1>

+                <p data-trans="wifi_main_sub_title"></p>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		    <div class="nav_right">

+		        <ul data-bind="visible: isShowSSIDInfoDiv">

+					<li><a data-trans="multi_ssid_1" data-bind="attr:{'data-trans': hasMultiSSID ? 'multi_ssid_1':'ssid_title'}" href="#wlan_main"></a></li>

+					<li data-bind="visible: hasMultiSSID"><a data-trans="multi_ssid_2" href="#wlan_guset"></a></li>

+					<li><a data-trans="wps" href="#wlan_wps"></a></li>

+					<li class="active"><a data-trans="ap_station" href="#wlan_station"></a></li>

+					<li><a data-trans="wifi_advance" href="#wlan_adv"></a></li>

+					<li data-bind="visible: hasWlanMacfilter"><a data-trans="mac_filter" href="#filter_mac"></a></li>

+				</ul>

+			</div>

+		</div>

+        <div class="col-xs-10">

+			<div class="form-body">

+				<form id="frmWifiSwitch" role="form">

+					<div class="content margin-top-20">

+						<div data-bind="visible: hasWifiSwitch" class="row form-group">

+							<label data-trans="wifi_switch" class="col-xs-4 side-right"></label>

+							<div class="col-xs-6">

+								<div class="row">

+									<div class="col-xs-4">

+										<input id="wifi_switch_enable" data-bind="checked: wifi_enable" name="wifi_switch" type="radio"

+											   value="1"/>

+										<label data-trans="enable" for="wifi_switch_enable"></label>

+									</div>

+									<div class="col-xs-4">

+										<input id="wifi_switch_disable" data-bind="checked: wifi_enable" name="wifi_switch" type="radio"

+											   value="0"/>

+										<label data-trans="disable" for="wifi_switch_disable"></label>

+									</div>

+								</div>

+							</div>

+						</div>

+						<div data-bind="visible: wifi_enable() == '1' && hasMultiSSID" class="row form-group">

+							<label data-trans="multi_ssid_enable" class="col-xs-4 side-right"></label>

+							<div class="col-xs-6">

+								<div class="row">

+									<div class="col-xs-4">

+										<input id="multi_ssid_switch_enable" data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio"

+											   value="1"/>

+										<label data-trans="enable" for="multi_ssid_switch_enable"></label>

+									</div>

+									<div class="col-xs-4">

+										<input id="multi_ssid_switch_disable" data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio"

+											   value="0"/>

+										<label data-trans="disable" for="multi_ssid_switch_disable"></label>

+									</div>

+								</div>

+							</div>

+						</div>

+						<div data-bind="visible: hasWifiSwitch || (wifi_enable() == '1' && hasMultiSSID)" class="form-buttons">

+							<input id="wifi_switch_apply" data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+							<!--input id="wifi_switch_cancel" type="button" class="btn btn-primary" data-bind='click: function(){clear("switch");}' data-trans='cancel'/-->

+						</div>

+					</div>

+				</form>

+				

+				<div data-bind="visible: isShowSSIDInfoDiv" class="content">

+					<form id='frmAPStation' role="form">

+						<div data-bind="visible:pageState() == page.list">

+							<h3 data-trans="ap_station" class="form-title"></h3>

+							<div class="content">

+								<div class="row form-group">

+									<label data-trans='ap_station_switch' class="col-xs-4 side-right"></label>

+									<div class="col-xs-6">

+                                    <div class="row">

+									<div class="col-xs-4">

+										<input id="ap_station_switch_enable" data-bind="checked: ap_station_enable" name="ap_station_switch" type="radio"

+											   value="1"/>

+										<label data-trans="enable" for="ap_station_switch_enable"></label>

+									</div>

+									<div class="col-xs-4">

+										<input id="ap_station_switch_disable" data-bind="checked: ap_station_enable" name="ap_station_switch" type="radio"

+											   value="0"/>

+										<label data-trans="disable" for="ap_station_switch_disable"></label>

+									</div>

+									</div>

+								    </div>

+								</div>

+								<div data-bind="visible:ap_station_enable()=='1'" class="row form-group">

+									<label data-trans='ap_station_current_status' class="col-xs-4 side-right"></label>

+

+									<div class="col-xs-6">

+										<span data-bind="text:current_status_text,attr:{'data-trans':current_status_trans}"></span>

+									</div>

+								</div>

+							</div>

+							<div class="form-buttons">

+								<input id="btnApply" data-trans="apply" data-bind="click:apply, disable:isCableMode() == true && ap_station_enable()=='1'" type="button" class="btn btn-primary"/>

+							</div>

+							<div data-bind="visible:ap_station_enable()=='1' && origin_ap_station_enable =='1'">

+								<h3 data-trans="ap_station_hotspot_list" class="form-title"></h3>

+								<div>

+									<input id="btnDisconnect" data-trans="ap_station_disconnect"

+										   data-bind="click:disconnectHotspot,visible:connectButtonStatus()=='hide'" type="button" class="btn btn-primary"/>

+									<input id="btnConnect" data-trans="ap_station_connect"

+										   data-bind="click:connectHotspot,disable:connectButtonStatus()=='disable' || isCableMode() == true,visible:connectButtonStatus()=='show'||connectButtonStatus()=='disable'" type="button" class="btn btn-primary"/>

+									<input id="btnDelete" data-trans="delete"

+										   data-bind="click:deleteHotspot,disable:hasSelectFromUser() == false || isCableMode() == true" type="button" class="btn btn-primary"/>

+									<input id="btnEdit" data-trans="edit"

+										   data-bind="click:openEditPage,disable:hasSelectFromUser() == false || isCableMode() == true" type="button" class="btn btn-primary"/>

+									<input id="btnOpenAddPage" data-trans="add"

+										   data-bind="click:openAddPage,disable:isCableMode() == true" type="button" class="btn btn-primary"/>

+								</div>

+								<div id="apList" data-bind="simpleGrid: apGrid"></div>

+							</div>

+						</div>

+						<div data-bind="visible:pageState() == page.add || pageState() == page.edit">

+							<h3 data-trans="ap_station_add_hotspot" data-bind="visible:pageState() == page.add" class="form-title"></h3>

+							<h3 data-trans="ap_station_edit_hotspot" data-bind="visible:pageState() == page.edit" class="form-title"></h3>

+							<div class="content">

+								<div class="row form-group">

+									<label data-trans='ssid_name' for="txtSSID" class="col-xs-4 side-right"></label>

+									<div class="col-xs-6">

+										<input id="txtSSID" data-bind="value:ssid" maxlength="32" name="txtSSID" type="text" class="required  form-control"/>

+									</div>

+								</div>

+								<div class="row form-group">

+									<label data-trans='security_mode' for='mode' class="col-xs-4 side-right"></label>

+									<div class="col-xs-6">

+										<select id="mode" data-transid='ap_station_security_mode' 

+												data-bind="options: modes, value: authMode, optionsText: transOption('ap_station_security_mode'), optionsValue: 'value'" class="form-control"></select>

+									</div>

+								</div>

+								<div data-bind='visible: authMode() == "OPEN"' class="row form-group">

+									<label data-trans='ap_station_encrypt_type' for='selEncryptType' class="col-xs-4 side-right"></label>

+

+									<div class="col-xs-6">

+										<select id="selEncryptType" data-bind="value: encryptType,optionsValue: 'value'" class="form-control">

+											<option data-trans="ap_station_encrypt_type_none" value="NONE"></option>

+											<option data-trans="ap_station_encrypt_type_wep" value="WEP"></option>

+										</select>

+									</div>

+								</div>

+								<div data-bind='visible:  (authMode() == "OPEN" && encryptType() == "WEP") || authMode() == "SHARED"' class="row form-group">

+									<label data-trans='ap_station_wep_default_key' for='selWepKeyType' class="col-xs-4 side-right"></label>

+

+									<div class="col-xs-6">

+										<select id="selWepKeyType" data-bind="value: keyID,optionsValue: 'value'" class="form-control">

+											<option data-trans="ap_station_wep_key_0" value="0"></option>

+											<option data-trans="ap_station_wep_key_1" value="1"></option>

+											<option data-trans="ap_station_wep_key_2" value="2"></option>

+											<option data-trans="ap_station_wep_key_3" value="3"></option>

+										</select>

+									</div>

+								</div>

+								<div data-bind='visible: (authMode() == "OPEN" && encryptType() == "WEP") || authMode() == "SHARED"' class="row form-group">

+									<label data-trans='ap_station_wep_key' for='txtWepKey' class="col-xs-4 side-right"></label>

+

+									<div class="col-xs-6">

+										<input id='pwdWepKey'

+											   data-bind="value: password,visible:!showPassword()" maxlength='26' name="pwdWepKey" type="password" class="required form-control"/>

+										<input id='txtWepKey'

+											   data-bind="value: password,visible:showPassword()" maxlength='26' name="txtWepKey" type="text" class="required form-control"/>

+										<div class="margin-top-10">

+										<p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler"

+										   manualControl="true" class="checkbox">

+											<input id="showPassword" data-bind="checked:showPassword" type="checkbox"/>

+										</p>

+										<label data-trans="display_password" for="showPassword" class="floatleft margintop5 lineheight25"/>

+										</div>

+										<div id="lblShowPassword" class="clear"></div>

+									</div>

+								</div>

+								<div data-bind='visible: authMode() == "WPAPSK" || authMode() == "WPA2PSK" || authMode() == "WPAPSKWPA2PSK" ' class="row form-group">

+									<label class="col-xs-4 side-right" for='cipher_TKIP' data-trans='ap_station_cipher'></label>

+

+									<div id="cipherGroup" class="col-xs-6">

+										<input id="cipher_TKIP"

+											   data-bind="checked: encryptType_WPA" name="cipher" value="TKIP" type="radio">

+										<label data-trans="ap_station_cipher_TKIP" for="cipher_TKIP"></label>

+										<input id="cipher_AES"

+											   data-bind="checked: encryptType_WPA" name="cipher" value="CCMP" type="radio">

+										<label data-trans="ap_station_cipher_AES" for="cipher_AES"></label>

+										<input id="cipher_AUTO"

+											   data-bind="checked: encryptType_WPA" name="cipher" value="TKIPCCMP" type="radio">

+										<label data-trans="ap_station_cipher_AUTO" for="cipher_AUTO"></label>

+									</div>

+								</div>

+								<div data-bind='visible: authMode() == "WPAPSK" || authMode() == "WPA2PSK" || authMode() == "WPAPSKWPA2PSK" || authMode() == "WPA3Personal" || authMode() == "WPA2WPA3"' class="row form-group">

+									<label data-trans='pass_phrase' for='txtWPAKey' class="col-xs-4 side-right"></label>

+

+									<div class="col-xs-6">

+										<input id='codeWPAKey'

+											   data-bind="value: password,visible:!showPassword()" minlength='8' maxlength='63' name="codeWPAKey" type="password" class="required form-control"/>

+										<input id='txtWPAKey'

+											   data-bind="value: password,visible:showPassword()" minlength='8' maxlength='63' name="txtWPAKey" type="text" class="required form-control"/>

+										<div class="margin-top-10">

+										<p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler"

+										   manualControl="true" class="checkbox">

+											<input id="showWPAPassword" data-bind="checked:showPassword" type="checkbox"/>

+										</p>

+										<label data-trans="display_password" for="showWPAPassword" class="floatleft margintop5 lineheight25"/>

+										</div>

+										<div id="lblshowWPAPassword" class="clear"></div>

+									</div>

+								</div>

+							</div>

+							<div class="form-buttons" >

+								<input id="btnRefreshSearch" data-trans="refresh"

+									   data-bind="click:searchHotspot,visible:pageState() == page.add" type="button" class="btn btn-primary"/>

+								<!--<input id="btnReset" type="button" class="btn btn-primary" data-trans="clear"-->

+									   <!--data-bind="click:clear"/>-->

+								<input id="btnAdd" data-trans="apply" type="submit" formmethod="post" class="btn btn-primary"/>

+								<input id="btnBack" data-trans="back"

+									   data-bind="click:openListPage" type="button" class="btn btn-primary"/>

+							</div>

+							<div id="apSearchList" data-bind="simpleGrid: apSearchGrid,visible:pageState() == page.add"></div>

+						</div>

+						<div data-bind="visible:pageState() == page.list" class="form-note">

+							<div class="notes-title">&nbsp;</div>

+							<ul class="notes-content">

+								<li data-trans="ap_station_note_info"></li>

+								<li data-bind="visible: hasMultiSSID" data-trans="ap_station_note_disable_info"></li>

+							</ul>

+						</div>			

+					</form>

+				</div>

+			</div>

+		</div>

+	</div>

+</div>

diff --git a/ap/app/zte_webui_min/subpg/wifi_guest.html b/ap/app/zte_webui_min/subpg/wifi_guest.html
new file mode 100755
index 0000000..84e55b6
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_guest.html
@@ -0,0 +1,244 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title form-title-multi">

+                <h1 data-trans='wifi_wireless_settings'></h1>

+                <p data-trans="wifi_main_sub_title"></p>

+            </div>

+        </div>

+    </div>

+<div class="row">

+<div class="col-xs-2">

+		    <div class="nav_right">

+				<ul data-bind="visible: isShowSSIDInfoDiv">

+					<li><a data-trans="multi_ssid_1" href="#wlan_main"></a></li>

+					<li class="active"><a data-trans="multi_ssid_2" href="#wlan_guset"></a></li>

+					<li><a data-trans="wps" href="#wlan_wps"></a></li>

+					<li data-bind="visible: hasAPStation"><a data-trans="ap_station" href="#wlan_station"></a></li>

+					<li><a data-trans="wifi_advance" href="#wlan_adv"></a></li>

+					<li data-bind="visible: hasWlanMacfilter"><a data-trans="mac_filter" href="#filter_mac"></a></li>

+				</ul>

+			</div>

+		</div>

+        <div class="col-xs-10">

+

+<div class="form-body">

+	<form id="frmWifiSwitch" role="form">

+        <div class="content margin-top-20">

+            <div data-bind="visible: hasWifiSwitch" class="row form-group">

+                <label data-trans="wifi_switch" class="col-xs-4 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_enable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="wifi_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_disable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="wifi_switch_disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+			<div data-bind="visible: wifi_enable() == '1'" class="row form-group">

+				<label data-trans="multi_ssid_enable" class="col-xs-4 side-right"></label>

+				<div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_enable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="multi_ssid_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_disable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="multi_ssid_switch_disable"></label>

+                        </div>

+                    </div>

+				</div>

+			</div>

+            <div data-bind="visible: hasWifiSwitch || (wifi_enable() == '1' && hasMultiSSID)" class="form-buttons">

+                <input id="wifi_switch_apply" data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+                <!--input id="wifi_switch_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("switch");}' data-trans='cancel'/-->

+            </div>

+        </div>

+    </form>

+

+    

+	<!--

+	<form id="frmMultiSSID" data-bind="visible:hasMultiSSID && !hasWifiSwitch">

+		<div class="form-title" data-trans="multi_ssid_enable"></div>

+		<div class="content">

+			<div class="row form-group">

+				<label class="col-xs-4 side-right" data-trans="multi_ssid_enable"></label>

+				<div class="col-xs-6">

+					<input type="radio" name="multi_ssid_switch" id="multi_ssid_switch_enable"

+						   data-bind="checked: multi_ssid_enable" value="1"/>

+					<label for="multi_ssid_switch_enable" data-trans="enable"></label>

+					<input type="radio" name="multi_ssid_switch" id="multi_ssid_switch_disable"

+						   data-bind="checked: multi_ssid_enable" value="0"/>

+					<label for="multi_ssid_switch_disable" data-trans="disable"></label>

+				</div>

+			</div>

+			<div class="form-buttons">

+				<input id="mutissid_apply" type="submit" formmethod="post" class="btn-1 " data-trans='apply'/>

+				<input id="multissid_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("switch");}' data-trans='cancel'/>

+			</div>

+		</div>

+	</form>-->

+	<div data-bind="visible: isShowSSIDInfoDiv">

+        <div data-bind="visible:origin_multi_ssid_enable!='1'|| !hasMultiSSID" data-trans="wif_guest_disabled">

+        </div>

+        <form id="frmSSID2" data-bind="visible:origin_multi_ssid_enable=='1'&& hasMultiSSID">

+	        <h3 data-bind="attr:{'data-trans': 'multi_ssid_2'}" class="form-title"></h3>

+            <div class="content">

+                <div class="row form-group">

+                    <label for="m_ssid" data-trans="network_name" class="col-xs-4 side-right"></label>

+

+                    <div class="col-xs-6">

+                        <input id="m_ssid" data-bind="value: m_ssid" maxlength="32" name="m_ssid" type="text" class="required form-control"/>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label class="col-xs-4 side-right"></label>

+                    <div class="col-xs-8 label-absolute">

+                        <p data-bind="css:{'checkbox_selected': m_broadcast() == '0'}" class="checkbox">

+                            <input id="mBroadcastCheckbox" data-bind="checked: m_broadcast() == '0'" name="mBroadcastCheckbox" type="checkbox" value="1"/>

+                        </p>

+                        <label data-trans="wifi_broadcast_desc"></label>

+                    </div>

+                </div>

+                <div data-bind="visible: showIsolated" class="row form-group">

+                    <label class="col-xs-4"></label>

+                    <div class="col-xs-8">

+                        <p data-bind="css:{'checkbox_selected': m_apIsolation() == 1}" class="checkbox">

+                            <input id="mApIsolatedCheckbox" data-bind="checked: m_apIsolation() == 1" name="mApIsolatedCheckbox" type="checkbox" value="1"/>

+                        </p>

+                        <label data-trans="wifi_isolated_desc"></label>

+                    </div>

+                </div>

+                <div class="row form-group">

+                    <label data-trans='security_mode' class="col-xs-4 side-right" for='m_mode'></label>

+                    <div class="col-xs-6">

+                        <select id="m_mode" data-transid='security_mode'

+                                data-bind="options: m_modes, value: m_selectedMode, optionsText: transOption('security_mode'), optionsValue: 'value'" class="form-control"></select>

+                    </div>

+                </div>

+                <div data-bind='visible: m_selectedMode() == "OPEN" && hasWifiWep' class="row form-group">

+					<label data-trans='ap_station_encrypt_type' for='m_selEncryptType' class="col-xs-4 side-right"></label>

+					<div class="col-xs-6">

+						<select id="m_selEncryptType" data-bind="value: m_encryptType,optionsValue: 'value'" class="form-control">

+							<option data-trans="ap_station_encrypt_type_none" value="NONE"></option>

+							<option data-trans="ap_station_encrypt_type_wep" value="WEP"></option>

+						</select>

+					</div>

+				</div>

+				<div data-bind='visible:  (m_selectedMode() == "OPEN" && m_encryptType() == "WEP" && hasWifiWep) || (m_selectedMode() == "SHARED" && hasWifiWep)' class="row form-group">

+					<label data-trans='ap_station_wep_default_key' for='m_selWepKeyType' class="col-xs-4 side-right"></label>

+					<div class="col-xs-6">

+						<select id="m_selWepKeyType" data-bind="value: m_keyID,optionsValue: 'value', event:{ change: profileChangeHandler}" class="form-control">

+							<option data-trans="ap_station_wep_key_0" value="0"></option>

+							<option data-trans="ap_station_wep_key_1" value="1"></option>

+							<option data-trans="ap_station_wep_key_2" value="2"></option>

+							<option data-trans="ap_station_wep_key_3" value="3"></option>

+						</select>

+					</div>

+				</div>

+				<div data-bind='visible: (m_selectedMode() == "OPEN" && m_encryptType() == "WEP" && hasWifiWep) || (m_selectedMode() == "SHARED" && hasWifiWep)' class="row form-group">

+					<label data-trans='ap_station_wep_key' for='m_pwdWepKey' class="col-xs-4 side-right"></label>

+

+					<div class="col-xs-6">

+						<input id='m_pwdWepKey'

+											   data-bind="value: m_wepPassword,visible:!m_showPassword()" maxlength='26' name="m_pwdWepKey" type="password" class="required form-control"/>

+						<input id='m_txtWepKey'

+											   data-bind="value: m_wepPassword,visible:m_showPassword()" maxlength='26' name="m_txtWepKey" type="text" class="required form-control"/>

+						<div class="margin-top-10">

+							<p data-bind="css:{'checkbox_selected': m_showPassword()}, click: m_showPasswordHandler"

+										   manualControl="true" class="checkbox">

+								<input id="m_showWepPassword" data-bind="checked:m_showPassword" type="checkbox"/>

+							</p>

+							<label data-trans="display_password" for="m_showWepPassword" class="floatleft margintop5 lineheight25"/>

+						</div>

+						<div id="m_lblShowWepPassword" class="clear"></div>

+					</div>

+				</div>

+				<div id="passwordContainer" data-bind='visible: m_selectedMode() == "WPA2PSK" || m_selectedMode() == "WPAPSKWPA2PSK" || m_selectedMode() == "WPA3Personal" || m_selectedMode() == "WPA2WPA3"' class="row form-group">

+                    <label data-trans='pass_phrase' for='m_pass' class="col-xs-4 side-right"></label>

+

+                    <div class="col-xs-6">

+                        <input id='m_pass' data-bind="value: m_passPhrase,visible:!m_showPassword()"

+                               minlength='8' maxlength='63' name="m_pass" type="password" class="required form-control floatleft margintop5"/>

+                        <input id='m_passShow' data-bind="value: m_passPhrase,visible:m_showPassword()"

+                               minlength='8' maxlength='63' name="m_passShow" type="text" class="required form-control floatleft margintop5"/>

+                        <div class="margin-top-10">

+                            <p data-bind="css:{'checkbox_selected': m_showPassword()}, click: m_showPasswordHandler" manualControl="true" class="checkbox floatleft margintop10 marginleft5 marginright5">

+                                <input id="m_showPassword" data-bind="checked:m_showPassword" type="checkbox"/>

+                            </p>

+                            <label data-trans="display_password" class="floatleft margintop5 lineheight25"></label>

+                        </div>

+                        <div id="m_lblShowPassword" class="clear"></div>						

+                    </div>

+                </div>

+				<div class="row form-group">

+				    <label class="col-xs-4 side-right" ></label>

+					<div class="col-xs-6">

+					    <div data-bind="visible: showQRSwitch" class="margin-top-10">

+                            <p data-bind="css:{'checkbox_selected': showQR()}, click: showQRHandler" manualControl="true" class="checkbox">

+                                <input id="showQR" data-bind="checked:showQR" type="checkbox"/>

+                            </p>

+                            <label data-trans="display_QR" class="floatleft lineheight25 margintop5"></label>

+                        </div>

+						<div id="h_qrcode"  data-bind="visible: showQRCode">

+							<img id="qrcode_img" data-bind="attr: {src: qrcodeSrc}" src="./pic/res_blacktrans.png" width="111"/>				

+						</div>

+				    </div>

+				</div>

+                <div class="row form-group">

+                    <label data-trans="max_station_number" for="m_maxStation" class="col-xs-4 side-right"></label>

+

+                    <div class="col-xs-6">

+                        <select id="m_maxStation"

+                                data-bind="options: m_maxStations, value: m_selectedStation, optionsText: 'text', optionsValue: 'value'" name="m_maxStation" class="form-control"></select>

+                    </div>

+                </div>

+

+            </div>

+            <div class="form-buttons">

+                <input id="ssid2_apply" data-trans='apply' data-bind="disable: (adBand()=='b' && adMode() == '2' && m_selectedMode() == 'SHARED') || (adBand()=='b' && adMode() == '2' && m_selectedMode() == 'OPEN' && m_encryptType() == 'WEP')" type="submit" formmethod="post" class="btn btn-primary"/>

+                <!--input id="ssid2_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("ssid2");}' data-trans='cancel'/-->

+            </div>

+        </form>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="wifi_basic_note_multi_ssid_switch"></li>

+                <li data-trans="wifi_basic_note_network_name"></li>

+                <!--<li data-trans="wifi_basic_note_network_name_input"></li>-->

+                <li data-trans="wifi_basic_note_broadcast"></li>

+                <li data-trans="wifi_basic_note_security_mode"></li>

+                <li class="no-style">

+                    <ul>

+                        <li data-trans="wifi_basic_note_no_encryption"></li>

+						<li data-bind='visible: hasWifiWep' data-trans="wifi_basic_note_shared"></li>

+                        <li data-trans="wifi_basic_note_wpa_psk_aes"></li>

+                        <li data-trans="wifi_basic_note_wpa_psk"></li>

+                        <li data-bind='visible: hasWifiWpa3' data-trans="wifi_basic_note_wpa3"></li>

+                        <li data-bind='visible: hasWifiWpa23' data-trans="wifi_basic_note_wpa2_wpa3"></li>

+                    </ul>

+                </li>

+                <li data-trans="wifi_basic_note_pass_phrase"></li>

+                <li data-trans="wifi_basic_note_max_station_number"></li>

+            </ul>

+        </div>

+    </div>

+</div>

+

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/wifi_mac_filter.html b/ap/app/zte_webui_min/subpg/wifi_mac_filter.html
new file mode 100755
index 0000000..8d1e64e
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_mac_filter.html
@@ -0,0 +1,170 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title form-title-multi">

+                <h1 data-trans='wifi_wireless_settings'></h1>

+                <p data-trans="wifi_main_sub_title"></p>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		    <div class="nav_right">

+				<ul data-bind="visible: isShowSSIDInfoDiv">

+					<li><a data-trans="multi_ssid_1" data-bind="attr:{'data-trans': hasMultiSSID ? 'multi_ssid_1':'ssid_title'}" href="#wlan_main"></a></li>

+					<li data-bind="visible: hasMultiSSID"><a data-trans="multi_ssid_2" href="#wlan_guset"></a></li>

+					<li><a data-trans="wps" href="#wlan_wps"></a></li>

+					<li data-bind="visible: hasAPStation"><a data-trans="ap_station" href="#wlan_station"></a></li>

+					<li><a data-trans="wifi_advance" href="#wlan_adv"></a></li>

+					<li class="active"><a data-trans="mac_filter" href="#filter_mac"></a></li>

+				</ul>

+			</div>

+		</div>

+        <div class="col-xs-10">

+

+        <div class="form-body">

+		

+		<form id="frmWifiSwitch" role="form">

+            <div class="content margin-top-20">

+                <div data-bind="visible: hasWifiSwitch" class="row form-group">

+                    <label data-trans="wifi_switch" class="col-xs-4 side-right"></label>

+                    <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_enable" data-bind="checked: wifi_enable" name="wifi_switch" type="radio"

+                                   value="1"/>

+                            <label data-trans="enable" for="wifi_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_disable" data-bind="checked: wifi_enable" name="wifi_switch" type="radio"

+                                   value="0"/>

+                            <label data-trans="disable" for="wifi_switch_disable"></label>

+                        </div>

+                    </div>

+                    </div>

+                </div>

+			    <div data-bind="visible: wifi_enable() == '1' && hasMultiSSID" class="row form-group">

+				    <label data-trans="multi_ssid_enable" class="col-xs-4 side-right"></label>

+				    <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_enable" data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio"

+                                   value="1"/>

+                            <label data-trans="enable" for="multi_ssid_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_disable" data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio"

+                                   value="0"/>

+                            <label data-trans="disable" for="multi_ssid_switch_disable"></label>

+                        </div>

+                    </div>

+				    </div>

+			    </div>

+                <div data-bind="visible: hasWifiSwitch || (wifi_enable() == '1' && hasMultiSSID)" class="form-buttons">

+                    <input id="wifi_switch_apply" data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+                    <!--input id="wifi_switch_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("switch");}' data-trans='cancel'/-->

+                </div>

+            </div>

+        </form>

+		

+		<div data-bind="visible: isShowSSIDInfoDiv">

+	        <form id="mac_filter_form" role="form">

+                <h3 data-trans="mac_filter" class="form-title"></h3>

+                <div class="content margin-top-20">

+	

+	                <div class="content">

+		                <div class="row form-group">

+			                <label data-trans="mac_filter_lable" for="country" class="col-xs-4 side-right"></label>

+                            <div class="col-xs-4">

+                                <select id="country" data-bind="value: selectedAction, event:{ change: ChangeHandler}" name="country" class="form-control">

+								    <option data-trans="wlan_mac_filter_0" value="0"></option>

+								    <option data-trans="wlan_mac_filter_1" value="1"></option>

+								    <option data-trans="wlan_mac_filter_2" value="2"></option>

+								</select>

+                             </div>

+		                </div>

+		                <div class="row form-group">

+		                    <label class="col-xs-4 side-right"></label>

+		                	<div class="col-xs-3">

+			                	<input id="mac_1" maxlength="32" data-bind="value: mac1,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" name="mac_1" type="text" class="form-control"/>

+			                </div>

+			                <div class="col-xs-3">

+			                	<input id="mac_2" maxlength="32" data-bind="value: mac2,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" name="mac_2" type="text" class="form-control"/>

+			                </div>

+	                	</div>

+		                <div class="row form-group">

+		                    <label class="col-xs-4 side-right"></label>

+		                	<div class="col-xs-3">

+		                		<input id="mac_3" data-bind="value: mac3,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_3" type="text" class="form-control"/>

+		                	</div>

+		                	<div class="col-xs-3">

+		                		<input id="mac_4" data-bind="value: mac4,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_4" type="text" class="form-control"/>

+		                	</div>

+		                </div>

+		                <div class="row form-group">

+		                    <label class="col-xs-4 side-right"></label>

+		                	<div class="col-xs-3">

+		                		<input id="mac_5" data-bind="value: mac5,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_5" type="text" class="form-control"/>

+		                	</div>

+			                <div class="col-xs-3">

+		                		<input id="mac_6" data-bind="value: mac6,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_6" type="text" class="form-control"/>

+		                	</div>

+		                </div>

+		                <div class="row form-group">

+		                    <label class="col-xs-4 side-right"></label>

+			                <div class="col-xs-3">

+			                	<input id="mac_7" data-bind="value: mac7,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_7" type="text" class="form-control"/>

+		                	</div>

+		                	<div class="col-xs-3">

+		                		<input id="mac_8" data-bind="value: mac8,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_8" type="text" class="form-control"/>

+		                	</div>

+		                </div>

+		                <div class="row form-group">

+		                    <label class="col-xs-4 side-right"></label>

+		                	<div class="col-xs-3">

+		                		<input id="mac_9" data-bind="value: mac9,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_9" type="text" class="form-control"/>

+		                	</div>

+		                	<div class="col-xs-3">

+		                		<input id="mac_10" data-bind="value: mac10,disable:selectedAction() == 0,css:{disabled:selectedAction() == 0}" maxlength="32" name="mac_10" type="text" class="form-control"/>

+		                	</div>

+		                </div>

+	                </div>

+	                <div class="form-buttons">

+                        <input data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+	                </div>

+                </div>

+            </form>

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="wif_filter_note1"></li>

+                    <li data-trans="wif_filter_note2"></li>

+                    <li data-trans="wif_filter_note3"></li>

+                    <li data-trans="wif_filter_note4"></li>

+                </ul>

+            </div>

+        </div>

+		

+        </div>

+        </div>

+    </div>

+</div>

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/ap/app/zte_webui_min/subpg/wifi_main.html b/ap/app/zte_webui_min/subpg/wifi_main.html
new file mode 100755
index 0000000..b2c7dad
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_main.html
@@ -0,0 +1,241 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title form-title-multi">

+                <h1 data-trans='wifi_wireless_settings'></h1>

+                <p data-trans="wifi_main_sub_title"></p>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		    <div class="nav_right">

+				<ul data-bind="visible: isShowSSIDInfoDiv">

+					<li class="active"><a data-trans="multi_ssid_1" data-bind="attr:{'data-trans': hasMultiSSID ? 'multi_ssid_1':'ssid_title'}" href="#wlan_main"></a></li>

+					<li data-bind="visible: hasMultiSSID"><a data-trans="multi_ssid_2" href="#wlan_guset"></a></li>

+					<li><a data-trans="wps" href="#wlan_wps"></a></li>

+					<li data-bind="visible: hasAPStation"><a data-trans="ap_station" href="#wlan_station"></a></li>

+					<li><a data-trans="wifi_advance" href="#wlan_adv"></a></li>

+					<li data-bind="visible: hasWlanMacfilter"><a data-trans="mac_filter" href="#filter_mac"></a></li>

+				</ul>

+			</div>

+		</div>

+        <div class="col-xs-10">

+

+<div class="form-body">

+	<form id="frmWifiSwitch" role="form">

+        <div class="content margin-top-20">

+            <div data-bind="visible: hasWifiSwitch" class="row form-group">

+                <label data-trans="wifi_switch" class="col-xs-4 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_enable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="wifi_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_disable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="wifi_switch_disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+			<div data-bind="visible: wifi_enable() == '1' && hasMultiSSID" class="row form-group">

+				<label data-trans="multi_ssid_enable" class="col-xs-4 side-right"></label>

+				<div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_enable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="multi_ssid_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_disable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="multi_ssid_switch_disable"></label>

+                        </div>

+                    </div>

+				</div>

+			</div>

+            <div data-bind="visible: hasWifiSwitch || (wifi_enable() == '1' && hasMultiSSID)" class="form-buttons">

+                <input id="wifi_switch_apply" data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+                <!--input id="wifi_switch_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("switch");}' data-trans='cancel'/-->

+            </div>

+        </div>

+    </form>

+

+    

+	<!--form id="frmMultiSSID" data-bind="visible:hasMultiSSID && !hasWifiSwitch">

+		<div class="form-title" data-trans="multi_ssid_enable"></div>

+		<div class="content">

+			<div class="row form-group">

+				<label class="col-xs-4 side-right" data-trans="multi_ssid_enable"></label>

+				<div class="col-xs-6">

+					<input type="radio" name="multi_ssid_switch" id="multi_ssid_switch_enable"

+						   data-bind="checked: multi_ssid_enable" value="1"/>

+					<label for="multi_ssid_switch_enable" data-trans="enable"></label>

+					<input type="radio" name="multi_ssid_switch" id="multi_ssid_switch_disable"

+						   data-bind="checked: multi_ssid_enable" value="0"/>

+					<label for="multi_ssid_switch_disable" data-trans="disable"></label>

+				</div>

+			</div>

+			<div class="form-buttons">

+				<input id="mutissid_apply" type="submit" formmethod="post" class="btn-1 " data-trans='apply'/>

+				<input id="multissid_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("switch");}' data-trans='cancel'/>

+			</div>

+		</div>

+	</form-->

+	<div data-bind="visible: isShowSSIDInfoDiv">

+		<form id="frmSSID1">

+	        <h3 data-bind="attr:{'data-trans': hasMultiSSID ? 'multi_ssid_1':'ssid_title'}" class="form-title"></h3>

+			<div class="content">

+				<div class="row form-group">

+					<label data-trans="network_name" for="ssid" class="col-xs-4 side-right"></label>

+					<div class="col-xs-6">

+						<input id="ssid" data-bind="value: ssid" maxlength="32" name="ssid" type="text" class="required form-control"/>

+					</div>

+				</div>

+                <div class="row form-group">

+                    <label class="col-xs-4"></label>

+                    <div class="col-xs-8 label-absolute">

+                        <p data-bind="css:{'checkbox_selected': broadcast() == '0'}" class="checkbox">

+                            <input id="broadcastCheckbox" data-bind="checked: broadcast() == '0'" name="broadcastCheckbox" type="checkbox" value="1"/>

+                        </p>

+                        <label data-trans="wifi_broadcast_desc"></label>

+                    </div>

+                </div>

+                <div data-bind="visible: showIsolated" class="row form-group">

+                    <label class="col-xs-4"></label>

+                    <div class="col-xs-8">

+                        <p data-bind="css:{'checkbox_selected': apIsolation() == 1}" class="checkbox">

+                            <input id="apisolatedCheckbox" data-bind="checked: apIsolation() == 1" name="apisolatedCheckbox" type="checkbox" value="1"/>

+                        </p>

+                        <label data-trans="wifi_isolated_desc"></label>

+                    </div>

+                </div>

+				<div class="row form-group">

+					<label data-trans='security_mode' for='mode' class="col-xs-4 side-right"></label>

+					<div class="col-xs-6">

+						<select id="mode" data-transid='security_mode'

+								data-bind="options: modes, value: selectedMode, optionsText: transOption('security_mode'), optionsValue: 'value'" class="form-control"></select>

+					</div>

+				</div>

+				

+				<div data-bind='visible: selectedMode() == "OPEN" && hasWifiWep' class="row form-group">

+					<label data-trans='ap_station_encrypt_type' class="col-xs-4 side-right" for='selEncryptType'></label>

+					<div class="col-xs-6">

+						<select id="selEncryptType" data-bind="value: encryptType,optionsValue: 'value'" class="form-control">

+							<option data-trans="ap_station_encrypt_type_none" value="NONE"></option>

+							<option data-trans="ap_station_encrypt_type_wep" value="WEP"></option>

+						</select>

+					</div>

+				</div>

+				<div data-bind='visible:  (selectedMode() == "OPEN" && encryptType() == "WEP" && hasWifiWep) || (selectedMode() == "SHARED" && hasWifiWep)' class="row form-group">

+					<label data-trans='ap_station_wep_default_key' for='selWepKeyType' class="col-xs-4 side-right"></label>

+					<div class="col-xs-6">

+						<select id="selWepKeyType" data-bind="value: keyID,optionsValue: 'value', event:{ change: profileChangeHandler}" class="form-control">

+							<option data-trans="ap_station_wep_key_0" value="0"></option>

+							<option data-trans="ap_station_wep_key_1" value="1"></option>

+							<option data-trans="ap_station_wep_key_2" value="2"></option>

+							<option data-trans="ap_station_wep_key_3" value="3"></option>

+						</select>

+					</div>

+				</div>

+				<div data-bind='visible: (selectedMode() == "OPEN" && encryptType() == "WEP" && hasWifiWep) || (selectedMode() == "SHARED" && hasWifiWep)' class="row form-group">

+					<label data-trans='ap_station_wep_key' for='pwdWepKey' class="col-xs-4 side-right"></label>

+					<div class="col-xs-6">

+						<input id='pwdWepKey'

+											   data-bind="value: wepPassword,visible:!showPassword()" maxlength='26' name="pwdWepKey" type="password" class="required form-control"/>

+						<input id='txtWepKey'

+											   data-bind="value: wepPassword,visible:showPassword()" maxlength='26' name="txtWepKey" type="text" class="required form-control"/>

+						<div class="margin-top-10">

+							<p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler"

+										   manualControl="true" class="checkbox">

+								<input id="showWepPassword" data-bind="checked:showPassword" type="checkbox"/>

+							</p>

+							<label data-trans="display_password" for="showWepPassword" class="floatleft margintop5 lineheight25"/>

+						</div>

+						<div id="lblShowWepPassword" class="clear"></div>

+					</div>

+				</div>

+				<div id="passwordContainer"

+									 data-bind='visible: selectedMode() == "WPA2PSK" || selectedMode() == "WPAPSKWPA2PSK" || selectedMode() == "WPA3Personal" || selectedMode() == "WPA2WPA3"' class="row form-group">

+					<label data-trans='pass_phrase' for='txtWPAKey' class="col-xs-4 side-right"></label>

+					<div class="col-xs-6">

+						<input id='codeWPAKey' data-bind="value: passPhrase,visible:!showPassword()"

+							   minlength='8' maxlength='63' name="codeWPAKey" type="password" class="required form-control"/>

+						<input id='txtWPAKey' data-bind="value: passPhrase,visible:showPassword()"

+							   minlength='8' maxlength='63' name="txtWPAKey" type="text" class="required form-control"/>

+						<div class="margin-top-10">

+                            <p data-bind="css:{'checkbox_selected': showPassword()}, click: showPasswordHandler" manualControl="true" class="checkbox">

+                                <input id="showPassword" data-bind="checked:showPassword" type="checkbox"/>

+                            </p>

+                            <label data-trans="display_password" class="floatleft lineheight25 margintop5"></label>

+                        </div>						

+						<div id="lblshowWPAPassword" class="clear"></div>

+					</div>

+				</div>

+				<div class="row form-group">

+				    <label class="col-xs-4 side-right" ></label>

+					<div class="col-xs-6">

+				        <div data-bind="visible: showQRSwitch" class="margin-top-10">

+                            <p data-bind="css:{'checkbox_selected': showQR()}, click: showQRHandler" manualControl="true" class="checkbox">

+                                <input id="showQR" data-bind="checked:showQR" type="checkbox"/>

+                            </p>

+                                <label data-trans="display_QR" class="floatleft lineheight25 margintop5"></label>

+                        </div>

+					    <div id="h_qrcode" data-bind="visible: showQRCode">

+						    <img id="qrcode_img" data-bind="attr: {src: qrcodeSrc}" src="./pic/res_blacktrans.png" width="111"/>				

+					    </div>

+					</div>

+				</div>

+				<div class="row form-group">

+					<label data-trans="max_station_number" class="col-xs-4 side-right" for="maxStation"></label>

+

+					<div class="col-xs-6">

+						<select id="maxStation"

+								data-bind="options: maxStations, value: selectedStation, optionsText: 'text', optionsValue: 'value'" name="maxStation" class="form-control"></select>

+					</div>

+				</div>

+

+			</div>

+			<div class="form-buttons">

+				<input id="ssid1_apply" data-trans='apply' data-bind="disable: (adBand()=='b' && adMode() == '2' && selectedMode() == 'SHARED') || (adBand()=='b' && adMode() == '2' && selectedMode() == 'OPEN' && encryptType() == 'WEP')" type="submit" formmethod="post" class="btn btn-primary"/>

+				<!--input id="ssid1_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("ssid1");}' data-trans='cancel'/-->

+			</div>

+        </form>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-bind="visible: hasMultiSSID" data-trans="wifi_basic_note_multi_ssid_switch"></li>

+                <li data-trans="wifi_basic_note_network_name"></li>

+                <!--<li data-trans="wifi_basic_note_network_name_input"></li>-->

+                <li data-trans="wifi_basic_note_broadcast"></li>

+                <li data-trans="wifi_basic_note_security_mode"></li>

+                <li class="no-style">

+                    <ul>

+                        <li data-trans="wifi_basic_note_no_encryption"></li>

+						<li data-bind='visible: hasWifiWep' data-trans="wifi_basic_note_shared"></li>

+                        <li data-trans="wifi_basic_note_wpa_psk_aes"></li>

+                        <li data-trans="wifi_basic_note_wpa_psk"></li>

+                        <li data-bind='visible: hasWifiWpa3' data-trans="wifi_basic_note_wpa3"></li>

+                        <li data-bind='visible: hasWifiWpa23' data-trans="wifi_basic_note_wpa2_wpa3"></li>

+                    </ul>

+                </li>

+                <li data-trans="wifi_basic_note_pass_phrase"></li>

+                <li data-trans="wifi_basic_note_max_station_number"></li>

+            </ul>

+        </div>

+    </div>

+</div>

+

+</div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/wifi_sleep_mode.html b/ap/app/zte_webui_min/subpg/wifi_sleep_mode.html
new file mode 100755
index 0000000..519041a
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_sleep_mode.html
@@ -0,0 +1,159 @@
+<div id="innerContainer">

+<div class="row header-row">

+    <div class="col-xs-1">

+        <a href="#main">

+            <img alt="" src="pic/direct-back.png">

+        </a>

+    </div>

+    <div class="col-xs-11">

+        <div class="form-title">

+            <h1 data-trans='advanced_settings'></h1>

+        </div>

+    </div>

+</div>

+<div class="row">

+    <div class="col-xs-2">

+		<div class="nav_right">

+		    <ul>

+            <li class="active"><a data-trans="sleep_mode" href="#wlan_sleep"></a></li>

+            <li><a data-trans="router_setting" href="#route_set"></a></li>

+            <li><a data-trans="firewall" href="#filter_main"></a></li>

+            <li data-bind="visible:hasUpdateCheck"><a data-trans="update_settings" href="#fota"></a></li>

+            <li data-bind="visible:hasUssd"><a data-trans="USSD" href="#usat"></a></li>

+			<li data-bind="visible:hasDdns"><a data-trans="DDNS" href="#dynamic_dns"></a></li>

+            <li><a data-trans="others" href="#more"></a></li>

+        </ul>

+	    </div>

+	</div>

+    <div class="col-xs-10">

+        

+

+<div class="form-body margin-top-20">

+    <!--hide wifi range settings until sw implements it-->

+    <form id='wifiRangeForm'>

+        <h3 data-trans="wifi_range_settings" class="form-title"></h3>

+        <div class="content">

+            <div class="row">

+                <label data-trans='wifi_range' class="col-xs-3"></label>

+                <div class="col-xs-8">

+                    <input id='short_mode' data-bind="checked: wifiRangeMode" name="rangeGroup" type="radio" value="short_mode"/>

+                    <label data-bind="visible: !isCPE" data-trans='wifi_short_mode' for='short_mode'></label>

+                    <label data-bind="visible: isCPE" data-trans='wifi_des_short_mode' for='short_mode'></label>

+                </div>

+            </div>

+            <div class="row">

+                <label class="col-xs-3"></label>

+                <div class="col-xs-8">

+                    <input id='medium_mode' data-bind="checked: wifiRangeMode" name="rangeGroup" type="radio" value="medium_mode"/>

+                    <label data-trans='wifi_medium_mode' for='medium_mode'></label>

+                </div>

+            </div>

+            <div class="row">

+                <label class="col-xs-3"></label>

+                <div class="col-xs-8">

+                    <input id='long_mode' data-bind="checked: wifiRangeMode" name="rangeGroup" type="radio" value="long_mode"/>

+                    <label data-trans='wifi_long_mode' for='long_mode'></label>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="wifi_range_note_range"></li>

+                <li class="no-style">

+                    <ul data-bind="visible: !isCPE">

+                        <li data-trans="wifi_range_note_short"></li>

+                        <li data-trans="wifi_range_note_medium"></li>

+                        <li data-trans="wifi_range_note_long"></li>

+                    </ul>

+                    <ul data-bind="visible: isCPE">

+                        <li data-trans="wifi_range_note_short_cpe"></li>

+                        <li data-trans="wifi_range_note_medium_cpe"></li>

+                        <li data-trans="wifi_range_note_long_cpe"></li>

+                    </ul>

+                </li>

+            </ul>

+        </div>

+    </form>

+    <form id="frmTsw" data-bind="visible: showTSWDiv">

+        <div class="form-body">

+            <h3 data-trans="time_sleep_wake_up" class="form-title"></h3>

+            <div class="content">

+                <div class="row form-group">

+                    <label data-trans="tsw_settings" class="col-xs-3 side-right"></label>

+                    <div class="col-xs-6">

+                        <div class="row">

+                            <div class="col-xs-4">

+                                <input id="tswEnable" data-bind="checked: openEnable" name="tswGrp" type="radio" value="1"/>

+                                <label data-trans="enable" for="tswEnable"></label>

+                            </div>

+                            <div class="col-xs-4">

+                                <input id="tswDisable" data-bind="checked: openEnable" name="tswGrp" type="radio" value="0"/>

+                                <label for="tswDisable" data-trans="disable"></label>

+                            </div>

+                        </div>

+                    </div>

+                </div>

+                <div data-bind="visible: openEnable() == '1'" class="row form-group">

+                    <div class="col-xs-3">

+                        <span data-trans="tsw_timer_on"></span>

+                    </div>

+                    <div class="col-xs-9">

+                        <div>

+                            <input id="openH" data-bind="value: openH" min="0" max="23" maxlength="2" name="openH" style="width: 27px;display:inline-block;padding: 5px 4px;" type="text" class="required form-control"> :

+                            <input id="openM" data-bind="value: openM" min="0" max="59" maxlength="2" name="openM" style="width: 27px;display:inline-block;padding: 5px 4px;" type="text" class="required form-control">

+                        </div>

+                    </div>

+                    <div id="openErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+                <div data-bind="visible: openEnable() == '1'" class="row form-group">

+                    <div class="col-xs-3">

+                        <span data-trans="tsw_timer_off"></span>

+                    </div>

+                    <div class="col-xs-9">

+                        <input id="closeH" data-bind="value: closeH" min="0" max="23" maxlength="2" name="closeH" style="width: 27px;display:inline-block;padding: 5px 4px;" type="text" class="required form-control"> :

+                        <input id="closeM" data-bind="value: closeM" min="0" max="59" maxlength="2" name="closeM" style="width: 27px;display:inline-block;padding: 5px 4px;" type="text" class="required form-control">

+                    </div>

+                    <div id="closeErrorDiv" class="col-xs-9 col-md-offset-3"></div>

+                </div>

+            </div>

+            <div class="form-buttons">

+                <input data-trans="apply" type="submit" formmethod="post" class="btn btn-primary"/>

+            </div>

+            <div class="form-note">

+                <div class="notes-title">&nbsp;</div>

+                <ul class="notes-content">

+                    <li data-trans="tsw_note"></li>

+                    <li data-trans="tsw_note_on"></li>

+                    <li data-trans="tsw_note_off"></li>

+                </ul>

+            </div>

+        </div>

+    </form>

+    <form id='sleepModeForm' data-bind="visible: showSleepDiv">

+        <h3 data-trans='wifi_sleep' class="form-title"></h3>

+        <div class="content">

+            <div class="row">

+                <label data-trans='sleep_time' class="col-xs-3" for='mode'></label>

+                <div class="col-xs-4">

+                <select id="mode" data-bind="options: modes, value: selectedMode, optionsText: transOption('sleep_mode'), optionsValue: 'value'" data-transid='sleep_mode' class="form-control"></select>

+                </div>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="wifi_sleep_note_info"></li>

+            </ul>

+        </div>

+    </form>

+</div>

+    </div>

+</div>

+</div>
\ No newline at end of file
diff --git a/ap/app/zte_webui_min/subpg/wifi_station_info.html b/ap/app/zte_webui_min/subpg/wifi_station_info.html
new file mode 100755
index 0000000..50b8738
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_station_info.html
@@ -0,0 +1,122 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title form-title-multi">

+                <h1 data-trans='station_info'></h1>

+                <p data-trans="station_info_sub_title"></p>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-1 margin-top-15">

+        </div>

+        <div class="col-xs-11">

+

+<div id="station_info_div" class="form-body">

+	<div class="content ko-grid-container">

+        <div id="wireless_div">

+            <h2 data-trans="wireless_access_device"></h2>

+            <table class="table table-striped table-hover">

+                <thead>

+                    <tr>

+                        <th data-trans="station_number" width="60"></th>

+                        <th data-trans="host_name"></th>

+                        <th width="100"></th>

+                        <th data-trans="mac_address" width="200"></th>

+                        <th data-trans="pc_action" data-bind="visible: supportBlock" width="150"></th>

+                    </tr>

+                </thead>

+                <tbody data-bind="foreach:deviceInfo">

+                    <tr data-bind="css: {odd: $index() % 2 == 0, even: $index() % 2 != 0}">

+                        <td data-bind="text: $index()+1"></td>

+                        <td>

+                            <span data-bind="text: hostName, attr: {id: 'hostname_txt_'+idx}"></span>

+                            <input data-bind="attr: {id: 'hostname_input_'+idx}" maxlength="20" style="display: none;" type="text" class="form-control">

+                        </td>

+                        <td>

+                            <a data-bind="click: $root.editHostNameHandler, attr: {id: 'edit_btn_'+idx}" class="cursorhand"><img height="25" src="./pic/res_edit.png"></a>

+                            <a data-bind="click: $root.saveHostNameHandler, attr: {id: 'save_btn_'+idx}" style="display: none;" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a data-bind="click: $root.cancelEditHostNameHandler, attr: {id: 'cancel_btn_'+idx}" style="display: none;" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                        </td>

+                        <td data-bind="text: macAddress"></td>

+                        <td data-bind="visible: $root.supportBlock"><a data-trans="block" data-bind="visible: !inBlackGroup, css: {'not-allowed': disableFlag}, click: $root.wirelessBlockHandler" class="btn btn-primary btn-sm"></a></td>

+                    </tr>

+                </tbody>

+            </table>

+            <p data-bind="visible: deviceInfo().length == 0" data-trans="no_data"></p>

+        </div>

+

+        <div id="cable_div" data-bind="visible: showCableDiv">

+            <h2 data-trans="cable_access_device"></h2>

+            <table class="table table-striped table-hover">

+                <thead>

+                <tr>

+                    <th data-trans="station_number" width="60"></th>

+                    <th data-trans="host_name"></th>

+                    <th width="100"></th>

+                    <th data-trans="mac_address" width="350"></th>

+                </tr>

+                </thead>

+                <tbody data-bind="foreach:cableDeviceInfo">

+                    <tr data-bind="css: {odd: $index() % 2 == 0, even: $index() % 2 != 0}">

+                        <td data-bind="text: $index()+1"></td>

+                        <td>

+                            <span data-bind="text: hostName, attr: {id: 'hostname_txt_'+idx}"></span>

+                            <input data-bind="attr: {id: 'hostname_input_'+idx}" maxlength="20" type="text" style="display: none;" class="form-control">

+                        </td>

+                        <td>

+                            <a data-bind="click: $root.editHostNameHandler, attr: {id: 'edit_btn_'+idx}" class="cursorhand" ><img height="25" src="./pic/res_edit.png"></a>

+                            <a data-bind="click: $root.saveHostNameHandler, attr: {id: 'save_btn_'+idx}" style="display: none;" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a data-bind="click: $root.cancelEditHostNameHandler, attr: {id: 'cancel_btn_'+idx}" style="display: none;" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                        </td>

+                        <td data-bind="text: macAddress"></td>

+                    </tr>

+                </tbody>

+            </table>

+            <p data-bind="visible: cableDeviceInfo().length == 0" data-trans="no_data"></p>

+        </div>

+

+        <div id="black_div" data-bind="visible: showBlackDiv">

+            <h2 data-trans="black_list"></h2>

+            <table class="table table-striped table-hover">

+                <thead>

+                    <tr>

+                        <th data-trans="station_number" width="60"></th>

+                        <th data-trans="host_name" style="display:none"></th>

+                        <th style="display:none" width="100"></th>

+                        <th data-trans="mac_address"></th>

+                        <th data-trans="pc_action" width="150"></th>

+                    </tr>

+                </thead>

+                <tbody data-bind="foreach:blackDevices">

+                    <tr data-bind="css: {odd: $index() % 2 == 0, even: $index() % 2 != 0}">

+                        <td data-bind="text: $index()+1"></td>

+                        <td style="display:none">

+                            <span data-bind="text: hostName, attr: {id: 'hostname_txt_'+idx}"></span>

+                            <input data-bind="attr: {id: 'hostname_input_'+idx}" maxlength="20" style="display: none;" type="text" class="form-control">

+                        </td>

+                        <td style="display:none">

+                            <a data-bind="click: $root.editHostNameHandler, attr: {id: 'edit_btn_'+idx}" class="cursorhand"><img height="25" src="./pic/res_edit.png"></a>

+                            <a data-bind="click: $root.saveHostNameHandler, attr: {id: 'save_btn_'+idx}" style="display: none;" class="cursorhand"><img height="25" src="./pic/res_save.png"></a>

+                            <a data-bind="click: $root.cancelEditHostNameHandler, attr: {id: 'cancel_btn_'+idx}" style="display: none;" class="cursorhand"><img height="25" src="./pic/res_cancel.png"></a>

+                        </td>

+                        <td data-bind="text: macAddress"></td>

+                        <td><a data-trans="pc_remove" data-bind="click: $root.blacklistRemoveHandler" class="btn btn-primary btn-sm"></a></td>

+                    </tr>

+                </tbody>

+            </table>

+        </div>

+

+        <div data-bind="visible: showPCLink">

+            <span data-trans="station_info_desc"></span> <a data-trans="parental_control" href="#child_ctl"></a>

+        </div>

+    </div>

+</div>

+    </div>

+</div>

+</div>

diff --git a/ap/app/zte_webui_min/subpg/wifi_wps.html b/ap/app/zte_webui_min/subpg/wifi_wps.html
new file mode 100755
index 0000000..31785c3
--- /dev/null
+++ b/ap/app/zte_webui_min/subpg/wifi_wps.html
@@ -0,0 +1,122 @@
+<div id="innerContainer">

+    <div class="row header-row">

+        <div class="col-xs-1">

+            <a href="#main">

+                <img alt="" src="pic/direct-back.png">

+            </a>

+        </div>

+        <div class="col-xs-11">

+            <div class="form-title form-title-multi">

+                <h1 data-trans='wifi_wireless_settings'></h1>

+                <p data-trans="wifi_main_sub_title"></p>

+            </div>

+        </div>

+    </div>

+    <div class="row">

+        <div class="col-xs-2">

+		    <div class="nav_right">

+				<ul data-bind="visible: isShowSSIDInfoDiv">

+					<li><a data-trans="multi_ssid_1" data-bind="attr:{'data-trans': hasMultiSSID ? 'multi_ssid_1':'ssid_title'}" href="#wlan_main"></a></li>

+					<li data-bind="visible: hasMultiSSID"><a data-trans="multi_ssid_2" href="#wlan_guset"></a></li>

+					<li class="active"><a data-trans="wps" href="#wlan_wps"></a></li>

+					<li data-bind="visible: hasAPStation"><a data-trans="ap_station" href="#wlan_station"></a></li>

+					<li><a data-trans="wifi_advance" href="#wlan_adv"></a></li>

+					<li data-bind="visible: hasWlanMacfilter"><a data-trans="mac_filter" href="#filter_mac"></a></li>

+				</ul>

+			</div>

+		</div>

+        <div class="col-xs-10">

+

+<div class="form-body">

+    <form id="frmWifiSwitch" role="form">

+        <div class="content margin-top-20">

+            <div data-bind="visible: hasWifiSwitch" class="row form-group">

+                <label data-trans="wifi_switch" class="col-xs-4 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_enable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="wifi_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="wifi_switch_disable"

+                                   data-bind="checked: wifi_enable" name="wifi_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="wifi_switch_disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div data-bind="visible: wifi_enable() == '1' && hasMultiSSID" class="row form-group">

+                <label data-trans="multi_ssid_enable" class="col-xs-4 side-right"></label>

+                <div class="col-xs-6">

+                    <div class="row">

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_enable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="1"/>

+                            <label data-trans="enable" for="multi_ssid_switch_enable"></label>

+                        </div>

+                        <div class="col-xs-4">

+                            <input id="multi_ssid_switch_disable"

+                                   data-bind="checked: multi_ssid_enable" name="multi_ssid_switch" type="radio" value="0"/>

+                            <label data-trans="disable" for="multi_ssid_switch_disable"></label>

+                        </div>

+                    </div>

+                </div>

+            </div>

+            <div data-bind="visible: hasWifiSwitch || (wifi_enable() == '1' && hasMultiSSID)" class="form-buttons">

+                <input id="wifi_switch_apply" data-trans='apply' type="submit" formmethod="post" class="btn btn-primary"/>

+                <!--input id="wifi_switch_cancel" type="button" class="btn-1 " data-bind='click: function(){clear("switch");}' data-trans='cancel'/-->

+            </div>

+        </div>

+    </form>

+

+    <div data-bind="visible: isShowSSIDInfoDiv" class="content">

+        <form id='wpsForm' role="form">

+	    <h3 data-bind="attr:{'data-trans': 'wps'}" class="form-title"></h3>

+        <div data-bind="visible: hasMultiSSID" class="row form-group">

+            <label data-trans='ssid_title' for="multiSSID" class="col-xs-4 side-right"></label>

+            <div class="col-xs-4">

+                <select id="multiSSID" data-bind="options: mulOption, value: wpsSSID, optionsValue: 'value', optionsText: 'text'" class="valid form-control">

+				</select>

+            </div>

+        </div>

+		<div class="row form-group">

+            <label data-trans="wps" class="col-xs-4 side-right"></label>

+            <div class="col-xs-6">

+                <div class="row">

+                    <div class="col-xs-4">

+                        <input id="pinMode" data-bind="checked: wpsType" name="wpsMode" type="radio" value="PIN"/>

+                        <label data-trans="wps_pin" for="pinMode"></label>

+                    </div>

+                    <div class="col-xs-6">

+                        <input id="txtPin" data-bind="value: wpsPin, enable: wpsType() == 'PIN', valueUpdate: 'keypress'" maxlength="9" name="txtPin" type="text" class="required margin-left-5  form-control"/>

+                    </div>

+                </div>

+            </div>

+        </div>

+        <div class="row form-group">

+            <label class="col-xs-4 side-right"></label>

+            <div class="col-xs-6">

+                <input id="pbcMode" data-bind="checked: wpsType" name="wpsMode" type="radio" value="PBC"/>

+                <label data-trans="wps_pbc" for="pbcMode"></label>

+            </div>

+        </div>

+        <div class="form-buttons">

+            <input data-bind="enable: wpsType() != '', css:{disabled: wpsType() == ''}" class="btn btn-primary" data-trans='apply' type="submit" formmethod="post"/>

+        </div>

+        <div class="form-note">

+            <div class="notes-title">&nbsp;</div>

+            <ul class="notes-content">

+                <li data-trans="wps_note_all"></li>

+                <li data-trans="wps_note_pin"></li>

+                <li data-trans="wps_note_pbc"></li>

+                <li data-trans="wps_note_wait"></li>

+            </ul>

+        </div>

+        </form>

+    </div>

+</div>

+    </div>

+</div>

+</div>
\ No newline at end of file