Browse Source

报表&版本管理

likeku 8 years ago
commit
52d22a6f1b
100 changed files with 27171 additions and 0 deletions
  1. 6800 0
      global/css/bootstrap.css
  2. 5 0
      global/css/bootstrap.min.css
  3. 347 0
      global/css/codemirror/codemirror.css
  4. 41 0
      global/css/codemirror/dracula.css
  5. 54 0
      global/css/codemirror/material.css
  6. 41 0
      global/css/codemirror/theme/3024-day.css
  7. 39 0
      global/css/codemirror/theme/3024-night.css
  8. 32 0
      global/css/codemirror/theme/abcdef.css
  9. 5 0
      global/css/codemirror/theme/ambiance-mobile.css
  10. 74 0
      global/css/codemirror/theme/ambiance.css
  11. 38 0
      global/css/codemirror/theme/base16-dark.css
  12. 38 0
      global/css/codemirror/theme/base16-light.css
  13. 34 0
      global/css/codemirror/theme/bespin.css
  14. 32 0
      global/css/codemirror/theme/blackboard.css
  15. 25 0
      global/css/codemirror/theme/cobalt.css
  16. 33 0
      global/css/codemirror/theme/colorforth.css
  17. 40 0
      global/css/codemirror/theme/dracula.css
  18. 35 0
      global/css/codemirror/theme/duotone-dark.css
  19. 36 0
      global/css/codemirror/theme/duotone-light.css
  20. 23 0
      global/css/codemirror/theme/eclipse.css
  21. 13 0
      global/css/codemirror/theme/elegant.css
  22. 34 0
      global/css/codemirror/theme/erlang-dark.css
  23. 34 0
      global/css/codemirror/theme/hopscotch.css
  24. 43 0
      global/css/codemirror/theme/icecoder.css
  25. 34 0
      global/css/codemirror/theme/isotope.css
  26. 47 0
      global/css/codemirror/theme/lesser-dark.css
  27. 95 0
      global/css/codemirror/theme/liquibyte.css
  28. 53 0
      global/css/codemirror/theme/material.css
  29. 37 0
      global/css/codemirror/theme/mbo.css
  30. 46 0
      global/css/codemirror/theme/mdn-like.css
  31. 45 0
      global/css/codemirror/theme/midnight.css
  32. 36 0
      global/css/codemirror/theme/monokai.css
  33. 12 0
      global/css/codemirror/theme/neat.css
  34. 43 0
      global/css/codemirror/theme/neo.css
  35. 27 0
      global/css/codemirror/theme/night.css
  36. 85 0
      global/css/codemirror/theme/panda-syntax.css
  37. 38 0
      global/css/codemirror/theme/paraiso-dark.css
  38. 38 0
      global/css/codemirror/theme/paraiso-light.css
  39. 52 0
      global/css/codemirror/theme/pastel-on-dark.css
  40. 34 0
      global/css/codemirror/theme/railscasts.css
  41. 25 0
      global/css/codemirror/theme/rubyblue.css
  42. 44 0
      global/css/codemirror/theme/seti.css
  43. 169 0
      global/css/codemirror/theme/solarized.css
  44. 30 0
      global/css/codemirror/theme/the-matrix.css
  45. 35 0
      global/css/codemirror/theme/tomorrow-night-bright.css
  46. 38 0
      global/css/codemirror/theme/tomorrow-night-eighties.css
  47. 64 0
      global/css/codemirror/theme/ttcn.css
  48. 32 0
      global/css/codemirror/theme/twilight.css
  49. 34 0
      global/css/codemirror/theme/vibrant-ink.css
  50. 53 0
      global/css/codemirror/theme/xq-dark.css
  51. 43 0
      global/css/codemirror/theme/xq-light.css
  52. 44 0
      global/css/codemirror/theme/yeti.css
  53. 37 0
      global/css/codemirror/theme/zenburn.css
  54. BIN
      global/css/login-bg-fc.jpg
  55. BIN
      global/css/login-bg.jpg
  56. 118 0
      global/css/style.css
  57. BIN
      global/fonts/glyphicons-halflings-regular.eot
  58. 288 0
      global/fonts/glyphicons-halflings-regular.svg
  59. BIN
      global/fonts/glyphicons-halflings-regular.ttf
  60. BIN
      global/fonts/glyphicons-halflings-regular.woff
  61. BIN
      global/fonts/glyphicons-halflings-regular.woff2
  62. 2363 0
      global/js/bootstrap.js
  63. 7 0
      global/js/bootstrap.min.js
  64. 8935 0
      global/js/codemirror/codemirror.js
  65. 825 0
      global/js/codemirror/css.js
  66. 105 0
      global/js/codemirror/fold/brace-fold.js
  67. 59 0
      global/js/codemirror/fold/comment-fold.js
  68. 150 0
      global/js/codemirror/fold/foldcode.js
  69. 20 0
      global/js/codemirror/fold/foldgutter.css
  70. 146 0
      global/js/codemirror/fold/foldgutter.js
  71. 48 0
      global/js/codemirror/fold/indent-fold.js
  72. 49 0
      global/js/codemirror/fold/markdown-fold.js
  73. 182 0
      global/js/codemirror/fold/xml-fold.js
  74. 743 0
      global/js/codemirror/javascript.js
  75. 394 0
      global/js/codemirror/xml.js
  76. 28 0
      global/js/global.js
  77. 5 0
      global/js/jquery-1.9.1.min.js
  78. 13 0
      global/js/npm.js
  79. 33 0
      index.php
  80. 291 0
      jlzfver.sql
  81. 254 0
      protected/class/PasswordHash.php
  82. 661 0
      protected/class/client.php
  83. 117 0
      protected/config/common.conf.php
  84. 36 0
      protected/config/db.conf.php
  85. 113 0
      protected/config/routes.conf.php
  86. 218 0
      protected/controller/ApiController.php
  87. 209 0
      protected/controller/BaseController.php
  88. 260 0
      protected/controller/HostController.php
  89. 875 0
      protected/controller/MainController.php
  90. 58 0
      protected/model/category.php
  91. 30 0
      protected/model/fcuser.php
  92. 33 0
      protected/model/hosts.php
  93. 49 0
      protected/model/item.php
  94. 30 0
      protected/model/log.php
  95. 23 0
      protected/model/migrations.php
  96. 23 0
      protected/model/passwordreset.php
  97. 56 0
      protected/model/report.php
  98. 28 0
      protected/model/servers.php
  99. 30 0
      protected/model/upgradelogs.php
  100. 0 0
      protected/model/version.php

File diff suppressed because it is too large
+ 6800 - 0
global/css/bootstrap.css


File diff suppressed because it is too large
+ 5 - 0
global/css/bootstrap.min.css


+ 347 - 0
global/css/codemirror/codemirror.css

@@ -0,0 +1,347 @@
+/* BASICS */
+
+.CodeMirror {
+  /* Set height, width, borders, and global font properties here */
+  font-family: monospace;
+  height:300px;
+  color: black;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+  padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+  padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+  border-right: 1px solid #ddd;
+  background-color: #f7f7f7;
+  white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+  padding: 0 3px 0 5px;
+  min-width: 20px;
+  text-align: right;
+  color: #999;
+  white-space: nowrap;
+}
+
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
+/* CURSOR */
+
+.CodeMirror-cursor {
+  border-left: 1px solid black;
+  border-right: none;
+  width: 0;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+  border-left: 1px solid silver;
+}
+.cm-fat-cursor .CodeMirror-cursor {
+  width: auto;
+  border: 0 !important;
+  background: #7e7;
+}
+.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+  width: auto;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+  background-color: #7e7;
+}
+@-moz-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@-webkit-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+
+/* Can style cursor different in overwrite (non-insert) mode */
+.CodeMirror-overwrite .CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-rulers {
+  position: absolute;
+  left: 0; right: 0; top: -50px; bottom: -20px;
+  overflow: hidden;
+}
+.CodeMirror-ruler {
+  border-left: 1px solid #ccc;
+  top: 0; bottom: 0;
+  position: absolute;
+}
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-s-default .cm-error {color: #f00;}
+.cm-invalidchar {color: #f00;}
+
+.CodeMirror-composing { border-bottom: 2px solid; }
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+   the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+  position: relative;
+  overflow: hidden;
+  background: white;
+}
+
+.CodeMirror-scroll {
+  overflow: scroll !important; /* Things will break if this is overridden */
+  /* 30px is the magic margin used to hide the element's real scrollbars */
+  /* See overflow: hidden in .CodeMirror */
+  margin-bottom: -30px; margin-right: -30px;
+  padding-bottom: 30px;
+  height: 100%;
+  outline: none; /* Prevent dragging from highlighting the element */
+  position: relative;
+}
+.CodeMirror-sizer {
+  position: relative;
+  border-right: 30px solid transparent;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+   before actual scrolling happens, thus preventing shaking and
+   flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  position: absolute;
+  z-index: 6;
+  display: none;
+}
+.CodeMirror-vscrollbar {
+  right: 0; top: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+  bottom: 0; left: 0;
+  overflow-y: hidden;
+  overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+  right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+  left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+  position: absolute; left: 0; top: 0;
+  min-height: 100%;
+  z-index: 3;
+}
+.CodeMirror-gutter {
+  white-space: normal;
+  height: 100%;
+  display: inline-block;
+  vertical-align: top;
+  margin-bottom: -30px;
+  /* Hack to make IE7 behave */
+  *zoom:1;
+  *display:inline;
+}
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  background: none !important;
+  border: none !important;
+}
+.CodeMirror-gutter-background {
+  position: absolute;
+  top: 0; bottom: 0;
+  z-index: 4;
+}
+.CodeMirror-gutter-elt {
+  position: absolute;
+  cursor: default;
+  z-index: 4;
+}
+.CodeMirror-gutter-wrapper {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+
+.CodeMirror-lines {
+  cursor: text;
+  min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+  /* Reset some styles that the rest of the page might have set */
+  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+  border-width: 0;
+  background: transparent;
+  font-family: inherit;
+  font-size: inherit;
+  margin: 0;
+  white-space: pre;
+  word-wrap: normal;
+  line-height: inherit;
+  color: inherit;
+  z-index: 2;
+  position: relative;
+  overflow: visible;
+  -webkit-tap-highlight-color: transparent;
+  -webkit-font-variant-ligatures: none;
+  font-variant-ligatures: none;
+}
+.CodeMirror-wrap pre {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  word-break: normal;
+}
+
+.CodeMirror-linebackground {
+  position: absolute;
+  left: 0; right: 0; top: 0; bottom: 0;
+  z-index: 0;
+}
+
+.CodeMirror-linewidget {
+  position: relative;
+  z-index: 2;
+  overflow: auto;
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-code {
+  outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+.CodeMirror-measure {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  overflow: hidden;
+  visibility: hidden;
+}
+
+.CodeMirror-cursor {
+  position: absolute;
+  pointer-events: none;
+}
+.CodeMirror-measure pre { position: static; }
+
+div.CodeMirror-cursors {
+  visibility: hidden;
+  position: relative;
+  z-index: 3;
+}
+div.CodeMirror-dragcursors {
+  visibility: visible;
+}
+
+.CodeMirror-focused div.CodeMirror-cursors {
+  visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
+
+.cm-searching {
+  background: #ffa;
+  background: rgba(255, 255, 0, .4);
+}
+
+/* IE7 hack to prevent it from returning funny offsetTops on the spans */
+.CodeMirror span { *vertical-align: text-bottom; }
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+  /* Hide the cursor when printing */
+  .CodeMirror div.CodeMirror-cursors {
+    visibility: hidden;
+  }
+}
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }

+ 41 - 0
global/css/codemirror/dracula.css

@@ -0,0 +1,41 @@
+/*
+
+    Name:       dracula
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)
+
+    Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme)
+
+*/
+
+
+.cm-s-dracula.CodeMirror, .cm-s-dracula .CodeMirror-gutters {
+  background-color: #282a36 !important;
+  color: #f8f8f2 !important;
+  border: none;
+}
+.cm-s-dracula .CodeMirror-gutters { color: #282a36; }
+.cm-s-dracula .CodeMirror-cursor { border-left: solid thin #f8f8f0; }
+.cm-s-dracula .CodeMirror-linenumber { color: #6D8A88; }
+.cm-s-dracula.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
+.cm-s-dracula .CodeMirror-line::selection, .cm-s-dracula .CodeMirror-line > span::selection, .cm-s-dracula .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-dracula .CodeMirror-line::-moz-selection, .cm-s-dracula .CodeMirror-line > span::-moz-selection, .cm-s-dracula .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-dracula span.cm-comment { color: #6272a4; }
+.cm-s-dracula span.cm-string, .cm-s-dracula span.cm-string-2 { color: #f1fa8c; }
+.cm-s-dracula span.cm-number { color: #bd93f9; }
+.cm-s-dracula span.cm-variable { color: #50fa7b; }
+.cm-s-dracula span.cm-variable-2 { color: white; }
+.cm-s-dracula span.cm-def { color: #ffb86c; }
+.cm-s-dracula span.cm-keyword { color: #ff79c6; }
+.cm-s-dracula span.cm-operator { color: #ff79c6; }
+.cm-s-dracula span.cm-keyword { color: #ff79c6; }
+.cm-s-dracula span.cm-atom { color: #bd93f9; }
+.cm-s-dracula span.cm-meta { color: #f8f8f2; }
+.cm-s-dracula span.cm-tag { color: #ff79c6; }
+.cm-s-dracula span.cm-attribute { color: #50fa7b; }
+.cm-s-dracula span.cm-qualifier { color: #50fa7b; }
+.cm-s-dracula span.cm-property { color: #66d9ef; }
+.cm-s-dracula span.cm-builtin { color: #50fa7b; }
+.cm-s-dracula span.cm-variable-3 { color: #50fa7b; }
+
+.cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); }
+.cm-s-dracula .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 54 - 0
global/css/codemirror/material.css

@@ -0,0 +1,54 @@
+/*
+
+    Name:       material
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)
+
+    Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)
+
+*/
+
+.cm-s-material {
+  background-color: #263238;
+  color: rgba(233, 237, 237, 1);
+}
+.cm-s-material .CodeMirror-gutters {
+  background: #263238;
+  color: rgb(83,127,126);
+  border: none;
+  border-right:1px solid #334047
+}
+.cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); }
+.cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
+.cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }
+.cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
+.cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
+
+.cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); }
+.cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); }
+.cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }
+.cm-s-material .cm-variable-2 { color: #80CBC4; }
+.cm-s-material .cm-variable-3 { color: #82B1FF; }
+.cm-s-material .cm-builtin { color: #DECB6B; }
+.cm-s-material .cm-atom { color: #F77669; }
+.cm-s-material .cm-number { color: #F77669; }
+.cm-s-material .cm-def { color: rgba(233, 237, 237, 1); }
+.cm-s-material .cm-string { color: #C3E88D; }
+.cm-s-material .cm-string-2 { color: #80CBC4; }
+.cm-s-material .cm-comment { color: #546E7A; }
+.cm-s-material .cm-variable { color: #82B1FF; }
+.cm-s-material .cm-tag { color: #80CBC4; }
+.cm-s-material .cm-meta { color: #80CBC4; }
+.cm-s-material .cm-attribute { color: #FFCB6B; }
+.cm-s-material .cm-property { color: #80CBAE; }
+.cm-s-material .cm-qualifier { color: #DECB6B; }
+.cm-s-material .cm-variable-3 { color: #DECB6B; }
+.cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }
+.cm-s-material .cm-error {
+  color: rgba(255, 255, 255, 1.0);
+  background-color: #EC5F67;
+}
+.cm-s-material .CodeMirror-matchingbracket {
+  text-decoration: underline;
+  color: white !important;
+}

+ 41 - 0
global/css/codemirror/theme/3024-day.css

@@ -0,0 +1,41 @@
+/*
+
+    Name:       3024 day
+    Author:     Jan T. Sott (http://github.com/idleberg)
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-3024-day.CodeMirror { background: #f7f7f7; color: #3a3432; }
+.cm-s-3024-day div.CodeMirror-selected { background: #d6d5d4; }
+
+.cm-s-3024-day .CodeMirror-line::selection, .cm-s-3024-day .CodeMirror-line > span::selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d6d5d4; }
+.cm-s-3024-day .CodeMirror-line::-moz-selection, .cm-s-3024-day .CodeMirror-line > span::-moz-selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d9d9d9; }
+
+.cm-s-3024-day .CodeMirror-gutters { background: #f7f7f7; border-right: 0px; }
+.cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; }
+.cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; }
+.cm-s-3024-day .CodeMirror-linenumber { color: #807d7c; }
+
+.cm-s-3024-day .CodeMirror-cursor { border-left: 1px solid #5c5855; }
+
+.cm-s-3024-day span.cm-comment { color: #cdab53; }
+.cm-s-3024-day span.cm-atom { color: #a16a94; }
+.cm-s-3024-day span.cm-number { color: #a16a94; }
+
+.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute { color: #01a252; }
+.cm-s-3024-day span.cm-keyword { color: #db2d20; }
+.cm-s-3024-day span.cm-string { color: #fded02; }
+
+.cm-s-3024-day span.cm-variable { color: #01a252; }
+.cm-s-3024-day span.cm-variable-2 { color: #01a0e4; }
+.cm-s-3024-day span.cm-def { color: #e8bbd0; }
+.cm-s-3024-day span.cm-bracket { color: #3a3432; }
+.cm-s-3024-day span.cm-tag { color: #db2d20; }
+.cm-s-3024-day span.cm-link { color: #a16a94; }
+.cm-s-3024-day span.cm-error { background: #db2d20; color: #5c5855; }
+
+.cm-s-3024-day .CodeMirror-activeline-background { background: #e8f2ff; }
+.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important; }

+ 39 - 0
global/css/codemirror/theme/3024-night.css

@@ -0,0 +1,39 @@
+/*
+
+    Name:       3024 night
+    Author:     Jan T. Sott (http://github.com/idleberg)
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-3024-night.CodeMirror { background: #090300; color: #d6d5d4; }
+.cm-s-3024-night div.CodeMirror-selected { background: #3a3432; }
+.cm-s-3024-night .CodeMirror-line::selection, .cm-s-3024-night .CodeMirror-line > span::selection, .cm-s-3024-night .CodeMirror-line > span > span::selection { background: rgba(58, 52, 50, .99); }
+.cm-s-3024-night .CodeMirror-line::-moz-selection, .cm-s-3024-night .CodeMirror-line > span::-moz-selection, .cm-s-3024-night .CodeMirror-line > span > span::-moz-selection { background: rgba(58, 52, 50, .99); }
+.cm-s-3024-night .CodeMirror-gutters { background: #090300; border-right: 0px; }
+.cm-s-3024-night .CodeMirror-guttermarker { color: #db2d20; }
+.cm-s-3024-night .CodeMirror-guttermarker-subtle { color: #5c5855; }
+.cm-s-3024-night .CodeMirror-linenumber { color: #5c5855; }
+
+.cm-s-3024-night .CodeMirror-cursor { border-left: 1px solid #807d7c; }
+
+.cm-s-3024-night span.cm-comment { color: #cdab53; }
+.cm-s-3024-night span.cm-atom { color: #a16a94; }
+.cm-s-3024-night span.cm-number { color: #a16a94; }
+
+.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute { color: #01a252; }
+.cm-s-3024-night span.cm-keyword { color: #db2d20; }
+.cm-s-3024-night span.cm-string { color: #fded02; }
+
+.cm-s-3024-night span.cm-variable { color: #01a252; }
+.cm-s-3024-night span.cm-variable-2 { color: #01a0e4; }
+.cm-s-3024-night span.cm-def { color: #e8bbd0; }
+.cm-s-3024-night span.cm-bracket { color: #d6d5d4; }
+.cm-s-3024-night span.cm-tag { color: #db2d20; }
+.cm-s-3024-night span.cm-link { color: #a16a94; }
+.cm-s-3024-night span.cm-error { background: #db2d20; color: #807d7c; }
+
+.cm-s-3024-night .CodeMirror-activeline-background { background: #2F2F2F; }
+.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 32 - 0
global/css/codemirror/theme/abcdef.css

@@ -0,0 +1,32 @@
+.cm-s-abcdef.CodeMirror { background: #0f0f0f; color: #defdef; }
+.cm-s-abcdef div.CodeMirror-selected { background: #515151; }
+.cm-s-abcdef .CodeMirror-line::selection, .cm-s-abcdef .CodeMirror-line > span::selection, .cm-s-abcdef .CodeMirror-line > span > span::selection { background: rgba(56, 56, 56, 0.99); }
+.cm-s-abcdef .CodeMirror-line::-moz-selection, .cm-s-abcdef .CodeMirror-line > span::-moz-selection, .cm-s-abcdef .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 56, 56, 0.99); }
+.cm-s-abcdef .CodeMirror-gutters { background: #555; border-right: 2px solid #314151; }
+.cm-s-abcdef .CodeMirror-guttermarker { color: #222; }
+.cm-s-abcdef .CodeMirror-guttermarker-subtle { color: azure; }
+.cm-s-abcdef .CodeMirror-linenumber { color: #FFFFFF; }
+.cm-s-abcdef .CodeMirror-cursor { border-left: 1px solid #00FF00; }
+
+.cm-s-abcdef span.cm-keyword { color: darkgoldenrod; font-weight: bold; }
+.cm-s-abcdef span.cm-atom { color: #77F; }
+.cm-s-abcdef span.cm-number { color: violet; }
+.cm-s-abcdef span.cm-def { color: #fffabc; }
+.cm-s-abcdef span.cm-variable { color: #abcdef; }
+.cm-s-abcdef span.cm-variable-2 { color: #cacbcc; }
+.cm-s-abcdef span.cm-variable-3, .cm-s-abcdef span.cm-type { color: #def; }
+.cm-s-abcdef span.cm-property { color: #fedcba; }
+.cm-s-abcdef span.cm-operator { color: #ff0; }
+.cm-s-abcdef span.cm-comment { color: #7a7b7c; font-style: italic;}
+.cm-s-abcdef span.cm-string { color: #2b4; }
+.cm-s-abcdef span.cm-meta { color: #C9F; }
+.cm-s-abcdef span.cm-qualifier { color: #FFF700; }
+.cm-s-abcdef span.cm-builtin { color: #30aabc; }
+.cm-s-abcdef span.cm-bracket { color: #8a8a8a; }
+.cm-s-abcdef span.cm-tag { color: #FFDD44; }
+.cm-s-abcdef span.cm-attribute { color: #DDFF00; }
+.cm-s-abcdef span.cm-error { color: #FF0000; }
+.cm-s-abcdef span.cm-header { color: aquamarine; font-weight: bold; }
+.cm-s-abcdef span.cm-link { color: blueviolet; }
+
+.cm-s-abcdef .CodeMirror-activeline-background { background: #314151; }

+ 5 - 0
global/css/codemirror/theme/ambiance-mobile.css

@@ -0,0 +1,5 @@
+.cm-s-ambiance.CodeMirror {
+  -webkit-box-shadow: none;
+  -moz-box-shadow: none;
+  box-shadow: none;
+}

File diff suppressed because it is too large
+ 74 - 0
global/css/codemirror/theme/ambiance.css


+ 38 - 0
global/css/codemirror/theme/base16-dark.css

@@ -0,0 +1,38 @@
+/*
+
+    Name:       Base16 Default Dark
+    Author:     Chris Kempson (http://chriskempson.com)
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-base16-dark.CodeMirror { background: #151515; color: #e0e0e0; }
+.cm-s-base16-dark div.CodeMirror-selected { background: #303030; }
+.cm-s-base16-dark .CodeMirror-line::selection, .cm-s-base16-dark .CodeMirror-line > span::selection, .cm-s-base16-dark .CodeMirror-line > span > span::selection { background: rgba(48, 48, 48, .99); }
+.cm-s-base16-dark .CodeMirror-line::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(48, 48, 48, .99); }
+.cm-s-base16-dark .CodeMirror-gutters { background: #151515; border-right: 0px; }
+.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; }
+.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; }
+.cm-s-base16-dark .CodeMirror-linenumber { color: #505050; }
+.cm-s-base16-dark .CodeMirror-cursor { border-left: 1px solid #b0b0b0; }
+
+.cm-s-base16-dark span.cm-comment { color: #8f5536; }
+.cm-s-base16-dark span.cm-atom { color: #aa759f; }
+.cm-s-base16-dark span.cm-number { color: #aa759f; }
+
+.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute { color: #90a959; }
+.cm-s-base16-dark span.cm-keyword { color: #ac4142; }
+.cm-s-base16-dark span.cm-string { color: #f4bf75; }
+
+.cm-s-base16-dark span.cm-variable { color: #90a959; }
+.cm-s-base16-dark span.cm-variable-2 { color: #6a9fb5; }
+.cm-s-base16-dark span.cm-def { color: #d28445; }
+.cm-s-base16-dark span.cm-bracket { color: #e0e0e0; }
+.cm-s-base16-dark span.cm-tag { color: #ac4142; }
+.cm-s-base16-dark span.cm-link { color: #aa759f; }
+.cm-s-base16-dark span.cm-error { background: #ac4142; color: #b0b0b0; }
+
+.cm-s-base16-dark .CodeMirror-activeline-background { background: #202020; }
+.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 38 - 0
global/css/codemirror/theme/base16-light.css

@@ -0,0 +1,38 @@
+/*
+
+    Name:       Base16 Default Light
+    Author:     Chris Kempson (http://chriskempson.com)
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-base16-light.CodeMirror { background: #f5f5f5; color: #202020; }
+.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; }
+.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; }
+.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }
+.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }
+.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }
+.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }
+.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; }
+.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; }
+
+.cm-s-base16-light span.cm-comment { color: #8f5536; }
+.cm-s-base16-light span.cm-atom { color: #aa759f; }
+.cm-s-base16-light span.cm-number { color: #aa759f; }
+
+.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; }
+.cm-s-base16-light span.cm-keyword { color: #ac4142; }
+.cm-s-base16-light span.cm-string { color: #f4bf75; }
+
+.cm-s-base16-light span.cm-variable { color: #90a959; }
+.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }
+.cm-s-base16-light span.cm-def { color: #d28445; }
+.cm-s-base16-light span.cm-bracket { color: #202020; }
+.cm-s-base16-light span.cm-tag { color: #ac4142; }
+.cm-s-base16-light span.cm-link { color: #aa759f; }
+.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; }
+
+.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; }
+.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 34 - 0
global/css/codemirror/theme/bespin.css

@@ -0,0 +1,34 @@
+/*
+
+    Name:       Bespin
+    Author:     Mozilla / Jan T. Sott
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-bespin.CodeMirror {background: #28211c; color: #9d9b97;}
+.cm-s-bespin div.CodeMirror-selected {background: #36312e !important;}
+.cm-s-bespin .CodeMirror-gutters {background: #28211c; border-right: 0px;}
+.cm-s-bespin .CodeMirror-linenumber {color: #666666;}
+.cm-s-bespin .CodeMirror-cursor {border-left: 1px solid #797977 !important;}
+
+.cm-s-bespin span.cm-comment {color: #937121;}
+.cm-s-bespin span.cm-atom {color: #9b859d;}
+.cm-s-bespin span.cm-number {color: #9b859d;}
+
+.cm-s-bespin span.cm-property, .cm-s-bespin span.cm-attribute {color: #54be0d;}
+.cm-s-bespin span.cm-keyword {color: #cf6a4c;}
+.cm-s-bespin span.cm-string {color: #f9ee98;}
+
+.cm-s-bespin span.cm-variable {color: #54be0d;}
+.cm-s-bespin span.cm-variable-2 {color: #5ea6ea;}
+.cm-s-bespin span.cm-def {color: #cf7d34;}
+.cm-s-bespin span.cm-error {background: #cf6a4c; color: #797977;}
+.cm-s-bespin span.cm-bracket {color: #9d9b97;}
+.cm-s-bespin span.cm-tag {color: #cf6a4c;}
+.cm-s-bespin span.cm-link {color: #9b859d;}
+
+.cm-s-bespin .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
+.cm-s-bespin .CodeMirror-activeline-background { background: #404040; }

+ 32 - 0
global/css/codemirror/theme/blackboard.css

@@ -0,0 +1,32 @@
+/* Port of TextMate's Blackboard theme */
+
+.cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; }
+.cm-s-blackboard div.CodeMirror-selected { background: #253B76; }
+.cm-s-blackboard .CodeMirror-line::selection, .cm-s-blackboard .CodeMirror-line > span::selection, .cm-s-blackboard .CodeMirror-line > span > span::selection { background: rgba(37, 59, 118, .99); }
+.cm-s-blackboard .CodeMirror-line::-moz-selection, .cm-s-blackboard .CodeMirror-line > span::-moz-selection, .cm-s-blackboard .CodeMirror-line > span > span::-moz-selection { background: rgba(37, 59, 118, .99); }
+.cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; }
+.cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; }
+.cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; }
+.cm-s-blackboard .CodeMirror-linenumber { color: #888; }
+.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7; }
+
+.cm-s-blackboard .cm-keyword { color: #FBDE2D; }
+.cm-s-blackboard .cm-atom { color: #D8FA3C; }
+.cm-s-blackboard .cm-number { color: #D8FA3C; }
+.cm-s-blackboard .cm-def { color: #8DA6CE; }
+.cm-s-blackboard .cm-variable { color: #FF6400; }
+.cm-s-blackboard .cm-operator { color: #FBDE2D; }
+.cm-s-blackboard .cm-comment { color: #AEAEAE; }
+.cm-s-blackboard .cm-string { color: #61CE3C; }
+.cm-s-blackboard .cm-string-2 { color: #61CE3C; }
+.cm-s-blackboard .cm-meta { color: #D8FA3C; }
+.cm-s-blackboard .cm-builtin { color: #8DA6CE; }
+.cm-s-blackboard .cm-tag { color: #8DA6CE; }
+.cm-s-blackboard .cm-attribute { color: #8DA6CE; }
+.cm-s-blackboard .cm-header { color: #FF6400; }
+.cm-s-blackboard .cm-hr { color: #AEAEAE; }
+.cm-s-blackboard .cm-link { color: #8DA6CE; }
+.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; }
+
+.cm-s-blackboard .CodeMirror-activeline-background { background: #3C3636; }
+.cm-s-blackboard .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }

+ 25 - 0
global/css/codemirror/theme/cobalt.css

@@ -0,0 +1,25 @@
+.cm-s-cobalt.CodeMirror { background: #002240; color: white; }
+.cm-s-cobalt div.CodeMirror-selected { background: #b36539; }
+.cm-s-cobalt .CodeMirror-line::selection, .cm-s-cobalt .CodeMirror-line > span::selection, .cm-s-cobalt .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); }
+.cm-s-cobalt .CodeMirror-line::-moz-selection, .cm-s-cobalt .CodeMirror-line > span::-moz-selection, .cm-s-cobalt .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); }
+.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }
+.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; }
+.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; }
+.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-cobalt span.cm-comment { color: #08f; }
+.cm-s-cobalt span.cm-atom { color: #845dc4; }
+.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; }
+.cm-s-cobalt span.cm-keyword { color: #ffee80; }
+.cm-s-cobalt span.cm-string { color: #3ad900; }
+.cm-s-cobalt span.cm-meta { color: #ff9d00; }
+.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; }
+.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def, .cm-s-cobalt .cm-type { color: white; }
+.cm-s-cobalt span.cm-bracket { color: #d8d8d8; }
+.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; }
+.cm-s-cobalt span.cm-link { color: #845dc4; }
+.cm-s-cobalt span.cm-error { color: #9d1e15; }
+
+.cm-s-cobalt .CodeMirror-activeline-background { background: #002D57; }
+.cm-s-cobalt .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; }

+ 33 - 0
global/css/codemirror/theme/colorforth.css

@@ -0,0 +1,33 @@
+.cm-s-colorforth.CodeMirror { background: #000000; color: #f8f8f8; }
+.cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }
+.cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; }
+.cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; }
+.cm-s-colorforth .CodeMirror-linenumber { color: #bababa; }
+.cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-colorforth span.cm-comment     { color: #ededed; }
+.cm-s-colorforth span.cm-def         { color: #ff1c1c; font-weight:bold; }
+.cm-s-colorforth span.cm-keyword     { color: #ffd900; }
+.cm-s-colorforth span.cm-builtin     { color: #00d95a; }
+.cm-s-colorforth span.cm-variable    { color: #73ff00; }
+.cm-s-colorforth span.cm-string      { color: #007bff; }
+.cm-s-colorforth span.cm-number      { color: #00c4ff; }
+.cm-s-colorforth span.cm-atom        { color: #606060; }
+
+.cm-s-colorforth span.cm-variable-2  { color: #EEE; }
+.cm-s-colorforth span.cm-variable-3, .cm-s-colorforth span.cm-type { color: #DDD; }
+.cm-s-colorforth span.cm-property    {}
+.cm-s-colorforth span.cm-operator    {}
+
+.cm-s-colorforth span.cm-meta        { color: yellow; }
+.cm-s-colorforth span.cm-qualifier   { color: #FFF700; }
+.cm-s-colorforth span.cm-bracket     { color: #cc7; }
+.cm-s-colorforth span.cm-tag         { color: #FFBD40; }
+.cm-s-colorforth span.cm-attribute   { color: #FFF700; }
+.cm-s-colorforth span.cm-error       { color: #f00; }
+
+.cm-s-colorforth div.CodeMirror-selected { background: #333d53; }
+
+.cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); }
+
+.cm-s-colorforth .CodeMirror-activeline-background { background: #253540; }

+ 40 - 0
global/css/codemirror/theme/dracula.css

@@ -0,0 +1,40 @@
+/*
+
+    Name:       dracula
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)
+
+    Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme)
+
+*/
+
+
+.cm-s-dracula.CodeMirror, .cm-s-dracula .CodeMirror-gutters {
+  background-color: #282a36 !important;
+  color: #f8f8f2 !important;
+  border: none;
+}
+.cm-s-dracula .CodeMirror-gutters { color: #282a36; }
+.cm-s-dracula .CodeMirror-cursor { border-left: solid thin #f8f8f0; }
+.cm-s-dracula .CodeMirror-linenumber { color: #6D8A88; }
+.cm-s-dracula .CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
+.cm-s-dracula .CodeMirror-line::selection, .cm-s-dracula .CodeMirror-line > span::selection, .cm-s-dracula .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-dracula .CodeMirror-line::-moz-selection, .cm-s-dracula .CodeMirror-line > span::-moz-selection, .cm-s-dracula .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-dracula span.cm-comment { color: #6272a4; }
+.cm-s-dracula span.cm-string, .cm-s-dracula span.cm-string-2 { color: #f1fa8c; }
+.cm-s-dracula span.cm-number { color: #bd93f9; }
+.cm-s-dracula span.cm-variable { color: #50fa7b; }
+.cm-s-dracula span.cm-variable-2 { color: white; }
+.cm-s-dracula span.cm-def { color: #50fa7b; }
+.cm-s-dracula span.cm-operator { color: #ff79c6; }
+.cm-s-dracula span.cm-keyword { color: #ff79c6; }
+.cm-s-dracula span.cm-atom { color: #bd93f9; }
+.cm-s-dracula span.cm-meta { color: #f8f8f2; }
+.cm-s-dracula span.cm-tag { color: #ff79c6; }
+.cm-s-dracula span.cm-attribute { color: #50fa7b; }
+.cm-s-dracula span.cm-qualifier { color: #50fa7b; }
+.cm-s-dracula span.cm-property { color: #66d9ef; }
+.cm-s-dracula span.cm-builtin { color: #50fa7b; }
+.cm-s-dracula span.cm-variable-3, .cm-s-dracula span.cm-type { color: #ffb86c; }
+
+.cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); }
+.cm-s-dracula .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 35 - 0
global/css/codemirror/theme/duotone-dark.css

@@ -0,0 +1,35 @@
+/*
+Name:   DuoTone-Dark
+Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
+
+CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/)
+*/
+
+.cm-s-duotone-dark.CodeMirror { background: #2a2734; color: #6c6783; }
+.cm-s-duotone-dark div.CodeMirror-selected { background: #545167!important; }
+.cm-s-duotone-dark .CodeMirror-gutters { background: #2a2734; border-right: 0px; }
+.cm-s-duotone-dark .CodeMirror-linenumber { color: #545167; }
+
+/* begin cursor */
+.cm-s-duotone-dark .CodeMirror-cursor { border-left: 1px solid #ffad5c; /* border-left: 1px solid #ffad5c80; */ border-right: .5em solid #ffad5c; /* border-right: .5em solid #ffad5c80; */ opacity: .5; }
+.cm-s-duotone-dark .CodeMirror-activeline-background { background: #363342; /* background: #36334280;  */ opacity: .5;}
+.cm-s-duotone-dark .cm-fat-cursor .CodeMirror-cursor { background: #ffad5c; /* background: #ffad5c80; */ opacity: .5;}
+/* end cursor */
+
+.cm-s-duotone-dark span.cm-atom, .cm-s-duotone-dark span.cm-number, .cm-s-duotone-dark span.cm-keyword, .cm-s-duotone-dark span.cm-variable, .cm-s-duotone-dark span.cm-attribute, .cm-s-duotone-dark span.cm-quote, .cm-s-duotone-dark span.cm-hr, .cm-s-duotone-dark span.cm-link { color: #ffcc99; }
+
+.cm-s-duotone-dark span.cm-property { color: #9a86fd; }
+.cm-s-duotone-dark span.cm-punctuation, .cm-s-duotone-dark span.cm-unit, .cm-s-duotone-dark span.cm-negative { color: #e09142; }
+.cm-s-duotone-dark span.cm-string { color: #ffb870; }
+.cm-s-duotone-dark span.cm-operator { color: #ffad5c; }
+.cm-s-duotone-dark span.cm-positive { color: #6a51e6; }
+
+.cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-type, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; }
+.cm-s-duotone-dark span.cm-def, .cm-s-duotone-dark span.cm-tag, .cm-s-duotone-dark span.cm-builtin, .cm-s-duotone-dark span.cm-qualifier, .cm-s-duotone-dark span.cm-header, .cm-s-duotone-dark span.cm-em { color: #eeebff; }
+.cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #6c6783; }
+
+/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */
+.cm-s-duotone-dark span.cm-error, .cm-s-duotone-dark span.cm-invalidchar { color: #f00; }
+
+.cm-s-duotone-dark span.cm-header { font-weight: normal; }
+.cm-s-duotone-dark .CodeMirror-matchingbracket { text-decoration: underline; color: #eeebff !important; } 

+ 36 - 0
global/css/codemirror/theme/duotone-light.css

@@ -0,0 +1,36 @@
+/*
+Name:   DuoTone-Light
+Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
+
+CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/)
+*/
+
+.cm-s-duotone-light.CodeMirror { background: #faf8f5; color: #b29762; }
+.cm-s-duotone-light div.CodeMirror-selected { background: #e3dcce !important; }
+.cm-s-duotone-light .CodeMirror-gutters { background: #faf8f5; border-right: 0px; }
+.cm-s-duotone-light .CodeMirror-linenumber { color: #cdc4b1; }
+
+/* begin cursor */
+.cm-s-duotone-light .CodeMirror-cursor { border-left: 1px solid #93abdc; /* border-left: 1px solid #93abdc80; */ border-right: .5em solid #93abdc; /* border-right: .5em solid #93abdc80; */ opacity: .5; }
+.cm-s-duotone-light .CodeMirror-activeline-background { background: #e3dcce;  /* background: #e3dcce80; */ opacity: .5; }
+.cm-s-duotone-light .cm-fat-cursor .CodeMirror-cursor { background: #93abdc; /* #93abdc80; */ opacity: .5; }
+/* end cursor */
+
+.cm-s-duotone-light span.cm-atom, .cm-s-duotone-light span.cm-number, .cm-s-duotone-light span.cm-keyword, .cm-s-duotone-light span.cm-variable, .cm-s-duotone-light span.cm-attribute, .cm-s-duotone-light span.cm-quote, .cm-s-duotone-light-light span.cm-hr, .cm-s-duotone-light-light span.cm-link { color: #063289; }
+
+.cm-s-duotone-light span.cm-property { color: #b29762; }
+.cm-s-duotone-light span.cm-punctuation, .cm-s-duotone-light span.cm-unit, .cm-s-duotone-light span.cm-negative { color: #063289; }
+.cm-s-duotone-light span.cm-string, .cm-s-duotone-light span.cm-operator { color: #1659df; }
+.cm-s-duotone-light span.cm-positive { color: #896724; }
+
+.cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-type, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; }
+.cm-s-duotone-light span.cm-def, .cm-s-duotone-light span.cm-tag, .cm-s-duotone-light span.cm-builtin, .cm-s-duotone-light span.cm-qualifier, .cm-s-duotone-light span.cm-header, .cm-s-duotone-light span.cm-em { color: #2d2006; }
+.cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #b6ad9a; }
+
+/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */
+/* .cm-s-duotone-light span.cm-error { background: #896724; color: #728fcb; } */
+.cm-s-duotone-light span.cm-error, .cm-s-duotone-light span.cm-invalidchar { color: #f00; }
+
+.cm-s-duotone-light span.cm-header { font-weight: normal; }
+.cm-s-duotone-light .CodeMirror-matchingbracket { text-decoration: underline; color: #faf8f5 !important; }
+

+ 23 - 0
global/css/codemirror/theme/eclipse.css

@@ -0,0 +1,23 @@
+.cm-s-eclipse span.cm-meta { color: #FF1717; }
+.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }
+.cm-s-eclipse span.cm-atom { color: #219; }
+.cm-s-eclipse span.cm-number { color: #164; }
+.cm-s-eclipse span.cm-def { color: #00f; }
+.cm-s-eclipse span.cm-variable { color: black; }
+.cm-s-eclipse span.cm-variable-2 { color: #0000C0; }
+.cm-s-eclipse span.cm-variable-3, .cm-s-eclipse span.cm-type { color: #0000C0; }
+.cm-s-eclipse span.cm-property { color: black; }
+.cm-s-eclipse span.cm-operator { color: black; }
+.cm-s-eclipse span.cm-comment { color: #3F7F5F; }
+.cm-s-eclipse span.cm-string { color: #2A00FF; }
+.cm-s-eclipse span.cm-string-2 { color: #f50; }
+.cm-s-eclipse span.cm-qualifier { color: #555; }
+.cm-s-eclipse span.cm-builtin { color: #30a; }
+.cm-s-eclipse span.cm-bracket { color: #cc7; }
+.cm-s-eclipse span.cm-tag { color: #170; }
+.cm-s-eclipse span.cm-attribute { color: #00c; }
+.cm-s-eclipse span.cm-link { color: #219; }
+.cm-s-eclipse span.cm-error { color: #f00; }
+
+.cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; }
+.cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }

+ 13 - 0
global/css/codemirror/theme/elegant.css

@@ -0,0 +1,13 @@
+.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { color: #762; }
+.cm-s-elegant span.cm-comment { color: #262; font-style: italic; line-height: 1em; }
+.cm-s-elegant span.cm-meta { color: #555; font-style: italic; line-height: 1em; }
+.cm-s-elegant span.cm-variable { color: black; }
+.cm-s-elegant span.cm-variable-2 { color: #b11; }
+.cm-s-elegant span.cm-qualifier { color: #555; }
+.cm-s-elegant span.cm-keyword { color: #730; }
+.cm-s-elegant span.cm-builtin { color: #30a; }
+.cm-s-elegant span.cm-link { color: #762; }
+.cm-s-elegant span.cm-error { background-color: #fdd; }
+
+.cm-s-elegant .CodeMirror-activeline-background { background: #e8f2ff; }
+.cm-s-elegant .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }

+ 34 - 0
global/css/codemirror/theme/erlang-dark.css

@@ -0,0 +1,34 @@
+.cm-s-erlang-dark.CodeMirror { background: #002240; color: white; }
+.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539; }
+.cm-s-erlang-dark .CodeMirror-line::selection, .cm-s-erlang-dark .CodeMirror-line > span::selection, .cm-s-erlang-dark .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); }
+.cm-s-erlang-dark .CodeMirror-line::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); }
+.cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }
+.cm-s-erlang-dark .CodeMirror-guttermarker { color: white; }
+.cm-s-erlang-dark .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; }
+.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-erlang-dark span.cm-quote      { color: #ccc; }
+.cm-s-erlang-dark span.cm-atom       { color: #f133f1; }
+.cm-s-erlang-dark span.cm-attribute  { color: #ff80e1; }
+.cm-s-erlang-dark span.cm-bracket    { color: #ff9d00; }
+.cm-s-erlang-dark span.cm-builtin    { color: #eaa; }
+.cm-s-erlang-dark span.cm-comment    { color: #77f; }
+.cm-s-erlang-dark span.cm-def        { color: #e7a; }
+.cm-s-erlang-dark span.cm-keyword    { color: #ffee80; }
+.cm-s-erlang-dark span.cm-meta       { color: #50fefe; }
+.cm-s-erlang-dark span.cm-number     { color: #ffd0d0; }
+.cm-s-erlang-dark span.cm-operator   { color: #d55; }
+.cm-s-erlang-dark span.cm-property   { color: #ccc; }
+.cm-s-erlang-dark span.cm-qualifier  { color: #ccc; }
+.cm-s-erlang-dark span.cm-special    { color: #ffbbbb; }
+.cm-s-erlang-dark span.cm-string     { color: #3ad900; }
+.cm-s-erlang-dark span.cm-string-2   { color: #ccc; }
+.cm-s-erlang-dark span.cm-tag        { color: #9effff; }
+.cm-s-erlang-dark span.cm-variable   { color: #50fe50; }
+.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; }
+.cm-s-erlang-dark span.cm-variable-3, .cm-s-erlang-dark span.cm-type { color: #ccc; }
+.cm-s-erlang-dark span.cm-error      { color: #9d1e15; }
+
+.cm-s-erlang-dark .CodeMirror-activeline-background { background: #013461; }
+.cm-s-erlang-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }

+ 34 - 0
global/css/codemirror/theme/hopscotch.css

@@ -0,0 +1,34 @@
+/*
+
+    Name:       Hopscotch
+    Author:     Jan T. Sott
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-hopscotch.CodeMirror {background: #322931; color: #d5d3d5;}
+.cm-s-hopscotch div.CodeMirror-selected {background: #433b42 !important;}
+.cm-s-hopscotch .CodeMirror-gutters {background: #322931; border-right: 0px;}
+.cm-s-hopscotch .CodeMirror-linenumber {color: #797379;}
+.cm-s-hopscotch .CodeMirror-cursor {border-left: 1px solid #989498 !important;}
+
+.cm-s-hopscotch span.cm-comment {color: #b33508;}
+.cm-s-hopscotch span.cm-atom {color: #c85e7c;}
+.cm-s-hopscotch span.cm-number {color: #c85e7c;}
+
+.cm-s-hopscotch span.cm-property, .cm-s-hopscotch span.cm-attribute {color: #8fc13e;}
+.cm-s-hopscotch span.cm-keyword {color: #dd464c;}
+.cm-s-hopscotch span.cm-string {color: #fdcc59;}
+
+.cm-s-hopscotch span.cm-variable {color: #8fc13e;}
+.cm-s-hopscotch span.cm-variable-2 {color: #1290bf;}
+.cm-s-hopscotch span.cm-def {color: #fd8b19;}
+.cm-s-hopscotch span.cm-error {background: #dd464c; color: #989498;}
+.cm-s-hopscotch span.cm-bracket {color: #d5d3d5;}
+.cm-s-hopscotch span.cm-tag {color: #dd464c;}
+.cm-s-hopscotch span.cm-link {color: #c85e7c;}
+
+.cm-s-hopscotch .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
+.cm-s-hopscotch .CodeMirror-activeline-background { background: #302020; }

+ 43 - 0
global/css/codemirror/theme/icecoder.css

@@ -0,0 +1,43 @@
+/*
+ICEcoder default theme by Matt Pass, used in code editor available at https://icecoder.net
+*/
+
+.cm-s-icecoder { color: #666; background: #1d1d1b; }
+
+.cm-s-icecoder span.cm-keyword { color: #eee; font-weight:bold; }  /* off-white 1 */
+.cm-s-icecoder span.cm-atom { color: #e1c76e; }                    /* yellow */
+.cm-s-icecoder span.cm-number { color: #6cb5d9; }                  /* blue */
+.cm-s-icecoder span.cm-def { color: #b9ca4a; }                     /* green */
+
+.cm-s-icecoder span.cm-variable { color: #6cb5d9; }                /* blue */
+.cm-s-icecoder span.cm-variable-2 { color: #cc1e5c; }              /* pink */
+.cm-s-icecoder span.cm-variable-3, .cm-s-icecoder span.cm-type { color: #f9602c; } /* orange */
+
+.cm-s-icecoder span.cm-property { color: #eee; }                   /* off-white 1 */
+.cm-s-icecoder span.cm-operator { color: #9179bb; }                /* purple */
+.cm-s-icecoder span.cm-comment { color: #97a3aa; }                 /* grey-blue */
+
+.cm-s-icecoder span.cm-string { color: #b9ca4a; }                  /* green */
+.cm-s-icecoder span.cm-string-2 { color: #6cb5d9; }                /* blue */
+
+.cm-s-icecoder span.cm-meta { color: #555; }                       /* grey */
+
+.cm-s-icecoder span.cm-qualifier { color: #555; }                  /* grey */
+.cm-s-icecoder span.cm-builtin { color: #214e7b; }                 /* bright blue */
+.cm-s-icecoder span.cm-bracket { color: #cc7; }                    /* grey-yellow */
+
+.cm-s-icecoder span.cm-tag { color: #e8e8e8; }                     /* off-white 2 */
+.cm-s-icecoder span.cm-attribute { color: #099; }                  /* teal */
+
+.cm-s-icecoder span.cm-header { color: #6a0d6a; }                  /* purple-pink */
+.cm-s-icecoder span.cm-quote { color: #186718; }                   /* dark green */
+.cm-s-icecoder span.cm-hr { color: #888; }                         /* mid-grey */
+.cm-s-icecoder span.cm-link { color: #e1c76e; }                    /* yellow */
+.cm-s-icecoder span.cm-error { color: #d00; }                      /* red */
+
+.cm-s-icecoder .CodeMirror-cursor { border-left: 1px solid white; }
+.cm-s-icecoder div.CodeMirror-selected { color: #fff; background: #037; }
+.cm-s-icecoder .CodeMirror-gutters { background: #1d1d1b; min-width: 41px; border-right: 0; }
+.cm-s-icecoder .CodeMirror-linenumber { color: #555; cursor: default; }
+.cm-s-icecoder .CodeMirror-matchingbracket { color: #fff !important; background: #555 !important; }
+.cm-s-icecoder .CodeMirror-activeline-background { background: #000; }

+ 34 - 0
global/css/codemirror/theme/isotope.css

@@ -0,0 +1,34 @@
+/*
+
+    Name:       Isotope
+    Author:     David Desandro / Jan T. Sott
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-isotope.CodeMirror {background: #000000; color: #e0e0e0;}
+.cm-s-isotope div.CodeMirror-selected {background: #404040 !important;}
+.cm-s-isotope .CodeMirror-gutters {background: #000000; border-right: 0px;}
+.cm-s-isotope .CodeMirror-linenumber {color: #808080;}
+.cm-s-isotope .CodeMirror-cursor {border-left: 1px solid #c0c0c0 !important;}
+
+.cm-s-isotope span.cm-comment {color: #3300ff;}
+.cm-s-isotope span.cm-atom {color: #cc00ff;}
+.cm-s-isotope span.cm-number {color: #cc00ff;}
+
+.cm-s-isotope span.cm-property, .cm-s-isotope span.cm-attribute {color: #33ff00;}
+.cm-s-isotope span.cm-keyword {color: #ff0000;}
+.cm-s-isotope span.cm-string {color: #ff0099;}
+
+.cm-s-isotope span.cm-variable {color: #33ff00;}
+.cm-s-isotope span.cm-variable-2 {color: #0066ff;}
+.cm-s-isotope span.cm-def {color: #ff9900;}
+.cm-s-isotope span.cm-error {background: #ff0000; color: #c0c0c0;}
+.cm-s-isotope span.cm-bracket {color: #e0e0e0;}
+.cm-s-isotope span.cm-tag {color: #ff0000;}
+.cm-s-isotope span.cm-link {color: #cc00ff;}
+
+.cm-s-isotope .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
+.cm-s-isotope .CodeMirror-activeline-background { background: #202020; }

+ 47 - 0
global/css/codemirror/theme/lesser-dark.css

@@ -0,0 +1,47 @@
+/*
+http://lesscss.org/ dark theme
+Ported to CodeMirror by Peter Kroon
+*/
+.cm-s-lesser-dark {
+  line-height: 1.3em;
+}
+.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; }
+.cm-s-lesser-dark div.CodeMirror-selected { background: #45443B; } /* 33322B*/
+.cm-s-lesser-dark .CodeMirror-line::selection, .cm-s-lesser-dark .CodeMirror-line > span::selection, .cm-s-lesser-dark .CodeMirror-line > span > span::selection { background: rgba(69, 68, 59, .99); }
+.cm-s-lesser-dark .CodeMirror-line::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(69, 68, 59, .99); }
+.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white; }
+.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/
+
+.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/
+
+.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; }
+.cm-s-lesser-dark .CodeMirror-guttermarker { color: #599eff; }
+.cm-s-lesser-dark .CodeMirror-guttermarker-subtle { color: #777; }
+.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; }
+
+.cm-s-lesser-dark span.cm-header { color: #a0a; }
+.cm-s-lesser-dark span.cm-quote { color: #090; }
+.cm-s-lesser-dark span.cm-keyword { color: #599eff; }
+.cm-s-lesser-dark span.cm-atom { color: #C2B470; }
+.cm-s-lesser-dark span.cm-number { color: #B35E4D; }
+.cm-s-lesser-dark span.cm-def { color: white; }
+.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; }
+.cm-s-lesser-dark span.cm-variable-2 { color: #669199; }
+.cm-s-lesser-dark span.cm-variable-3, .cm-s-lesser-dark span.cm-type { color: white; }
+.cm-s-lesser-dark span.cm-property { color: #92A75C; }
+.cm-s-lesser-dark span.cm-operator { color: #92A75C; }
+.cm-s-lesser-dark span.cm-comment { color: #666; }
+.cm-s-lesser-dark span.cm-string { color: #BCD279; }
+.cm-s-lesser-dark span.cm-string-2 { color: #f50; }
+.cm-s-lesser-dark span.cm-meta { color: #738C73; }
+.cm-s-lesser-dark span.cm-qualifier { color: #555; }
+.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; }
+.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; }
+.cm-s-lesser-dark span.cm-tag { color: #669199; }
+.cm-s-lesser-dark span.cm-attribute { color: #00c; }
+.cm-s-lesser-dark span.cm-hr { color: #999; }
+.cm-s-lesser-dark span.cm-link { color: #00c; }
+.cm-s-lesser-dark span.cm-error { color: #9d1e15; }
+
+.cm-s-lesser-dark .CodeMirror-activeline-background { background: #3C3A3A; }
+.cm-s-lesser-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }

+ 95 - 0
global/css/codemirror/theme/liquibyte.css

@@ -0,0 +1,95 @@
+.cm-s-liquibyte.CodeMirror {
+	background-color: #000;
+	color: #fff;
+	line-height: 1.2em;
+	font-size: 1em;
+}
+.cm-s-liquibyte .CodeMirror-focused .cm-matchhighlight {
+	text-decoration: underline;
+	text-decoration-color: #0f0;
+	text-decoration-style: wavy;
+}
+.cm-s-liquibyte .cm-trailingspace {
+	text-decoration: line-through;
+	text-decoration-color: #f00;
+	text-decoration-style: dotted;
+}
+.cm-s-liquibyte .cm-tab {
+	text-decoration: line-through;
+	text-decoration-color: #404040;
+	text-decoration-style: dotted;
+}
+.cm-s-liquibyte .CodeMirror-gutters { background-color: #262626; border-right: 1px solid #505050; padding-right: 0.8em; }
+.cm-s-liquibyte .CodeMirror-gutter-elt div { font-size: 1.2em; }
+.cm-s-liquibyte .CodeMirror-guttermarker {  }
+.cm-s-liquibyte .CodeMirror-guttermarker-subtle {  }
+.cm-s-liquibyte .CodeMirror-linenumber { color: #606060; padding-left: 0; }
+.cm-s-liquibyte .CodeMirror-cursor { border-left: 1px solid #eee; }
+
+.cm-s-liquibyte span.cm-comment     { color: #008000; }
+.cm-s-liquibyte span.cm-def         { color: #ffaf40; font-weight: bold; }
+.cm-s-liquibyte span.cm-keyword     { color: #c080ff; font-weight: bold; }
+.cm-s-liquibyte span.cm-builtin     { color: #ffaf40; font-weight: bold; }
+.cm-s-liquibyte span.cm-variable    { color: #5967ff; font-weight: bold; }
+.cm-s-liquibyte span.cm-string      { color: #ff8000; }
+.cm-s-liquibyte span.cm-number      { color: #0f0; font-weight: bold; }
+.cm-s-liquibyte span.cm-atom        { color: #bf3030; font-weight: bold; }
+
+.cm-s-liquibyte span.cm-variable-2  { color: #007f7f; font-weight: bold; }
+.cm-s-liquibyte span.cm-variable-3, .cm-s-liquibyte span.cm-type { color: #c080ff; font-weight: bold; }
+.cm-s-liquibyte span.cm-property    { color: #999; font-weight: bold; }
+.cm-s-liquibyte span.cm-operator    { color: #fff; }
+
+.cm-s-liquibyte span.cm-meta        { color: #0f0; }
+.cm-s-liquibyte span.cm-qualifier   { color: #fff700; font-weight: bold; }
+.cm-s-liquibyte span.cm-bracket     { color: #cc7; }
+.cm-s-liquibyte span.cm-tag         { color: #ff0; font-weight: bold; }
+.cm-s-liquibyte span.cm-attribute   { color: #c080ff; font-weight: bold; }
+.cm-s-liquibyte span.cm-error       { color: #f00; }
+
+.cm-s-liquibyte div.CodeMirror-selected { background-color: rgba(255, 0, 0, 0.25); }
+
+.cm-s-liquibyte span.cm-compilation { background-color: rgba(255, 255, 255, 0.12); }
+
+.cm-s-liquibyte .CodeMirror-activeline-background { background-color: rgba(0, 255, 0, 0.15); }
+
+/* Default styles for common addons */
+.cm-s-liquibyte .CodeMirror span.CodeMirror-matchingbracket { color: #0f0; font-weight: bold; }
+.cm-s-liquibyte .CodeMirror span.CodeMirror-nonmatchingbracket { color: #f00; font-weight: bold; }
+.CodeMirror-matchingtag { background-color: rgba(150, 255, 0, .3); }
+/* Scrollbars */
+/* Simple */
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div:hover, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div:hover {
+	background-color: rgba(80, 80, 80, .7);
+}
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div {
+	background-color: rgba(80, 80, 80, .3);
+	border: 1px solid #404040;
+	border-radius: 5px;
+}
+.cm-s-liquibyte div.CodeMirror-simplescroll-vertical div {
+	border-top: 1px solid #404040;
+	border-bottom: 1px solid #404040;
+}
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div {
+	border-left: 1px solid #404040;
+	border-right: 1px solid #404040;
+}
+.cm-s-liquibyte div.CodeMirror-simplescroll-vertical {
+	background-color: #262626;
+}
+.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal {
+	background-color: #262626;
+	border-top: 1px solid #404040;
+}
+/* Overlay */
+.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div, div.CodeMirror-overlayscroll-vertical div {
+	background-color: #404040;
+	border-radius: 5px;
+}
+.cm-s-liquibyte div.CodeMirror-overlayscroll-vertical div {
+	border: 1px solid #404040;
+}
+.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div {
+	border: 1px solid #404040;
+}

+ 53 - 0
global/css/codemirror/theme/material.css

@@ -0,0 +1,53 @@
+/*
+
+    Name:       material
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)
+
+    Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)
+
+*/
+
+.cm-s-material.CodeMirror {
+  background-color: #263238;
+  color: rgba(233, 237, 237, 1);
+}
+.cm-s-material .CodeMirror-gutters {
+  background: #263238;
+  color: rgb(83,127,126);
+  border: none;
+}
+.cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); }
+.cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
+.cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }
+.cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
+.cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
+
+.cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); }
+.cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); }
+.cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }
+.cm-s-material .cm-variable-2 { color: #80CBC4; }
+.cm-s-material .cm-variable-3, .cm-s-material .cm-type { color: #82B1FF; }
+.cm-s-material .cm-builtin { color: #DECB6B; }
+.cm-s-material .cm-atom { color: #F77669; }
+.cm-s-material .cm-number { color: #F77669; }
+.cm-s-material .cm-def { color: rgba(233, 237, 237, 1); }
+.cm-s-material .cm-string { color: #C3E88D; }
+.cm-s-material .cm-string-2 { color: #80CBC4; }
+.cm-s-material .cm-comment { color: #546E7A; }
+.cm-s-material .cm-variable { color: #82B1FF; }
+.cm-s-material .cm-tag { color: #80CBC4; }
+.cm-s-material .cm-meta { color: #80CBC4; }
+.cm-s-material .cm-attribute { color: #FFCB6B; }
+.cm-s-material .cm-property { color: #80CBAE; }
+.cm-s-material .cm-qualifier { color: #DECB6B; }
+.cm-s-material .cm-variable-3, .cm-s-material .cm-type { color: #DECB6B; }
+.cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }
+.cm-s-material .cm-error {
+  color: rgba(255, 255, 255, 1.0);
+  background-color: #EC5F67;
+}
+.cm-s-material .CodeMirror-matchingbracket {
+  text-decoration: underline;
+  color: white !important;
+}

+ 37 - 0
global/css/codemirror/theme/mbo.css

@@ -0,0 +1,37 @@
+/****************************************************************/
+/*   Based on mbonaci's Brackets mbo theme                      */
+/*   https://github.com/mbonaci/global/blob/master/Mbo.tmTheme  */
+/*   Create your own: http://tmtheme-editor.herokuapp.com       */
+/****************************************************************/
+
+.cm-s-mbo.CodeMirror { background: #2c2c2c; color: #ffffec; }
+.cm-s-mbo div.CodeMirror-selected { background: #716C62; }
+.cm-s-mbo .CodeMirror-line::selection, .cm-s-mbo .CodeMirror-line > span::selection, .cm-s-mbo .CodeMirror-line > span > span::selection { background: rgba(113, 108, 98, .99); }
+.cm-s-mbo .CodeMirror-line::-moz-selection, .cm-s-mbo .CodeMirror-line > span::-moz-selection, .cm-s-mbo .CodeMirror-line > span > span::-moz-selection { background: rgba(113, 108, 98, .99); }
+.cm-s-mbo .CodeMirror-gutters { background: #4e4e4e; border-right: 0px; }
+.cm-s-mbo .CodeMirror-guttermarker { color: white; }
+.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; }
+.cm-s-mbo .CodeMirror-linenumber { color: #dadada; }
+.cm-s-mbo .CodeMirror-cursor { border-left: 1px solid #ffffec; }
+
+.cm-s-mbo span.cm-comment { color: #95958a; }
+.cm-s-mbo span.cm-atom { color: #00a8c6; }
+.cm-s-mbo span.cm-number { color: #00a8c6; }
+
+.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute { color: #9ddfe9; }
+.cm-s-mbo span.cm-keyword { color: #ffb928; }
+.cm-s-mbo span.cm-string { color: #ffcf6c; }
+.cm-s-mbo span.cm-string.cm-property { color: #ffffec; }
+
+.cm-s-mbo span.cm-variable { color: #ffffec; }
+.cm-s-mbo span.cm-variable-2 { color: #00a8c6; }
+.cm-s-mbo span.cm-def { color: #ffffec; }
+.cm-s-mbo span.cm-bracket { color: #fffffc; font-weight: bold; }
+.cm-s-mbo span.cm-tag { color: #9ddfe9; }
+.cm-s-mbo span.cm-link { color: #f54b07; }
+.cm-s-mbo span.cm-error { border-bottom: #636363; color: #ffffec; }
+.cm-s-mbo span.cm-qualifier { color: #ffffec; }
+
+.cm-s-mbo .CodeMirror-activeline-background { background: #494b41; }
+.cm-s-mbo .CodeMirror-matchingbracket { color: #ffb928 !important; }
+.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); }

File diff suppressed because it is too large
+ 46 - 0
global/css/codemirror/theme/mdn-like.css


+ 45 - 0
global/css/codemirror/theme/midnight.css

@@ -0,0 +1,45 @@
+/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */
+
+/*<!--match-->*/
+.cm-s-midnight span.CodeMirror-matchhighlight { background: #494949; }
+.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; }
+
+/*<!--activeline-->*/
+.cm-s-midnight .CodeMirror-activeline-background { background: #253540; }
+
+.cm-s-midnight.CodeMirror {
+    background: #0F192A;
+    color: #D1EDFF;
+}
+
+.cm-s-midnight.CodeMirror { border-top: 1px solid black; border-bottom: 1px solid black; }
+
+.cm-s-midnight div.CodeMirror-selected { background: #314D67; }
+.cm-s-midnight .CodeMirror-line::selection, .cm-s-midnight .CodeMirror-line > span::selection, .cm-s-midnight .CodeMirror-line > span > span::selection { background: rgba(49, 77, 103, .99); }
+.cm-s-midnight .CodeMirror-line::-moz-selection, .cm-s-midnight .CodeMirror-line > span::-moz-selection, .cm-s-midnight .CodeMirror-line > span > span::-moz-selection { background: rgba(49, 77, 103, .99); }
+.cm-s-midnight .CodeMirror-gutters { background: #0F192A; border-right: 1px solid; }
+.cm-s-midnight .CodeMirror-guttermarker { color: white; }
+.cm-s-midnight .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-midnight .CodeMirror-linenumber { color: #D0D0D0; }
+.cm-s-midnight .CodeMirror-cursor { border-left: 1px solid #F8F8F0; }
+
+.cm-s-midnight span.cm-comment { color: #428BDD; }
+.cm-s-midnight span.cm-atom { color: #AE81FF; }
+.cm-s-midnight span.cm-number { color: #D1EDFF; }
+
+.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute { color: #A6E22E; }
+.cm-s-midnight span.cm-keyword { color: #E83737; }
+.cm-s-midnight span.cm-string { color: #1DC116; }
+
+.cm-s-midnight span.cm-variable { color: #FFAA3E; }
+.cm-s-midnight span.cm-variable-2 { color: #FFAA3E; }
+.cm-s-midnight span.cm-def { color: #4DD; }
+.cm-s-midnight span.cm-bracket { color: #D1EDFF; }
+.cm-s-midnight span.cm-tag { color: #449; }
+.cm-s-midnight span.cm-link { color: #AE81FF; }
+.cm-s-midnight span.cm-error { background: #F92672; color: #F8F8F0; }
+
+.cm-s-midnight .CodeMirror-matchingbracket {
+  text-decoration: underline;
+  color: white !important;
+}

+ 36 - 0
global/css/codemirror/theme/monokai.css

@@ -0,0 +1,36 @@
+/* Based on Sublime Text's Monokai theme */
+
+.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }
+.cm-s-monokai div.CodeMirror-selected { background: #49483E; }
+.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }
+.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }
+.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }
+.cm-s-monokai .CodeMirror-guttermarker { color: white; }
+.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }
+.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
+
+.cm-s-monokai span.cm-comment { color: #75715e; }
+.cm-s-monokai span.cm-atom { color: #ae81ff; }
+.cm-s-monokai span.cm-number { color: #ae81ff; }
+
+.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }
+.cm-s-monokai span.cm-keyword { color: #f92672; }
+.cm-s-monokai span.cm-builtin { color: #66d9ef; }
+.cm-s-monokai span.cm-string { color: #e6db74; }
+
+.cm-s-monokai span.cm-variable { color: #f8f8f2; }
+.cm-s-monokai span.cm-variable-2 { color: #9effff; }
+.cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; }
+.cm-s-monokai span.cm-def { color: #fd971f; }
+.cm-s-monokai span.cm-bracket { color: #f8f8f2; }
+.cm-s-monokai span.cm-tag { color: #f92672; }
+.cm-s-monokai span.cm-header { color: #ae81ff; }
+.cm-s-monokai span.cm-link { color: #ae81ff; }
+.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }
+
+.cm-s-monokai .CodeMirror-activeline-background { background: #373831; }
+.cm-s-monokai .CodeMirror-matchingbracket {
+  text-decoration: underline;
+  color: white !important;
+}

+ 12 - 0
global/css/codemirror/theme/neat.css

@@ -0,0 +1,12 @@
+.cm-s-neat span.cm-comment { color: #a86; }
+.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; }
+.cm-s-neat span.cm-string { color: #a22; }
+.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; }
+.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; }
+.cm-s-neat span.cm-variable { color: black; }
+.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
+.cm-s-neat span.cm-meta { color: #555; }
+.cm-s-neat span.cm-link { color: #3a3; }
+
+.cm-s-neat .CodeMirror-activeline-background { background: #e8f2ff; }
+.cm-s-neat .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }

+ 43 - 0
global/css/codemirror/theme/neo.css

@@ -0,0 +1,43 @@
+/* neo theme for codemirror */
+
+/* Color scheme */
+
+.cm-s-neo.CodeMirror {
+  background-color:#ffffff;
+  color:#2e383c;
+  line-height:1.4375;
+}
+.cm-s-neo .cm-comment { color:#75787b; }
+.cm-s-neo .cm-keyword, .cm-s-neo .cm-property { color:#1d75b3; }
+.cm-s-neo .cm-atom,.cm-s-neo .cm-number { color:#75438a; }
+.cm-s-neo .cm-node,.cm-s-neo .cm-tag { color:#9c3328; }
+.cm-s-neo .cm-string { color:#b35e14; }
+.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier { color:#047d65; }
+
+
+/* Editor styling */
+
+.cm-s-neo pre {
+  padding:0;
+}
+
+.cm-s-neo .CodeMirror-gutters {
+  border:none;
+  border-right:10px solid transparent;
+  background-color:transparent;
+}
+
+.cm-s-neo .CodeMirror-linenumber {
+  padding:0;
+  color:#e0e2e5;
+}
+
+.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; }
+.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; }
+
+.cm-s-neo .CodeMirror-cursor {
+  width: auto;
+  border: 0;
+  background: rgba(155,157,162,0.37);
+  z-index: 1;
+}

+ 27 - 0
global/css/codemirror/theme/night.css

@@ -0,0 +1,27 @@
+/* Loosely based on the Midnight Textmate theme */
+
+.cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; }
+.cm-s-night div.CodeMirror-selected { background: #447; }
+.cm-s-night .CodeMirror-line::selection, .cm-s-night .CodeMirror-line > span::selection, .cm-s-night .CodeMirror-line > span > span::selection { background: rgba(68, 68, 119, .99); }
+.cm-s-night .CodeMirror-line::-moz-selection, .cm-s-night .CodeMirror-line > span::-moz-selection, .cm-s-night .CodeMirror-line > span > span::-moz-selection { background: rgba(68, 68, 119, .99); }
+.cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }
+.cm-s-night .CodeMirror-guttermarker { color: white; }
+.cm-s-night .CodeMirror-guttermarker-subtle { color: #bbb; }
+.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; }
+.cm-s-night .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-night span.cm-comment { color: #8900d1; }
+.cm-s-night span.cm-atom { color: #845dc4; }
+.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
+.cm-s-night span.cm-keyword { color: #599eff; }
+.cm-s-night span.cm-string { color: #37f14a; }
+.cm-s-night span.cm-meta { color: #7678e2; }
+.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
+.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def, .cm-s-night span.cm-type { color: white; }
+.cm-s-night span.cm-bracket { color: #8da6ce; }
+.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
+.cm-s-night span.cm-link { color: #845dc4; }
+.cm-s-night span.cm-error { color: #9d1e15; }
+
+.cm-s-night .CodeMirror-activeline-background { background: #1C005A; }
+.cm-s-night .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }

+ 85 - 0
global/css/codemirror/theme/panda-syntax.css

@@ -0,0 +1,85 @@
+/*
+	Name:       Panda Syntax
+	Author:     Siamak Mokhtari (http://github.com/siamak/)
+	CodeMirror template by Siamak Mokhtari (https://github.com/siamak/atom-panda-syntax)
+*/
+.cm-s-panda-syntax {
+	background: #292A2B;
+	color: #E6E6E6;
+	line-height: 1.5;
+	font-family: 'Operator Mono', 'Source Sans Pro', Menlo, Monaco, Consolas, Courier New, monospace;
+}
+.cm-s-panda-syntax .CodeMirror-cursor { border-color: #ff2c6d; }
+.cm-s-panda-syntax .CodeMirror-activeline-background {
+	background: rgba(99, 123, 156, 0.1);
+}
+.cm-s-panda-syntax .CodeMirror-selected {
+	background: #FFF;
+}
+.cm-s-panda-syntax .cm-comment {
+	font-style: italic;
+	color: #676B79;
+}
+.cm-s-panda-syntax .cm-operator {
+	color: #f3f3f3;
+}
+.cm-s-panda-syntax .cm-string {
+	color: #19F9D8;
+}
+.cm-s-panda-syntax .cm-string-2 {
+    color: #FFB86C;
+}
+
+.cm-s-panda-syntax .cm-tag {
+	color: #ff2c6d;
+}
+.cm-s-panda-syntax .cm-meta {
+	color: #b084eb;
+}
+
+.cm-s-panda-syntax .cm-number {
+	color: #FFB86C;
+}
+.cm-s-panda-syntax .cm-atom {
+	color: #ff2c6d;
+}
+.cm-s-panda-syntax .cm-keyword {
+	color: #FF75B5;
+}
+.cm-s-panda-syntax .cm-variable {
+	color: #ffb86c;
+}
+.cm-s-panda-syntax .cm-variable-2 {
+	color: #ff9ac1;
+}
+.cm-s-panda-syntax .cm-variable-3, .cm-s-panda-syntax .cm-type {
+	color: #ff9ac1;
+}
+
+.cm-s-panda-syntax .cm-def {
+	color: #e6e6e6;
+}
+.cm-s-panda-syntax .cm-property {
+	color: #f3f3f3;
+}
+.cm-s-panda-syntax .cm-unit {
+    color: #ffb86c;
+}
+
+.cm-s-panda-syntax .cm-attribute {
+    color: #ffb86c;
+}
+
+.cm-s-panda-syntax .CodeMirror-matchingbracket {
+    border-bottom: 1px dotted #19F9D8;
+    padding-bottom: 2px;
+    color: #e6e6e6;
+}
+.cm-s-panda-syntax .CodeMirror-gutters {
+    background: #292a2b;
+    border-right-color: rgba(255, 255, 255, 0.1);
+}
+.cm-s-panda-syntax .CodeMirror-linenumber {
+    color: #e6e6e6;
+    opacity: 0.6;
+}

+ 38 - 0
global/css/codemirror/theme/paraiso-dark.css

@@ -0,0 +1,38 @@
+/*
+
+    Name:       Paraíso (Dark)
+    Author:     Jan T. Sott
+
+    Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
+    Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
+
+*/
+
+.cm-s-paraiso-dark.CodeMirror { background: #2f1e2e; color: #b9b6b0; }
+.cm-s-paraiso-dark div.CodeMirror-selected { background: #41323f; }
+.cm-s-paraiso-dark .CodeMirror-line::selection, .cm-s-paraiso-dark .CodeMirror-line > span::selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::selection { background: rgba(65, 50, 63, .99); }
+.cm-s-paraiso-dark .CodeMirror-line::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(65, 50, 63, .99); }
+.cm-s-paraiso-dark .CodeMirror-gutters { background: #2f1e2e; border-right: 0px; }
+.cm-s-paraiso-dark .CodeMirror-guttermarker { color: #ef6155; }
+.cm-s-paraiso-dark .CodeMirror-guttermarker-subtle { color: #776e71; }
+.cm-s-paraiso-dark .CodeMirror-linenumber { color: #776e71; }
+.cm-s-paraiso-dark .CodeMirror-cursor { border-left: 1px solid #8d8687; }
+
+.cm-s-paraiso-dark span.cm-comment { color: #e96ba8; }
+.cm-s-paraiso-dark span.cm-atom { color: #815ba4; }
+.cm-s-paraiso-dark span.cm-number { color: #815ba4; }
+
+.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute { color: #48b685; }
+.cm-s-paraiso-dark span.cm-keyword { color: #ef6155; }
+.cm-s-paraiso-dark span.cm-string { color: #fec418; }
+
+.cm-s-paraiso-dark span.cm-variable { color: #48b685; }
+.cm-s-paraiso-dark span.cm-variable-2 { color: #06b6ef; }
+.cm-s-paraiso-dark span.cm-def { color: #f99b15; }
+.cm-s-paraiso-dark span.cm-bracket { color: #b9b6b0; }
+.cm-s-paraiso-dark span.cm-tag { color: #ef6155; }
+.cm-s-paraiso-dark span.cm-link { color: #815ba4; }
+.cm-s-paraiso-dark span.cm-error { background: #ef6155; color: #8d8687; }
+
+.cm-s-paraiso-dark .CodeMirror-activeline-background { background: #4D344A; }
+.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 38 - 0
global/css/codemirror/theme/paraiso-light.css

@@ -0,0 +1,38 @@
+/*
+
+    Name:       Paraíso (Light)
+    Author:     Jan T. Sott
+
+    Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror)
+    Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
+
+*/
+
+.cm-s-paraiso-light.CodeMirror { background: #e7e9db; color: #41323f; }
+.cm-s-paraiso-light div.CodeMirror-selected { background: #b9b6b0; }
+.cm-s-paraiso-light .CodeMirror-line::selection, .cm-s-paraiso-light .CodeMirror-line > span::selection, .cm-s-paraiso-light .CodeMirror-line > span > span::selection { background: #b9b6b0; }
+.cm-s-paraiso-light .CodeMirror-line::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span > span::-moz-selection { background: #b9b6b0; }
+.cm-s-paraiso-light .CodeMirror-gutters { background: #e7e9db; border-right: 0px; }
+.cm-s-paraiso-light .CodeMirror-guttermarker { color: black; }
+.cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; }
+.cm-s-paraiso-light .CodeMirror-linenumber { color: #8d8687; }
+.cm-s-paraiso-light .CodeMirror-cursor { border-left: 1px solid #776e71; }
+
+.cm-s-paraiso-light span.cm-comment { color: #e96ba8; }
+.cm-s-paraiso-light span.cm-atom { color: #815ba4; }
+.cm-s-paraiso-light span.cm-number { color: #815ba4; }
+
+.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute { color: #48b685; }
+.cm-s-paraiso-light span.cm-keyword { color: #ef6155; }
+.cm-s-paraiso-light span.cm-string { color: #fec418; }
+
+.cm-s-paraiso-light span.cm-variable { color: #48b685; }
+.cm-s-paraiso-light span.cm-variable-2 { color: #06b6ef; }
+.cm-s-paraiso-light span.cm-def { color: #f99b15; }
+.cm-s-paraiso-light span.cm-bracket { color: #41323f; }
+.cm-s-paraiso-light span.cm-tag { color: #ef6155; }
+.cm-s-paraiso-light span.cm-link { color: #815ba4; }
+.cm-s-paraiso-light span.cm-error { background: #ef6155; color: #776e71; }
+
+.cm-s-paraiso-light .CodeMirror-activeline-background { background: #CFD1C4; }
+.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 52 - 0
global/css/codemirror/theme/pastel-on-dark.css

@@ -0,0 +1,52 @@
+/**
+ * Pastel On Dark theme ported from ACE editor
+ * @license MIT
+ * @copyright AtomicPages LLC 2014
+ * @author Dennis Thompson, AtomicPages LLC
+ * @version 1.1
+ * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme
+ */
+
+.cm-s-pastel-on-dark.CodeMirror {
+	background: #2c2827;
+	color: #8F938F;
+	line-height: 1.5;
+}
+.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2); }
+.cm-s-pastel-on-dark .CodeMirror-line::selection, .cm-s-pastel-on-dark .CodeMirror-line > span::selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::selection { background: rgba(221,240,255,0.2); }
+.cm-s-pastel-on-dark .CodeMirror-line::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(221,240,255,0.2); }
+
+.cm-s-pastel-on-dark .CodeMirror-gutters {
+	background: #34302f;
+	border-right: 0px;
+	padding: 0 3px;
+}
+.cm-s-pastel-on-dark .CodeMirror-guttermarker { color: white; }
+.cm-s-pastel-on-dark .CodeMirror-guttermarker-subtle { color: #8F938F; }
+.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; }
+.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7; }
+.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; }
+.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; }
+.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; }
+.cm-s-pastel-on-dark span.cm-property { color: #8F938F; }
+.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; }
+.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; }
+.cm-s-pastel-on-dark span.cm-string { color: #66A968; }
+.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; }
+.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; }
+.cm-s-pastel-on-dark span.cm-variable-3, .cm-s-pastel-on-dark span.cm-type { color: #DE8E30; }
+.cm-s-pastel-on-dark span.cm-def { color: #757aD8; }
+.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; }
+.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; }
+.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; }
+.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; }
+.cm-s-pastel-on-dark span.cm-error {
+	background: #757aD8;
+	color: #f8f8f0;
+}
+.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031); }
+.cm-s-pastel-on-dark .CodeMirror-matchingbracket {
+	border: 1px solid rgba(255,255,255,0.25);
+	color: #8F938F !important;
+	margin: -1px -1px 0 -1px;
+}

+ 34 - 0
global/css/codemirror/theme/railscasts.css

@@ -0,0 +1,34 @@
+/*
+
+    Name:       Railscasts
+    Author:     Ryan Bates (http://railscasts.com)
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-railscasts.CodeMirror {background: #2b2b2b; color: #f4f1ed;}
+.cm-s-railscasts div.CodeMirror-selected {background: #272935 !important;}
+.cm-s-railscasts .CodeMirror-gutters {background: #2b2b2b; border-right: 0px;}
+.cm-s-railscasts .CodeMirror-linenumber {color: #5a647e;}
+.cm-s-railscasts .CodeMirror-cursor {border-left: 1px solid #d4cfc9 !important;}
+
+.cm-s-railscasts span.cm-comment {color: #bc9458;}
+.cm-s-railscasts span.cm-atom {color: #b6b3eb;}
+.cm-s-railscasts span.cm-number {color: #b6b3eb;}
+
+.cm-s-railscasts span.cm-property, .cm-s-railscasts span.cm-attribute {color: #a5c261;}
+.cm-s-railscasts span.cm-keyword {color: #da4939;}
+.cm-s-railscasts span.cm-string {color: #ffc66d;}
+
+.cm-s-railscasts span.cm-variable {color: #a5c261;}
+.cm-s-railscasts span.cm-variable-2 {color: #6d9cbe;}
+.cm-s-railscasts span.cm-def {color: #cc7833;}
+.cm-s-railscasts span.cm-error {background: #da4939; color: #d4cfc9;}
+.cm-s-railscasts span.cm-bracket {color: #f4f1ed;}
+.cm-s-railscasts span.cm-tag {color: #da4939;}
+.cm-s-railscasts span.cm-link {color: #b6b3eb;}
+
+.cm-s-railscasts .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;}
+.cm-s-railscasts .CodeMirror-activeline-background { background: #303040; }

+ 25 - 0
global/css/codemirror/theme/rubyblue.css

@@ -0,0 +1,25 @@
+.cm-s-rubyblue.CodeMirror { background: #112435; color: white; }
+.cm-s-rubyblue div.CodeMirror-selected { background: #38566F; }
+.cm-s-rubyblue .CodeMirror-line::selection, .cm-s-rubyblue .CodeMirror-line > span::selection, .cm-s-rubyblue .CodeMirror-line > span > span::selection { background: rgba(56, 86, 111, 0.99); }
+.cm-s-rubyblue .CodeMirror-line::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 86, 111, 0.99); }
+.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; }
+.cm-s-rubyblue .CodeMirror-guttermarker { color: white; }
+.cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; }
+.cm-s-rubyblue .CodeMirror-linenumber { color: white; }
+.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; }
+.cm-s-rubyblue span.cm-atom { color: #F4C20B; }
+.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; }
+.cm-s-rubyblue span.cm-keyword { color: #F0F; }
+.cm-s-rubyblue span.cm-string { color: #F08047; }
+.cm-s-rubyblue span.cm-meta { color: #F0F; }
+.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; }
+.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def, .cm-s-rubyblue span.cm-type { color: white; }
+.cm-s-rubyblue span.cm-bracket { color: #F0F; }
+.cm-s-rubyblue span.cm-link { color: #F4C20B; }
+.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; }
+.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; }
+.cm-s-rubyblue span.cm-error { color: #AF2018; }
+
+.cm-s-rubyblue .CodeMirror-activeline-background { background: #173047; }

+ 44 - 0
global/css/codemirror/theme/seti.css

@@ -0,0 +1,44 @@
+/*
+
+    Name:       seti
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)
+
+    Original seti color scheme by Jesse Weed (https://github.com/jesseweed/seti-syntax)
+
+*/
+
+
+.cm-s-seti.CodeMirror {
+  background-color: #151718 !important;
+  color: #CFD2D1 !important;
+  border: none;
+}
+.cm-s-seti .CodeMirror-gutters {
+  color: #404b53;
+  background-color: #0E1112;
+  border: none;
+}
+.cm-s-seti .CodeMirror-cursor { border-left: solid thin #f8f8f0; }
+.cm-s-seti .CodeMirror-linenumber { color: #6D8A88; }
+.cm-s-seti.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
+.cm-s-seti .CodeMirror-line::selection, .cm-s-seti .CodeMirror-line > span::selection, .cm-s-seti .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-seti .CodeMirror-line::-moz-selection, .cm-s-seti .CodeMirror-line > span::-moz-selection, .cm-s-seti .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
+.cm-s-seti span.cm-comment { color: #41535b; }
+.cm-s-seti span.cm-string, .cm-s-seti span.cm-string-2 { color: #55b5db; }
+.cm-s-seti span.cm-number { color: #cd3f45; }
+.cm-s-seti span.cm-variable { color: #55b5db; }
+.cm-s-seti span.cm-variable-2 { color: #a074c4; }
+.cm-s-seti span.cm-def { color: #55b5db; }
+.cm-s-seti span.cm-keyword { color: #ff79c6; }
+.cm-s-seti span.cm-operator { color: #9fca56; }
+.cm-s-seti span.cm-keyword { color: #e6cd69; }
+.cm-s-seti span.cm-atom { color: #cd3f45; }
+.cm-s-seti span.cm-meta { color: #55b5db; }
+.cm-s-seti span.cm-tag { color: #55b5db; }
+.cm-s-seti span.cm-attribute { color: #9fca56; }
+.cm-s-seti span.cm-qualifier { color: #9fca56; }
+.cm-s-seti span.cm-property { color: #a074c4; }
+.cm-s-seti span.cm-variable-3, .cm-s-seti span.cm-type { color: #9fca56; }
+.cm-s-seti span.cm-builtin { color: #9fca56; }
+.cm-s-seti .CodeMirror-activeline-background { background: #101213; }
+.cm-s-seti .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 169 - 0
global/css/codemirror/theme/solarized.css

@@ -0,0 +1,169 @@
+/*
+Solarized theme for code-mirror
+http://ethanschoonover.com/solarized
+*/
+
+/*
+Solarized color palette
+http://ethanschoonover.com/solarized/img/solarized-palette.png
+*/
+
+.solarized.base03 { color: #002b36; }
+.solarized.base02 { color: #073642; }
+.solarized.base01 { color: #586e75; }
+.solarized.base00 { color: #657b83; }
+.solarized.base0 { color: #839496; }
+.solarized.base1 { color: #93a1a1; }
+.solarized.base2 { color: #eee8d5; }
+.solarized.base3  { color: #fdf6e3; }
+.solarized.solar-yellow  { color: #b58900; }
+.solarized.solar-orange  { color: #cb4b16; }
+.solarized.solar-red { color: #dc322f; }
+.solarized.solar-magenta { color: #d33682; }
+.solarized.solar-violet  { color: #6c71c4; }
+.solarized.solar-blue { color: #268bd2; }
+.solarized.solar-cyan { color: #2aa198; }
+.solarized.solar-green { color: #859900; }
+
+/* Color scheme for code-mirror */
+
+.cm-s-solarized {
+  line-height: 1.45em;
+  color-profile: sRGB;
+  rendering-intent: auto;
+}
+.cm-s-solarized.cm-s-dark {
+  color: #839496;
+  background-color: #002b36;
+  text-shadow: #002b36 0 1px;
+}
+.cm-s-solarized.cm-s-light {
+  background-color: #fdf6e3;
+  color: #657b83;
+  text-shadow: #eee8d5 0 1px;
+}
+
+.cm-s-solarized .CodeMirror-widget {
+  text-shadow: none;
+}
+
+.cm-s-solarized .cm-header { color: #586e75; }
+.cm-s-solarized .cm-quote { color: #93a1a1; }
+
+.cm-s-solarized .cm-keyword { color: #cb4b16; }
+.cm-s-solarized .cm-atom { color: #d33682; }
+.cm-s-solarized .cm-number { color: #d33682; }
+.cm-s-solarized .cm-def { color: #2aa198; }
+
+.cm-s-solarized .cm-variable { color: #839496; }
+.cm-s-solarized .cm-variable-2 { color: #b58900; }
+.cm-s-solarized .cm-variable-3, .cm-s-solarized .cm-type { color: #6c71c4; }
+
+.cm-s-solarized .cm-property { color: #2aa198; }
+.cm-s-solarized .cm-operator { color: #6c71c4; }
+
+.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; }
+
+.cm-s-solarized .cm-string { color: #859900; }
+.cm-s-solarized .cm-string-2 { color: #b58900; }
+
+.cm-s-solarized .cm-meta { color: #859900; }
+.cm-s-solarized .cm-qualifier { color: #b58900; }
+.cm-s-solarized .cm-builtin { color: #d33682; }
+.cm-s-solarized .cm-bracket { color: #cb4b16; }
+.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; }
+.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; }
+.cm-s-solarized .cm-tag { color: #93a1a1; }
+.cm-s-solarized .cm-attribute { color: #2aa198; }
+.cm-s-solarized .cm-hr {
+  color: transparent;
+  border-top: 1px solid #586e75;
+  display: block;
+}
+.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; }
+.cm-s-solarized .cm-special { color: #6c71c4; }
+.cm-s-solarized .cm-em {
+  color: #999;
+  text-decoration: underline;
+  text-decoration-style: dotted;
+}
+.cm-s-solarized .cm-strong { color: #eee; }
+.cm-s-solarized .cm-error,
+.cm-s-solarized .cm-invalidchar {
+  color: #586e75;
+  border-bottom: 1px dotted #dc322f;
+}
+
+.cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; }
+.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); }
+.cm-s-solarized.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(7, 54, 66, 0.99); }
+
+.cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; }
+.cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; }
+.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-ligh .CodeMirror-line > span::-moz-selection, .cm-s-ligh .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; }
+
+/* Editor styling */
+
+
+
+/* Little shadow on the view-port of the buffer view */
+.cm-s-solarized.CodeMirror {
+  -moz-box-shadow: inset 7px 0 12px -6px #000;
+  -webkit-box-shadow: inset 7px 0 12px -6px #000;
+  box-shadow: inset 7px 0 12px -6px #000;
+}
+
+/* Remove gutter border */
+.cm-s-solarized .CodeMirror-gutters {
+  border-right: 0;
+}
+
+/* Gutter colors and line number styling based of color scheme (dark / light) */
+
+/* Dark */
+.cm-s-solarized.cm-s-dark .CodeMirror-gutters {
+  background-color: #073642;
+}
+
+.cm-s-solarized.cm-s-dark .CodeMirror-linenumber {
+  color: #586e75;
+  text-shadow: #021014 0 -1px;
+}
+
+/* Light */
+.cm-s-solarized.cm-s-light .CodeMirror-gutters {
+  background-color: #eee8d5;
+}
+
+.cm-s-solarized.cm-s-light .CodeMirror-linenumber {
+  color: #839496;
+}
+
+/* Common */
+.cm-s-solarized .CodeMirror-linenumber {
+  padding: 0 5px;
+}
+.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; }
+.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; }
+.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; }
+
+.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text {
+  color: #586e75;
+}
+
+/* Cursor */
+.cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; }
+
+/* Fat cursor */
+.cm-s-solarized.cm-s-light.cm-fat-cursor .CodeMirror-cursor { background: #77ee77; }
+.cm-s-solarized.cm-s-light .cm-animate-fat-cursor { background-color: #77ee77; }
+.cm-s-solarized.cm-s-dark.cm-fat-cursor .CodeMirror-cursor { background: #586e75; }
+.cm-s-solarized.cm-s-dark .cm-animate-fat-cursor { background-color: #586e75; }
+
+/* Active line */
+.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {
+  background: rgba(255, 255, 255, 0.06);
+}
+.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
+  background: rgba(0, 0, 0, 0.06);
+}

+ 30 - 0
global/css/codemirror/theme/the-matrix.css

@@ -0,0 +1,30 @@
+.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; }
+.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D; }
+.cm-s-the-matrix .CodeMirror-line::selection, .cm-s-the-matrix .CodeMirror-line > span::selection, .cm-s-the-matrix .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); }
+.cm-s-the-matrix .CodeMirror-line::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); }
+.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; }
+.cm-s-the-matrix .CodeMirror-guttermarker { color: #0f0; }
+.cm-s-the-matrix .CodeMirror-guttermarker-subtle { color: white; }
+.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; }
+.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00; }
+
+.cm-s-the-matrix span.cm-keyword { color: #008803; font-weight: bold; }
+.cm-s-the-matrix span.cm-atom { color: #3FF; }
+.cm-s-the-matrix span.cm-number { color: #FFB94F; }
+.cm-s-the-matrix span.cm-def { color: #99C; }
+.cm-s-the-matrix span.cm-variable { color: #F6C; }
+.cm-s-the-matrix span.cm-variable-2 { color: #C6F; }
+.cm-s-the-matrix span.cm-variable-3, .cm-s-the-matrix span.cm-type { color: #96F; }
+.cm-s-the-matrix span.cm-property { color: #62FFA0; }
+.cm-s-the-matrix span.cm-operator { color: #999; }
+.cm-s-the-matrix span.cm-comment { color: #CCCCCC; }
+.cm-s-the-matrix span.cm-string { color: #39C; }
+.cm-s-the-matrix span.cm-meta { color: #C9F; }
+.cm-s-the-matrix span.cm-qualifier { color: #FFF700; }
+.cm-s-the-matrix span.cm-builtin { color: #30a; }
+.cm-s-the-matrix span.cm-bracket { color: #cc7; }
+.cm-s-the-matrix span.cm-tag { color: #FFBD40; }
+.cm-s-the-matrix span.cm-attribute { color: #FFF700; }
+.cm-s-the-matrix span.cm-error { color: #FF0000; }
+
+.cm-s-the-matrix .CodeMirror-activeline-background { background: #040; }

+ 35 - 0
global/css/codemirror/theme/tomorrow-night-bright.css

@@ -0,0 +1,35 @@
+/*
+
+    Name:       Tomorrow Night - Bright
+    Author:     Chris Kempson
+
+    Port done by Gerard Braad <me@gbraad.nl>
+
+*/
+
+.cm-s-tomorrow-night-bright.CodeMirror { background: #000000; color: #eaeaea; }
+.cm-s-tomorrow-night-bright div.CodeMirror-selected { background: #424242; }
+.cm-s-tomorrow-night-bright .CodeMirror-gutters { background: #000000; border-right: 0px; }
+.cm-s-tomorrow-night-bright .CodeMirror-guttermarker { color: #e78c45; }
+.cm-s-tomorrow-night-bright .CodeMirror-guttermarker-subtle { color: #777; }
+.cm-s-tomorrow-night-bright .CodeMirror-linenumber { color: #424242; }
+.cm-s-tomorrow-night-bright .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }
+
+.cm-s-tomorrow-night-bright span.cm-comment { color: #d27b53; }
+.cm-s-tomorrow-night-bright span.cm-atom { color: #a16a94; }
+.cm-s-tomorrow-night-bright span.cm-number { color: #a16a94; }
+
+.cm-s-tomorrow-night-bright span.cm-property, .cm-s-tomorrow-night-bright span.cm-attribute { color: #99cc99; }
+.cm-s-tomorrow-night-bright span.cm-keyword { color: #d54e53; }
+.cm-s-tomorrow-night-bright span.cm-string { color: #e7c547; }
+
+.cm-s-tomorrow-night-bright span.cm-variable { color: #b9ca4a; }
+.cm-s-tomorrow-night-bright span.cm-variable-2 { color: #7aa6da; }
+.cm-s-tomorrow-night-bright span.cm-def { color: #e78c45; }
+.cm-s-tomorrow-night-bright span.cm-bracket { color: #eaeaea; }
+.cm-s-tomorrow-night-bright span.cm-tag { color: #d54e53; }
+.cm-s-tomorrow-night-bright span.cm-link { color: #a16a94; }
+.cm-s-tomorrow-night-bright span.cm-error { background: #d54e53; color: #6A6A6A; }
+
+.cm-s-tomorrow-night-bright .CodeMirror-activeline-background { background: #2a2a2a; }
+.cm-s-tomorrow-night-bright .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 38 - 0
global/css/codemirror/theme/tomorrow-night-eighties.css

@@ -0,0 +1,38 @@
+/*
+
+    Name:       Tomorrow Night - Eighties
+    Author:     Chris Kempson
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-tomorrow-night-eighties.CodeMirror { background: #000000; color: #CCCCCC; }
+.cm-s-tomorrow-night-eighties div.CodeMirror-selected { background: #2D2D2D; }
+.cm-s-tomorrow-night-eighties .CodeMirror-line::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); }
+.cm-s-tomorrow-night-eighties .CodeMirror-line::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); }
+.cm-s-tomorrow-night-eighties .CodeMirror-gutters { background: #000000; border-right: 0px; }
+.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; }
+.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; }
+.cm-s-tomorrow-night-eighties .CodeMirror-linenumber { color: #515151; }
+.cm-s-tomorrow-night-eighties .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }
+
+.cm-s-tomorrow-night-eighties span.cm-comment { color: #d27b53; }
+.cm-s-tomorrow-night-eighties span.cm-atom { color: #a16a94; }
+.cm-s-tomorrow-night-eighties span.cm-number { color: #a16a94; }
+
+.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute { color: #99cc99; }
+.cm-s-tomorrow-night-eighties span.cm-keyword { color: #f2777a; }
+.cm-s-tomorrow-night-eighties span.cm-string { color: #ffcc66; }
+
+.cm-s-tomorrow-night-eighties span.cm-variable { color: #99cc99; }
+.cm-s-tomorrow-night-eighties span.cm-variable-2 { color: #6699cc; }
+.cm-s-tomorrow-night-eighties span.cm-def { color: #f99157; }
+.cm-s-tomorrow-night-eighties span.cm-bracket { color: #CCCCCC; }
+.cm-s-tomorrow-night-eighties span.cm-tag { color: #f2777a; }
+.cm-s-tomorrow-night-eighties span.cm-link { color: #a16a94; }
+.cm-s-tomorrow-night-eighties span.cm-error { background: #f2777a; color: #6A6A6A; }
+
+.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background { background: #343600; }
+.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

+ 64 - 0
global/css/codemirror/theme/ttcn.css

@@ -0,0 +1,64 @@
+.cm-s-ttcn .cm-quote { color: #090; }
+.cm-s-ttcn .cm-negative { color: #d44; }
+.cm-s-ttcn .cm-positive { color: #292; }
+.cm-s-ttcn .cm-header, .cm-strong { font-weight: bold; }
+.cm-s-ttcn .cm-em { font-style: italic; }
+.cm-s-ttcn .cm-link { text-decoration: underline; }
+.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; }
+.cm-s-ttcn .cm-header { color: #00f; font-weight: bold; }
+
+.cm-s-ttcn .cm-atom { color: #219; }
+.cm-s-ttcn .cm-attribute { color: #00c; }
+.cm-s-ttcn .cm-bracket { color: #997; }
+.cm-s-ttcn .cm-comment { color: #333333; }
+.cm-s-ttcn .cm-def { color: #00f; }
+.cm-s-ttcn .cm-em { font-style: italic; }
+.cm-s-ttcn .cm-error { color: #f00; }
+.cm-s-ttcn .cm-hr { color: #999; }
+.cm-s-ttcn .cm-invalidchar { color: #f00; }
+.cm-s-ttcn .cm-keyword { font-weight:bold; }
+.cm-s-ttcn .cm-link { color: #00c; text-decoration: underline; }
+.cm-s-ttcn .cm-meta { color: #555; }
+.cm-s-ttcn .cm-negative { color: #d44; }
+.cm-s-ttcn .cm-positive { color: #292; }
+.cm-s-ttcn .cm-qualifier { color: #555; }
+.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; }
+.cm-s-ttcn .cm-string { color: #006400; }
+.cm-s-ttcn .cm-string-2 { color: #f50; }
+.cm-s-ttcn .cm-strong { font-weight: bold; }
+.cm-s-ttcn .cm-tag { color: #170; }
+.cm-s-ttcn .cm-variable { color: #8B2252; }
+.cm-s-ttcn .cm-variable-2 { color: #05a; }
+.cm-s-ttcn .cm-variable-3, .cm-s-ttcn .cm-type { color: #085; }
+
+.cm-s-ttcn .cm-invalidchar { color: #f00; }
+
+/* ASN */
+.cm-s-ttcn .cm-accessTypes,
+.cm-s-ttcn .cm-compareTypes { color: #27408B; }
+.cm-s-ttcn .cm-cmipVerbs { color: #8B2252; }
+.cm-s-ttcn .cm-modifier { color:#D2691E; }
+.cm-s-ttcn .cm-status { color:#8B4545; }
+.cm-s-ttcn .cm-storage { color:#A020F0; }
+.cm-s-ttcn .cm-tags { color:#006400; }
+
+/* CFG */
+.cm-s-ttcn .cm-externalCommands { color: #8B4545; font-weight:bold; }
+.cm-s-ttcn .cm-fileNCtrlMaskOptions,
+.cm-s-ttcn .cm-sectionTitle { color: #2E8B57; font-weight:bold; }
+
+/* TTCN */
+.cm-s-ttcn .cm-booleanConsts,
+.cm-s-ttcn .cm-otherConsts,
+.cm-s-ttcn .cm-verdictConsts { color: #006400; }
+.cm-s-ttcn .cm-configOps,
+.cm-s-ttcn .cm-functionOps,
+.cm-s-ttcn .cm-portOps,
+.cm-s-ttcn .cm-sutOps,
+.cm-s-ttcn .cm-timerOps,
+.cm-s-ttcn .cm-verdictOps { color: #0000FF; }
+.cm-s-ttcn .cm-preprocessor,
+.cm-s-ttcn .cm-templateMatch,
+.cm-s-ttcn .cm-ttcn3Macros { color: #27408B; }
+.cm-s-ttcn .cm-types { color: #A52A2A; font-weight:bold; }
+.cm-s-ttcn .cm-visibilityModifiers { font-weight:bold; }

+ 32 - 0
global/css/codemirror/theme/twilight.css

@@ -0,0 +1,32 @@
+.cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/
+.cm-s-twilight div.CodeMirror-selected { background: #323232; } /**/
+.cm-s-twilight .CodeMirror-line::selection, .cm-s-twilight .CodeMirror-line > span::selection, .cm-s-twilight .CodeMirror-line > span > span::selection { background: rgba(50, 50, 50, 0.99); }
+.cm-s-twilight .CodeMirror-line::-moz-selection, .cm-s-twilight .CodeMirror-line > span::-moz-selection, .cm-s-twilight .CodeMirror-line > span > span::-moz-selection { background: rgba(50, 50, 50, 0.99); }
+
+.cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; }
+.cm-s-twilight .CodeMirror-guttermarker { color: white; }
+.cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; }
+.cm-s-twilight .CodeMirror-linenumber { color: #aaa; }
+.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-twilight .cm-keyword { color: #f9ee98; } /**/
+.cm-s-twilight .cm-atom { color: #FC0; }
+.cm-s-twilight .cm-number { color:  #ca7841; } /**/
+.cm-s-twilight .cm-def { color: #8DA6CE; }
+.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/
+.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def, .cm-s-twilight span.cm-type { color: #607392; } /**/
+.cm-s-twilight .cm-operator { color: #cda869; } /**/
+.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/
+.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/
+.cm-s-twilight .cm-string-2 { color:#bd6b18; } /*?*/
+.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/
+.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/
+.cm-s-twilight .cm-tag { color: #997643; } /**/
+.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/
+.cm-s-twilight .cm-header { color: #FF6400; }
+.cm-s-twilight .cm-hr { color: #AEAEAE; }
+.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/
+.cm-s-twilight .cm-error { border-bottom: 1px solid red; }
+
+.cm-s-twilight .CodeMirror-activeline-background { background: #27282E; }
+.cm-s-twilight .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }

+ 34 - 0
global/css/codemirror/theme/vibrant-ink.css

@@ -0,0 +1,34 @@
+/* Taken from the popular Visual Studio Vibrant Ink Schema */
+
+.cm-s-vibrant-ink.CodeMirror { background: black; color: white; }
+.cm-s-vibrant-ink div.CodeMirror-selected { background: #35493c; }
+.cm-s-vibrant-ink .CodeMirror-line::selection, .cm-s-vibrant-ink .CodeMirror-line > span::selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::selection { background: rgba(53, 73, 60, 0.99); }
+.cm-s-vibrant-ink .CodeMirror-line::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::-moz-selection { background: rgba(53, 73, 60, 0.99); }
+
+.cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; }
+.cm-s-vibrant-ink .CodeMirror-guttermarker { color: white; }
+.cm-s-vibrant-ink .CodeMirror-guttermarker-subtle { color: #d0d0d0; }
+.cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; }
+.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-vibrant-ink .cm-keyword { color: #CC7832; }
+.cm-s-vibrant-ink .cm-atom { color: #FC0; }
+.cm-s-vibrant-ink .cm-number { color:  #FFEE98; }
+.cm-s-vibrant-ink .cm-def { color: #8DA6CE; }
+.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D; }
+.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def, .cm-s-vibrant span.cm-type { color: #FFC66D; }
+.cm-s-vibrant-ink .cm-operator { color: #888; }
+.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; }
+.cm-s-vibrant-ink .cm-string { color:  #A5C25C; }
+.cm-s-vibrant-ink .cm-string-2 { color: red; }
+.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; }
+.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; }
+.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; }
+.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; }
+.cm-s-vibrant-ink .cm-header { color: #FF6400; }
+.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; }
+.cm-s-vibrant-ink .cm-link { color: blue; }
+.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; }
+
+.cm-s-vibrant-ink .CodeMirror-activeline-background { background: #27282E; }
+.cm-s-vibrant-ink .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }

+ 53 - 0
global/css/codemirror/theme/xq-dark.css

@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2011 by MarkLogic Corporation
+Author: Mike Brevoort <mike@brevoort.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; }
+.cm-s-xq-dark div.CodeMirror-selected { background: #27007A; }
+.cm-s-xq-dark .CodeMirror-line::selection, .cm-s-xq-dark .CodeMirror-line > span::selection, .cm-s-xq-dark .CodeMirror-line > span > span::selection { background: rgba(39, 0, 122, 0.99); }
+.cm-s-xq-dark .CodeMirror-line::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(39, 0, 122, 0.99); }
+.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; }
+.cm-s-xq-dark .CodeMirror-guttermarker { color: #FFBD40; }
+.cm-s-xq-dark .CodeMirror-guttermarker-subtle { color: #f8f8f8; }
+.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; }
+.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white; }
+
+.cm-s-xq-dark span.cm-keyword { color: #FFBD40; }
+.cm-s-xq-dark span.cm-atom { color: #6C8CD5; }
+.cm-s-xq-dark span.cm-number { color: #164; }
+.cm-s-xq-dark span.cm-def { color: #FFF; text-decoration:underline; }
+.cm-s-xq-dark span.cm-variable { color: #FFF; }
+.cm-s-xq-dark span.cm-variable-2 { color: #EEE; }
+.cm-s-xq-dark span.cm-variable-3, .cm-s-xq-dark span.cm-type { color: #DDD; }
+.cm-s-xq-dark span.cm-property {}
+.cm-s-xq-dark span.cm-operator {}
+.cm-s-xq-dark span.cm-comment { color: gray; }
+.cm-s-xq-dark span.cm-string { color: #9FEE00; }
+.cm-s-xq-dark span.cm-meta { color: yellow; }
+.cm-s-xq-dark span.cm-qualifier { color: #FFF700; }
+.cm-s-xq-dark span.cm-builtin { color: #30a; }
+.cm-s-xq-dark span.cm-bracket { color: #cc7; }
+.cm-s-xq-dark span.cm-tag { color: #FFBD40; }
+.cm-s-xq-dark span.cm-attribute { color: #FFF700; }
+.cm-s-xq-dark span.cm-error { color: #f00; }
+
+.cm-s-xq-dark .CodeMirror-activeline-background { background: #27282E; }
+.cm-s-xq-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; }

+ 43 - 0
global/css/codemirror/theme/xq-light.css

@@ -0,0 +1,43 @@
+/*
+Copyright (C) 2011 by MarkLogic Corporation
+Author: Mike Brevoort <mike@brevoort.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+.cm-s-xq-light span.cm-keyword { line-height: 1em; font-weight: bold; color: #5A5CAD; }
+.cm-s-xq-light span.cm-atom { color: #6C8CD5; }
+.cm-s-xq-light span.cm-number { color: #164; }
+.cm-s-xq-light span.cm-def { text-decoration:underline; }
+.cm-s-xq-light span.cm-variable { color: black; }
+.cm-s-xq-light span.cm-variable-2 { color:black; }
+.cm-s-xq-light span.cm-variable-3, .cm-s-xq-light span.cm-type { color: black; }
+.cm-s-xq-light span.cm-property {}
+.cm-s-xq-light span.cm-operator {}
+.cm-s-xq-light span.cm-comment { color: #0080FF; font-style: italic; }
+.cm-s-xq-light span.cm-string { color: red; }
+.cm-s-xq-light span.cm-meta { color: yellow; }
+.cm-s-xq-light span.cm-qualifier { color: grey; }
+.cm-s-xq-light span.cm-builtin { color: #7EA656; }
+.cm-s-xq-light span.cm-bracket { color: #cc7; }
+.cm-s-xq-light span.cm-tag { color: #3F7F7F; }
+.cm-s-xq-light span.cm-attribute { color: #7F007F; }
+.cm-s-xq-light span.cm-error { color: #f00; }
+
+.cm-s-xq-light .CodeMirror-activeline-background { background: #e8f2ff; }
+.cm-s-xq-light .CodeMirror-matchingbracket { outline:1px solid grey;color:black !important;background:yellow; }

+ 44 - 0
global/css/codemirror/theme/yeti.css

@@ -0,0 +1,44 @@
+/*
+
+    Name:       yeti
+    Author:     Michael Kaminsky (http://github.com/mkaminsky11)
+
+    Original yeti color scheme by Jesse Weed (https://github.com/jesseweed/yeti-syntax)
+
+*/
+
+
+.cm-s-yeti.CodeMirror {
+  background-color: #ECEAE8 !important;
+  color: #d1c9c0 !important;
+  border: none;
+}
+
+.cm-s-yeti .CodeMirror-gutters {
+  color: #adaba6;
+  background-color: #E5E1DB;
+  border: none;
+}
+.cm-s-yeti .CodeMirror-cursor { border-left: solid thin #d1c9c0; }
+.cm-s-yeti .CodeMirror-linenumber { color: #adaba6; }
+.cm-s-yeti.CodeMirror-focused div.CodeMirror-selected { background: #DCD8D2; }
+.cm-s-yeti .CodeMirror-line::selection, .cm-s-yeti .CodeMirror-line > span::selection, .cm-s-yeti .CodeMirror-line > span > span::selection { background: #DCD8D2; }
+.cm-s-yeti .CodeMirror-line::-moz-selection, .cm-s-yeti .CodeMirror-line > span::-moz-selection, .cm-s-yeti .CodeMirror-line > span > span::-moz-selection { background: #DCD8D2; }
+.cm-s-yeti span.cm-comment { color: #d4c8be; }
+.cm-s-yeti span.cm-string, .cm-s-yeti span.cm-string-2 { color: #96c0d8; }
+.cm-s-yeti span.cm-number { color: #a074c4; }
+.cm-s-yeti span.cm-variable { color: #55b5db; }
+.cm-s-yeti span.cm-variable-2 { color: #a074c4; }
+.cm-s-yeti span.cm-def { color: #55b5db; }
+.cm-s-yeti span.cm-operator { color: #9fb96e; }
+.cm-s-yeti span.cm-keyword { color: #9fb96e; }
+.cm-s-yeti span.cm-atom { color: #a074c4; }
+.cm-s-yeti span.cm-meta { color: #96c0d8; }
+.cm-s-yeti span.cm-tag { color: #96c0d8; }
+.cm-s-yeti span.cm-attribute { color: #9fb96e; }
+.cm-s-yeti span.cm-qualifier { color: #96c0d8; }
+.cm-s-yeti span.cm-property { color: #a074c4; }
+.cm-s-yeti span.cm-builtin { color: #a074c4; }
+.cm-s-yeti span.cm-variable-3, .cm-s-yeti span.cm-type { color: #96c0d8; }
+.cm-s-yeti .CodeMirror-activeline-background { background: #E7E4E0; }
+.cm-s-yeti .CodeMirror-matchingbracket { text-decoration: underline; }

+ 37 - 0
global/css/codemirror/theme/zenburn.css

@@ -0,0 +1,37 @@
+/**
+ * "
+ *  Using Zenburn color palette from the Emacs Zenburn Theme
+ *  https://github.com/bbatsov/zenburn-emacs/blob/master/zenburn-theme.el
+ *
+ *  Also using parts of https://github.com/xavi/coderay-lighttable-theme
+ * "
+ * From: https://github.com/wisenomad/zenburn-lighttable-theme/blob/master/zenburn.css
+ */
+
+.cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; }
+.cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; }
+.cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white; }
+.cm-s-zenburn { background-color: #3f3f3f; color: #dcdccc; }
+.cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; }
+.cm-s-zenburn span.cm-comment { color: #7f9f7f; }
+.cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; }
+.cm-s-zenburn span.cm-atom { color: #bfebbf; }
+.cm-s-zenburn span.cm-def { color: #dcdccc; }
+.cm-s-zenburn span.cm-variable { color: #dfaf8f; }
+.cm-s-zenburn span.cm-variable-2 { color: #dcdccc; }
+.cm-s-zenburn span.cm-string { color: #cc9393; }
+.cm-s-zenburn span.cm-string-2 { color: #cc9393; }
+.cm-s-zenburn span.cm-number { color: #dcdccc; }
+.cm-s-zenburn span.cm-tag { color: #93e0e3; }
+.cm-s-zenburn span.cm-property { color: #dfaf8f; }
+.cm-s-zenburn span.cm-attribute { color: #dfaf8f; }
+.cm-s-zenburn span.cm-qualifier { color: #7cb8bb; }
+.cm-s-zenburn span.cm-meta { color: #f0dfaf; }
+.cm-s-zenburn span.cm-header { color: #f0efd0; }
+.cm-s-zenburn span.cm-operator { color: #f0efd0; }
+.cm-s-zenburn span.CodeMirror-matchingbracket { box-sizing: border-box; background: transparent; border-bottom: 1px solid; }
+.cm-s-zenburn span.CodeMirror-nonmatchingbracket { border-bottom: 1px solid; background: none; }
+.cm-s-zenburn .CodeMirror-activeline { background: #000000; }
+.cm-s-zenburn .CodeMirror-activeline-background { background: #000000; }
+.cm-s-zenburn div.CodeMirror-selected { background: #545454; }
+.cm-s-zenburn .CodeMirror-focused div.CodeMirror-selected { background: #4f4f4f; }

BIN
global/css/login-bg-fc.jpg


BIN
global/css/login-bg.jpg


+ 118 - 0
global/css/style.css

@@ -0,0 +1,118 @@
+@charset "utf-8";
+ul, ol, li{
+  line-height:normal;
+  list-style-image:none;
+  list-style-position:outside;
+  list-style-type:none;
+  margin:0
+}
+dl {
+  margin:0
+}
+dd {
+  margin-left:0
+}
+body{
+  font: 12px/1.5 tahoma,arial,'Hiragino Sans GB',"微软雅黑",sans-serif;
+}
+a {
+  outline:none;
+} 
+a {
+  color: #0088cc;
+  text-decoration: none;
+}
+a:hover,
+a:focus {
+  color: #005580;
+  text-decoration:none;
+}
+.login.copy-right{
+  position:fixed;
+  bottom: 0;
+  left:50%;
+  margin-left: -112px
+}
+.login-top{
+  width:100%;
+  height:320px;
+  background: url(login-bg.jpg) no-repeat center center;
+  margin-bottom:30px;
+}
+.login-top.login-fc-bg{
+  background: url(login-bg-fc.jpg) no-repeat center center
+}
+.login-top h4,.login-top h5{
+  text-align: center;
+  color:#fff;
+  text-shadow:1px 1px 1px #333;
+}
+.login-top h4{
+  font-size:48px;
+  margin:120px 0 0 0;
+}
+.login-item .login-form{
+  width: 400px;
+  margin:0 auto;
+}
+.side-nav {
+  width:50px;
+  position:fixed;
+  left:0;
+  top:0;
+}
+.side-nav h1{
+  background:#333;
+  color:#fff;
+  font-size: 24px;
+  height:50px;
+  line-height: 50px;
+  margin:0;
+  text-align: center
+}
+.side-nav ul{
+  margin:0;
+  padding:0;
+  border-right:1px solid #333;
+}
+.side-nav ul li {
+  width:50px;
+  height:50px;
+}
+.side-nav ul li a{
+  display:inline-block;
+  color:#CCC;
+  font-size: 18px;
+  width:50px;
+  height:50px;
+  line-height: 50px;
+  text-align: center
+}
+.side-nav ul li a:hover{
+  color:#333
+}
+.side-nav ul li a.active{
+  color:#000;
+}
+.warp-content {
+  margin-left:50px;
+}
+.page-nav {
+  margin-bottom:10px;
+}
+nav a{
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5px;
+  text-decoration:none;
+  color: #337ab7;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+  margin-left: -1px;
+}
+nav a.current {
+  background: #ccc;
+  color: #fff;
+  font-weight: 600;
+  cursor: default;
+}

BIN
global/fonts/glyphicons-halflings-regular.eot


File diff suppressed because it is too large
+ 288 - 0
global/fonts/glyphicons-halflings-regular.svg


BIN
global/fonts/glyphicons-halflings-regular.ttf


BIN
global/fonts/glyphicons-halflings-regular.woff


BIN
global/fonts/glyphicons-halflings-regular.woff2


File diff suppressed because it is too large
+ 2363 - 0
global/js/bootstrap.js


File diff suppressed because it is too large
+ 7 - 0
global/js/bootstrap.min.js


File diff suppressed because it is too large
+ 8935 - 0
global/js/codemirror/codemirror.js


+ 825 - 0
global/js/codemirror/css.js

@@ -0,0 +1,825 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.defineMode("css", function(config, parserConfig) {
+  var inline = parserConfig.inline
+  if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
+
+  var indentUnit = config.indentUnit,
+      tokenHooks = parserConfig.tokenHooks,
+      documentTypes = parserConfig.documentTypes || {},
+      mediaTypes = parserConfig.mediaTypes || {},
+      mediaFeatures = parserConfig.mediaFeatures || {},
+      mediaValueKeywords = parserConfig.mediaValueKeywords || {},
+      propertyKeywords = parserConfig.propertyKeywords || {},
+      nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
+      fontProperties = parserConfig.fontProperties || {},
+      counterDescriptors = parserConfig.counterDescriptors || {},
+      colorKeywords = parserConfig.colorKeywords || {},
+      valueKeywords = parserConfig.valueKeywords || {},
+      allowNested = parserConfig.allowNested,
+      supportsAtComponent = parserConfig.supportsAtComponent === true;
+
+  var type, override;
+  function ret(style, tp) { type = tp; return style; }
+
+  // Tokenizers
+
+  function tokenBase(stream, state) {
+    var ch = stream.next();
+    if (tokenHooks[ch]) {
+      var result = tokenHooks[ch](stream, state);
+      if (result !== false) return result;
+    }
+    if (ch == "@") {
+      stream.eatWhile(/[\w\\\-]/);
+      return ret("def", stream.current());
+    } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
+      return ret(null, "compare");
+    } else if (ch == "\"" || ch == "'") {
+      state.tokenize = tokenString(ch);
+      return state.tokenize(stream, state);
+    } else if (ch == "#") {
+      stream.eatWhile(/[\w\\\-]/);
+      return ret("atom", "hash");
+    } else if (ch == "!") {
+      stream.match(/^\s*\w*/);
+      return ret("keyword", "important");
+    } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
+      stream.eatWhile(/[\w.%]/);
+      return ret("number", "unit");
+    } else if (ch === "-") {
+      if (/[\d.]/.test(stream.peek())) {
+        stream.eatWhile(/[\w.%]/);
+        return ret("number", "unit");
+      } else if (stream.match(/^-[\w\\\-]+/)) {
+        stream.eatWhile(/[\w\\\-]/);
+        if (stream.match(/^\s*:/, false))
+          return ret("variable-2", "variable-definition");
+        return ret("variable-2", "variable");
+      } else if (stream.match(/^\w+-/)) {
+        return ret("meta", "meta");
+      }
+    } else if (/[,+>*\/]/.test(ch)) {
+      return ret(null, "select-op");
+    } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
+      return ret("qualifier", "qualifier");
+    } else if (/[:;{}\[\]\(\)]/.test(ch)) {
+      return ret(null, ch);
+    } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
+               (ch == "d" && stream.match("omain(")) ||
+               (ch == "r" && stream.match("egexp("))) {
+      stream.backUp(1);
+      state.tokenize = tokenParenthesized;
+      return ret("property", "word");
+    } else if (/[\w\\\-]/.test(ch)) {
+      stream.eatWhile(/[\w\\\-]/);
+      return ret("property", "word");
+    } else {
+      return ret(null, null);
+    }
+  }
+
+  function tokenString(quote) {
+    return function(stream, state) {
+      var escaped = false, ch;
+      while ((ch = stream.next()) != null) {
+        if (ch == quote && !escaped) {
+          if (quote == ")") stream.backUp(1);
+          break;
+        }
+        escaped = !escaped && ch == "\\";
+      }
+      if (ch == quote || !escaped && quote != ")") state.tokenize = null;
+      return ret("string", "string");
+    };
+  }
+
+  function tokenParenthesized(stream, state) {
+    stream.next(); // Must be '('
+    if (!stream.match(/\s*[\"\')]/, false))
+      state.tokenize = tokenString(")");
+    else
+      state.tokenize = null;
+    return ret(null, "(");
+  }
+
+  // Context management
+
+  function Context(type, indent, prev) {
+    this.type = type;
+    this.indent = indent;
+    this.prev = prev;
+  }
+
+  function pushContext(state, stream, type, indent) {
+    state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
+    return type;
+  }
+
+  function popContext(state) {
+    if (state.context.prev)
+      state.context = state.context.prev;
+    return state.context.type;
+  }
+
+  function pass(type, stream, state) {
+    return states[state.context.type](type, stream, state);
+  }
+  function popAndPass(type, stream, state, n) {
+    for (var i = n || 1; i > 0; i--)
+      state.context = state.context.prev;
+    return pass(type, stream, state);
+  }
+
+  // Parser
+
+  function wordAsValue(stream) {
+    var word = stream.current().toLowerCase();
+    if (valueKeywords.hasOwnProperty(word))
+      override = "atom";
+    else if (colorKeywords.hasOwnProperty(word))
+      override = "keyword";
+    else
+      override = "variable";
+  }
+
+  var states = {};
+
+  states.top = function(type, stream, state) {
+    if (type == "{") {
+      return pushContext(state, stream, "block");
+    } else if (type == "}" && state.context.prev) {
+      return popContext(state);
+    } else if (supportsAtComponent && /@component/.test(type)) {
+      return pushContext(state, stream, "atComponentBlock");
+    } else if (/^@(-moz-)?document$/.test(type)) {
+      return pushContext(state, stream, "documentTypes");
+    } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
+      return pushContext(state, stream, "atBlock");
+    } else if (/^@(font-face|counter-style)/.test(type)) {
+      state.stateArg = type;
+      return "restricted_atBlock_before";
+    } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
+      return "keyframes";
+    } else if (type && type.charAt(0) == "@") {
+      return pushContext(state, stream, "at");
+    } else if (type == "hash") {
+      override = "builtin";
+    } else if (type == "word") {
+      override = "tag";
+    } else if (type == "variable-definition") {
+      return "maybeprop";
+    } else if (type == "interpolation") {
+      return pushContext(state, stream, "interpolation");
+    } else if (type == ":") {
+      return "pseudo";
+    } else if (allowNested && type == "(") {
+      return pushContext(state, stream, "parens");
+    }
+    return state.context.type;
+  };
+
+  states.block = function(type, stream, state) {
+    if (type == "word") {
+      var word = stream.current().toLowerCase();
+      if (propertyKeywords.hasOwnProperty(word)) {
+        override = "property";
+        return "maybeprop";
+      } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
+        override = "string-2";
+        return "maybeprop";
+      } else if (allowNested) {
+        override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
+        return "block";
+      } else {
+        override += " error";
+        return "maybeprop";
+      }
+    } else if (type == "meta") {
+      return "block";
+    } else if (!allowNested && (type == "hash" || type == "qualifier")) {
+      override = "error";
+      return "block";
+    } else {
+      return states.top(type, stream, state);
+    }
+  };
+
+  states.maybeprop = function(type, stream, state) {
+    if (type == ":") return pushContext(state, stream, "prop");
+    return pass(type, stream, state);
+  };
+
+  states.prop = function(type, stream, state) {
+    if (type == ";") return popContext(state);
+    if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
+    if (type == "}" || type == "{") return popAndPass(type, stream, state);
+    if (type == "(") return pushContext(state, stream, "parens");
+
+    if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
+      override += " error";
+    } else if (type == "word") {
+      wordAsValue(stream);
+    } else if (type == "interpolation") {
+      return pushContext(state, stream, "interpolation");
+    }
+    return "prop";
+  };
+
+  states.propBlock = function(type, _stream, state) {
+    if (type == "}") return popContext(state);
+    if (type == "word") { override = "property"; return "maybeprop"; }
+    return state.context.type;
+  };
+
+  states.parens = function(type, stream, state) {
+    if (type == "{" || type == "}") return popAndPass(type, stream, state);
+    if (type == ")") return popContext(state);
+    if (type == "(") return pushContext(state, stream, "parens");
+    if (type == "interpolation") return pushContext(state, stream, "interpolation");
+    if (type == "word") wordAsValue(stream);
+    return "parens";
+  };
+
+  states.pseudo = function(type, stream, state) {
+    if (type == "word") {
+      override = "variable-3";
+      return state.context.type;
+    }
+    return pass(type, stream, state);
+  };
+
+  states.documentTypes = function(type, stream, state) {
+    if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
+      override = "tag";
+      return state.context.type;
+    } else {
+      return states.atBlock(type, stream, state);
+    }
+  };
+
+  states.atBlock = function(type, stream, state) {
+    if (type == "(") return pushContext(state, stream, "atBlock_parens");
+    if (type == "}" || type == ";") return popAndPass(type, stream, state);
+    if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
+
+    if (type == "interpolation") return pushContext(state, stream, "interpolation");
+
+    if (type == "word") {
+      var word = stream.current().toLowerCase();
+      if (word == "only" || word == "not" || word == "and" || word == "or")
+        override = "keyword";
+      else if (mediaTypes.hasOwnProperty(word))
+        override = "attribute";
+      else if (mediaFeatures.hasOwnProperty(word))
+        override = "property";
+      else if (mediaValueKeywords.hasOwnProperty(word))
+        override = "keyword";
+      else if (propertyKeywords.hasOwnProperty(word))
+        override = "property";
+      else if (nonStandardPropertyKeywords.hasOwnProperty(word))
+        override = "string-2";
+      else if (valueKeywords.hasOwnProperty(word))
+        override = "atom";
+      else if (colorKeywords.hasOwnProperty(word))
+        override = "keyword";
+      else
+        override = "error";
+    }
+    return state.context.type;
+  };
+
+  states.atComponentBlock = function(type, stream, state) {
+    if (type == "}")
+      return popAndPass(type, stream, state);
+    if (type == "{")
+      return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
+    if (type == "word")
+      override = "error";
+    return state.context.type;
+  };
+
+  states.atBlock_parens = function(type, stream, state) {
+    if (type == ")") return popContext(state);
+    if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
+    return states.atBlock(type, stream, state);
+  };
+
+  states.restricted_atBlock_before = function(type, stream, state) {
+    if (type == "{")
+      return pushContext(state, stream, "restricted_atBlock");
+    if (type == "word" && state.stateArg == "@counter-style") {
+      override = "variable";
+      return "restricted_atBlock_before";
+    }
+    return pass(type, stream, state);
+  };
+
+  states.restricted_atBlock = function(type, stream, state) {
+    if (type == "}") {
+      state.stateArg = null;
+      return popContext(state);
+    }
+    if (type == "word") {
+      if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
+          (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
+        override = "error";
+      else
+        override = "property";
+      return "maybeprop";
+    }
+    return "restricted_atBlock";
+  };
+
+  states.keyframes = function(type, stream, state) {
+    if (type == "word") { override = "variable"; return "keyframes"; }
+    if (type == "{") return pushContext(state, stream, "top");
+    return pass(type, stream, state);
+  };
+
+  states.at = function(type, stream, state) {
+    if (type == ";") return popContext(state);
+    if (type == "{" || type == "}") return popAndPass(type, stream, state);
+    if (type == "word") override = "tag";
+    else if (type == "hash") override = "builtin";
+    return "at";
+  };
+
+  states.interpolation = function(type, stream, state) {
+    if (type == "}") return popContext(state);
+    if (type == "{" || type == ";") return popAndPass(type, stream, state);
+    if (type == "word") override = "variable";
+    else if (type != "variable" && type != "(" && type != ")") override = "error";
+    return "interpolation";
+  };
+
+  return {
+    startState: function(base) {
+      return {tokenize: null,
+              state: inline ? "block" : "top",
+              stateArg: null,
+              context: new Context(inline ? "block" : "top", base || 0, null)};
+    },
+
+    token: function(stream, state) {
+      if (!state.tokenize && stream.eatSpace()) return null;
+      var style = (state.tokenize || tokenBase)(stream, state);
+      if (style && typeof style == "object") {
+        type = style[1];
+        style = style[0];
+      }
+      override = style;
+      state.state = states[state.state](type, stream, state);
+      return override;
+    },
+
+    indent: function(state, textAfter) {
+      var cx = state.context, ch = textAfter && textAfter.charAt(0);
+      var indent = cx.indent;
+      if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
+      if (cx.prev) {
+        if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
+                          cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
+          // Resume indentation from parent context.
+          cx = cx.prev;
+          indent = cx.indent;
+        } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
+            ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
+          // Dedent relative to current context.
+          indent = Math.max(0, cx.indent - indentUnit);
+          cx = cx.prev;
+        }
+      }
+      return indent;
+    },
+
+    electricChars: "}",
+    blockCommentStart: "/*",
+    blockCommentEnd: "*/",
+    fold: "brace"
+  };
+});
+
+  function keySet(array) {
+    var keys = {};
+    for (var i = 0; i < array.length; ++i) {
+      keys[array[i]] = true;
+    }
+    return keys;
+  }
+
+  var documentTypes_ = [
+    "domain", "regexp", "url", "url-prefix"
+  ], documentTypes = keySet(documentTypes_);
+
+  var mediaTypes_ = [
+    "all", "aural", "braille", "handheld", "print", "projection", "screen",
+    "tty", "tv", "embossed"
+  ], mediaTypes = keySet(mediaTypes_);
+
+  var mediaFeatures_ = [
+    "width", "min-width", "max-width", "height", "min-height", "max-height",
+    "device-width", "min-device-width", "max-device-width", "device-height",
+    "min-device-height", "max-device-height", "aspect-ratio",
+    "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
+    "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
+    "max-color", "color-index", "min-color-index", "max-color-index",
+    "monochrome", "min-monochrome", "max-monochrome", "resolution",
+    "min-resolution", "max-resolution", "scan", "grid", "orientation",
+    "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
+    "pointer", "any-pointer", "hover", "any-hover"
+  ], mediaFeatures = keySet(mediaFeatures_);
+
+  var mediaValueKeywords_ = [
+    "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
+    "interlace", "progressive"
+  ], mediaValueKeywords = keySet(mediaValueKeywords_);
+
+  var propertyKeywords_ = [
+    "align-content", "align-items", "align-self", "alignment-adjust",
+    "alignment-baseline", "anchor-point", "animation", "animation-delay",
+    "animation-direction", "animation-duration", "animation-fill-mode",
+    "animation-iteration-count", "animation-name", "animation-play-state",
+    "animation-timing-function", "appearance", "azimuth", "backface-visibility",
+    "background", "background-attachment", "background-blend-mode", "background-clip",
+    "background-color", "background-image", "background-origin", "background-position",
+    "background-repeat", "background-size", "baseline-shift", "binding",
+    "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
+    "bookmark-target", "border", "border-bottom", "border-bottom-color",
+    "border-bottom-left-radius", "border-bottom-right-radius",
+    "border-bottom-style", "border-bottom-width", "border-collapse",
+    "border-color", "border-image", "border-image-outset",
+    "border-image-repeat", "border-image-slice", "border-image-source",
+    "border-image-width", "border-left", "border-left-color",
+    "border-left-style", "border-left-width", "border-radius", "border-right",
+    "border-right-color", "border-right-style", "border-right-width",
+    "border-spacing", "border-style", "border-top", "border-top-color",
+    "border-top-left-radius", "border-top-right-radius", "border-top-style",
+    "border-top-width", "border-width", "bottom", "box-decoration-break",
+    "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
+    "caption-side", "clear", "clip", "color", "color-profile", "column-count",
+    "column-fill", "column-gap", "column-rule", "column-rule-color",
+    "column-rule-style", "column-rule-width", "column-span", "column-width",
+    "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
+    "cue-after", "cue-before", "cursor", "direction", "display",
+    "dominant-baseline", "drop-initial-after-adjust",
+    "drop-initial-after-align", "drop-initial-before-adjust",
+    "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
+    "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
+    "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
+    "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
+    "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
+    "font-stretch", "font-style", "font-synthesis", "font-variant",
+    "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
+    "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
+    "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
+    "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
+    "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
+    "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
+    "grid-template-rows", "hanging-punctuation", "height", "hyphens",
+    "icon", "image-orientation", "image-rendering", "image-resolution",
+    "inline-box-align", "justify-content", "left", "letter-spacing",
+    "line-break", "line-height", "line-stacking", "line-stacking-ruby",
+    "line-stacking-shift", "line-stacking-strategy", "list-style",
+    "list-style-image", "list-style-position", "list-style-type", "margin",
+    "margin-bottom", "margin-left", "margin-right", "margin-top",
+    "marker-offset", "marks", "marquee-direction", "marquee-loop",
+    "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
+    "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
+    "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
+    "opacity", "order", "orphans", "outline",
+    "outline-color", "outline-offset", "outline-style", "outline-width",
+    "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
+    "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
+    "page", "page-break-after", "page-break-before", "page-break-inside",
+    "page-policy", "pause", "pause-after", "pause-before", "perspective",
+    "perspective-origin", "pitch", "pitch-range", "play-during", "position",
+    "presentation-level", "punctuation-trim", "quotes", "region-break-after",
+    "region-break-before", "region-break-inside", "region-fragment",
+    "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
+    "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
+    "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
+    "shape-outside", "size", "speak", "speak-as", "speak-header",
+    "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
+    "tab-size", "table-layout", "target", "target-name", "target-new",
+    "target-position", "text-align", "text-align-last", "text-decoration",
+    "text-decoration-color", "text-decoration-line", "text-decoration-skip",
+    "text-decoration-style", "text-emphasis", "text-emphasis-color",
+    "text-emphasis-position", "text-emphasis-style", "text-height",
+    "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
+    "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
+    "text-wrap", "top", "transform", "transform-origin", "transform-style",
+    "transition", "transition-delay", "transition-duration",
+    "transition-property", "transition-timing-function", "unicode-bidi",
+    "vertical-align", "visibility", "voice-balance", "voice-duration",
+    "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
+    "voice-volume", "volume", "white-space", "widows", "width", "word-break",
+    "word-spacing", "word-wrap", "z-index",
+    // SVG-specific
+    "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
+    "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
+    "color-interpolation", "color-interpolation-filters",
+    "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
+    "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
+    "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
+    "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
+    "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
+    "glyph-orientation-vertical", "text-anchor", "writing-mode"
+  ], propertyKeywords = keySet(propertyKeywords_);
+
+  var nonStandardPropertyKeywords_ = [
+    "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
+    "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
+    "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
+    "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
+    "searchfield-results-decoration", "zoom"
+  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
+
+  var fontProperties_ = [
+    "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
+    "font-stretch", "font-weight", "font-style"
+  ], fontProperties = keySet(fontProperties_);
+
+  var counterDescriptors_ = [
+    "additive-symbols", "fallback", "negative", "pad", "prefix", "range",
+    "speak-as", "suffix", "symbols", "system"
+  ], counterDescriptors = keySet(counterDescriptors_);
+
+  var colorKeywords_ = [
+    "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
+    "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
+    "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
+    "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
+    "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
+    "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
+    "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
+    "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
+    "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
+    "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
+    "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
+    "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
+    "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
+    "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
+    "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
+    "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
+    "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
+    "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
+    "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
+    "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
+    "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
+    "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
+    "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
+    "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
+    "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
+    "whitesmoke", "yellow", "yellowgreen"
+  ], colorKeywords = keySet(colorKeywords_);
+
+  var valueKeywords_ = [
+    "above", "absolute", "activeborder", "additive", "activecaption", "afar",
+    "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
+    "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
+    "arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page",
+    "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
+    "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
+    "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
+    "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
+    "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
+    "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
+    "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
+    "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
+    "compact", "condensed", "contain", "content",
+    "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
+    "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
+    "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
+    "destination-in", "destination-out", "destination-over", "devanagari", "difference",
+    "disc", "discard", "disclosure-closed", "disclosure-open", "document",
+    "dot-dash", "dot-dot-dash",
+    "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
+    "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
+    "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
+    "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
+    "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
+    "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
+    "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
+    "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
+    "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
+    "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
+    "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
+    "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
+    "help", "hidden", "hide", "higher", "highlight", "highlighttext",
+    "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
+    "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
+    "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
+    "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
+    "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
+    "katakana", "katakana-iroha", "keep-all", "khmer",
+    "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
+    "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
+    "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
+    "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
+    "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
+    "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
+    "media-controls-background", "media-current-time-display",
+    "media-fullscreen-button", "media-mute-button", "media-play-button",
+    "media-return-to-realtime-button", "media-rewind-button",
+    "media-seek-back-button", "media-seek-forward-button", "media-slider",
+    "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
+    "media-volume-slider-container", "media-volume-sliderthumb", "medium",
+    "menu", "menulist", "menulist-button", "menulist-text",
+    "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
+    "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
+    "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
+    "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
+    "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
+    "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
+    "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
+    "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
+    "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
+    "progress", "push-button", "radial-gradient", "radio", "read-only",
+    "read-write", "read-write-plaintext-only", "rectangle", "region",
+    "relative", "repeat", "repeating-linear-gradient",
+    "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
+    "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
+    "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
+    "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
+    "scroll", "scrollbar", "se-resize", "searchfield",
+    "searchfield-cancel-button", "searchfield-decoration",
+    "searchfield-results-button", "searchfield-results-decoration",
+    "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
+    "simp-chinese-formal", "simp-chinese-informal", "single",
+    "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
+    "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
+    "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
+    "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "spell-out", "square",
+    "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
+    "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table",
+    "table-caption", "table-cell", "table-column", "table-column-group",
+    "table-footer-group", "table-header-group", "table-row", "table-row-group",
+    "tamil",
+    "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
+    "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
+    "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
+    "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
+    "trad-chinese-formal", "trad-chinese-informal",
+    "translate", "translate3d", "translateX", "translateY", "translateZ",
+    "transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
+    "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
+    "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
+    "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
+    "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
+    "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
+    "xx-large", "xx-small"
+  ], valueKeywords = keySet(valueKeywords_);
+
+  var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
+    .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
+    .concat(valueKeywords_);
+  CodeMirror.registerHelper("hintWords", "css", allWords);
+
+  function tokenCComment(stream, state) {
+    var maybeEnd = false, ch;
+    while ((ch = stream.next()) != null) {
+      if (maybeEnd && ch == "/") {
+        state.tokenize = null;
+        break;
+      }
+      maybeEnd = (ch == "*");
+    }
+    return ["comment", "comment"];
+  }
+
+  CodeMirror.defineMIME("text/css", {
+    documentTypes: documentTypes,
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    mediaValueKeywords: mediaValueKeywords,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    fontProperties: fontProperties,
+    counterDescriptors: counterDescriptors,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (!stream.eat("*")) return false;
+        state.tokenize = tokenCComment;
+        return tokenCComment(stream, state);
+      }
+    },
+    name: "css"
+  });
+
+  CodeMirror.defineMIME("text/x-scss", {
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    mediaValueKeywords: mediaValueKeywords,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    fontProperties: fontProperties,
+    allowNested: true,
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (stream.eat("/")) {
+          stream.skipToEnd();
+          return ["comment", "comment"];
+        } else if (stream.eat("*")) {
+          state.tokenize = tokenCComment;
+          return tokenCComment(stream, state);
+        } else {
+          return ["operator", "operator"];
+        }
+      },
+      ":": function(stream) {
+        if (stream.match(/\s*\{/))
+          return [null, "{"];
+        return false;
+      },
+      "$": function(stream) {
+        stream.match(/^[\w-]+/);
+        if (stream.match(/^\s*:/, false))
+          return ["variable-2", "variable-definition"];
+        return ["variable-2", "variable"];
+      },
+      "#": function(stream) {
+        if (!stream.eat("{")) return false;
+        return [null, "interpolation"];
+      }
+    },
+    name: "css",
+    helperType: "scss"
+  });
+
+  CodeMirror.defineMIME("text/x-less", {
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    mediaValueKeywords: mediaValueKeywords,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    fontProperties: fontProperties,
+    allowNested: true,
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (stream.eat("/")) {
+          stream.skipToEnd();
+          return ["comment", "comment"];
+        } else if (stream.eat("*")) {
+          state.tokenize = tokenCComment;
+          return tokenCComment(stream, state);
+        } else {
+          return ["operator", "operator"];
+        }
+      },
+      "@": function(stream) {
+        if (stream.eat("{")) return [null, "interpolation"];
+        if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
+        stream.eatWhile(/[\w\\\-]/);
+        if (stream.match(/^\s*:/, false))
+          return ["variable-2", "variable-definition"];
+        return ["variable-2", "variable"];
+      },
+      "&": function() {
+        return ["atom", "atom"];
+      }
+    },
+    name: "css",
+    helperType: "less"
+  });
+
+  CodeMirror.defineMIME("text/x-gss", {
+    documentTypes: documentTypes,
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    fontProperties: fontProperties,
+    counterDescriptors: counterDescriptors,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    supportsAtComponent: true,
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (!stream.eat("*")) return false;
+        state.tokenize = tokenCComment;
+        return tokenCComment(stream, state);
+      }
+    },
+    name: "css",
+    helperType: "gss"
+  });
+
+});

+ 105 - 0
global/js/codemirror/fold/brace-fold.js

@@ -0,0 +1,105 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.registerHelper("fold", "brace", function(cm, start) {
+  var line = start.line, lineText = cm.getLine(line);
+  var tokenType;
+
+  function findOpening(openCh) {
+    for (var at = start.ch, pass = 0;;) {
+      var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
+      if (found == -1) {
+        if (pass == 1) break;
+        pass = 1;
+        at = lineText.length;
+        continue;
+      }
+      if (pass == 1 && found < start.ch) break;
+      tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
+      if (!/^(comment|string)/.test(tokenType)) return found + 1;
+      at = found - 1;
+    }
+  }
+
+  var startToken = "{", endToken = "}", startCh = findOpening("{");
+  if (startCh == null) {
+    startToken = "[", endToken = "]";
+    startCh = findOpening("[");
+  }
+
+  if (startCh == null) return;
+  var count = 1, lastLine = cm.lastLine(), end, endCh;
+  outer: for (var i = line; i <= lastLine; ++i) {
+    var text = cm.getLine(i), pos = i == line ? startCh : 0;
+    for (;;) {
+      var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
+      if (nextOpen < 0) nextOpen = text.length;
+      if (nextClose < 0) nextClose = text.length;
+      pos = Math.min(nextOpen, nextClose);
+      if (pos == text.length) break;
+      if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
+        if (pos == nextOpen) ++count;
+        else if (!--count) { end = i; endCh = pos; break outer; }
+      }
+      ++pos;
+    }
+  }
+  if (end == null || line == end && endCh == startCh) return;
+  return {from: CodeMirror.Pos(line, startCh),
+          to: CodeMirror.Pos(end, endCh)};
+});
+
+CodeMirror.registerHelper("fold", "import", function(cm, start) {
+  function hasImport(line) {
+    if (line < cm.firstLine() || line > cm.lastLine()) return null;
+    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+    if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+    if (start.type != "keyword" || start.string != "import") return null;
+    // Now find closing semicolon, return its position
+    for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
+      var text = cm.getLine(i), semi = text.indexOf(";");
+      if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
+    }
+  }
+
+  var startLine = start.line, has = hasImport(startLine), prev;
+  if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
+    return null;
+  for (var end = has.end;;) {
+    var next = hasImport(end.line + 1);
+    if (next == null) break;
+    end = next.end;
+  }
+  return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
+});
+
+CodeMirror.registerHelper("fold", "include", function(cm, start) {
+  function hasInclude(line) {
+    if (line < cm.firstLine() || line > cm.lastLine()) return null;
+    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+    if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+    if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
+  }
+
+  var startLine = start.line, has = hasInclude(startLine);
+  if (has == null || hasInclude(startLine - 1) != null) return null;
+  for (var end = startLine;;) {
+    var next = hasInclude(end + 1);
+    if (next == null) break;
+    ++end;
+  }
+  return {from: CodeMirror.Pos(startLine, has + 1),
+          to: cm.clipPos(CodeMirror.Pos(end))};
+});
+
+});

+ 59 - 0
global/js/codemirror/fold/comment-fold.js

@@ -0,0 +1,59 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
+  return mode.blockCommentStart && mode.blockCommentEnd;
+}, function(cm, start) {
+  var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
+  if (!startToken || !endToken) return;
+  var line = start.line, lineText = cm.getLine(line);
+
+  var startCh;
+  for (var at = start.ch, pass = 0;;) {
+    var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
+    if (found == -1) {
+      if (pass == 1) return;
+      pass = 1;
+      at = lineText.length;
+      continue;
+    }
+    if (pass == 1 && found < start.ch) return;
+    if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
+        (found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
+         !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
+      startCh = found + startToken.length;
+      break;
+    }
+    at = found - 1;
+  }
+
+  var depth = 1, lastLine = cm.lastLine(), end, endCh;
+  outer: for (var i = line; i <= lastLine; ++i) {
+    var text = cm.getLine(i), pos = i == line ? startCh : 0;
+    for (;;) {
+      var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
+      if (nextOpen < 0) nextOpen = text.length;
+      if (nextClose < 0) nextClose = text.length;
+      pos = Math.min(nextOpen, nextClose);
+      if (pos == text.length) break;
+      if (pos == nextOpen) ++depth;
+      else if (!--depth) { end = i; endCh = pos; break outer; }
+      ++pos;
+    }
+  }
+  if (end == null || line == end && endCh == startCh) return;
+  return {from: CodeMirror.Pos(line, startCh),
+          to: CodeMirror.Pos(end, endCh)};
+});
+
+});

+ 150 - 0
global/js/codemirror/fold/foldcode.js

@@ -0,0 +1,150 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  function doFold(cm, pos, options, force) {
+    if (options && options.call) {
+      var finder = options;
+      options = null;
+    } else {
+      var finder = getOption(cm, options, "rangeFinder");
+    }
+    if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
+    var minSize = getOption(cm, options, "minFoldSize");
+
+    function getRange(allowFolded) {
+      var range = finder(cm, pos);
+      if (!range || range.to.line - range.from.line < minSize) return null;
+      var marks = cm.findMarksAt(range.from);
+      for (var i = 0; i < marks.length; ++i) {
+        if (marks[i].__isFold && force !== "fold") {
+          if (!allowFolded) return null;
+          range.cleared = true;
+          marks[i].clear();
+        }
+      }
+      return range;
+    }
+
+    var range = getRange(true);
+    if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
+      pos = CodeMirror.Pos(pos.line - 1, 0);
+      range = getRange(false);
+    }
+    if (!range || range.cleared || force === "unfold") return;
+
+    var myWidget = makeWidget(cm, options);
+    CodeMirror.on(myWidget, "mousedown", function(e) {
+      myRange.clear();
+      CodeMirror.e_preventDefault(e);
+    });
+    var myRange = cm.markText(range.from, range.to, {
+      replacedWith: myWidget,
+      clearOnEnter: getOption(cm, options, "clearOnEnter"),
+      __isFold: true
+    });
+    myRange.on("clear", function(from, to) {
+      CodeMirror.signal(cm, "unfold", cm, from, to);
+    });
+    CodeMirror.signal(cm, "fold", cm, range.from, range.to);
+  }
+
+  function makeWidget(cm, options) {
+    var widget = getOption(cm, options, "widget");
+    if (typeof widget == "string") {
+      var text = document.createTextNode(widget);
+      widget = document.createElement("span");
+      widget.appendChild(text);
+      widget.className = "CodeMirror-foldmarker";
+    }
+    return widget;
+  }
+
+  // Clumsy backwards-compatible interface
+  CodeMirror.newFoldFunction = function(rangeFinder, widget) {
+    return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
+  };
+
+  // New-style interface
+  CodeMirror.defineExtension("foldCode", function(pos, options, force) {
+    doFold(this, pos, options, force);
+  });
+
+  CodeMirror.defineExtension("isFolded", function(pos) {
+    var marks = this.findMarksAt(pos);
+    for (var i = 0; i < marks.length; ++i)
+      if (marks[i].__isFold) return true;
+  });
+
+  CodeMirror.commands.toggleFold = function(cm) {
+    cm.foldCode(cm.getCursor());
+  };
+  CodeMirror.commands.fold = function(cm) {
+    cm.foldCode(cm.getCursor(), null, "fold");
+  };
+  CodeMirror.commands.unfold = function(cm) {
+    cm.foldCode(cm.getCursor(), null, "unfold");
+  };
+  CodeMirror.commands.foldAll = function(cm) {
+    cm.operation(function() {
+      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
+        cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
+    });
+  };
+  CodeMirror.commands.unfoldAll = function(cm) {
+    cm.operation(function() {
+      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
+        cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
+    });
+  };
+
+  CodeMirror.registerHelper("fold", "combine", function() {
+    var funcs = Array.prototype.slice.call(arguments, 0);
+    return function(cm, start) {
+      for (var i = 0; i < funcs.length; ++i) {
+        var found = funcs[i](cm, start);
+        if (found) return found;
+      }
+    };
+  });
+
+  CodeMirror.registerHelper("fold", "auto", function(cm, start) {
+    var helpers = cm.getHelpers(start, "fold");
+    for (var i = 0; i < helpers.length; i++) {
+      var cur = helpers[i](cm, start);
+      if (cur) return cur;
+    }
+  });
+
+  var defaultOptions = {
+    rangeFinder: CodeMirror.fold.auto,
+    widget: "\u2194",
+    minFoldSize: 0,
+    scanUp: false,
+    clearOnEnter: true
+  };
+
+  CodeMirror.defineOption("foldOptions", null);
+
+  function getOption(cm, options, name) {
+    if (options && options[name] !== undefined)
+      return options[name];
+    var editorOptions = cm.options.foldOptions;
+    if (editorOptions && editorOptions[name] !== undefined)
+      return editorOptions[name];
+    return defaultOptions[name];
+  }
+
+  CodeMirror.defineExtension("foldOption", function(options, name) {
+    return getOption(this, options, name);
+  });
+});

+ 20 - 0
global/js/codemirror/fold/foldgutter.css

@@ -0,0 +1,20 @@
+.CodeMirror-foldmarker {
+  color: blue;
+  text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
+  font-family: arial;
+  line-height: .3;
+  cursor: pointer;
+}
+.CodeMirror-foldgutter {
+  width: .7em;
+}
+.CodeMirror-foldgutter-open,
+.CodeMirror-foldgutter-folded {
+  cursor: pointer;
+}
+.CodeMirror-foldgutter-open:after {
+  content: "\25BE";
+}
+.CodeMirror-foldgutter-folded:after {
+  content: "\25B8";
+}

+ 146 - 0
global/js/codemirror/fold/foldgutter.js

@@ -0,0 +1,146 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"), require("./foldcode"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror", "./foldcode"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
+    if (old && old != CodeMirror.Init) {
+      cm.clearGutter(cm.state.foldGutter.options.gutter);
+      cm.state.foldGutter = null;
+      cm.off("gutterClick", onGutterClick);
+      cm.off("change", onChange);
+      cm.off("viewportChange", onViewportChange);
+      cm.off("fold", onFold);
+      cm.off("unfold", onFold);
+      cm.off("swapDoc", onChange);
+    }
+    if (val) {
+      cm.state.foldGutter = new State(parseOptions(val));
+      updateInViewport(cm);
+      cm.on("gutterClick", onGutterClick);
+      cm.on("change", onChange);
+      cm.on("viewportChange", onViewportChange);
+      cm.on("fold", onFold);
+      cm.on("unfold", onFold);
+      cm.on("swapDoc", onChange);
+    }
+  });
+
+  var Pos = CodeMirror.Pos;
+
+  function State(options) {
+    this.options = options;
+    this.from = this.to = 0;
+  }
+
+  function parseOptions(opts) {
+    if (opts === true) opts = {};
+    if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
+    if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
+    if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
+    return opts;
+  }
+
+  function isFolded(cm, line) {
+    var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
+    for (var i = 0; i < marks.length; ++i)
+      if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
+  }
+
+  function marker(spec) {
+    if (typeof spec == "string") {
+      var elt = document.createElement("div");
+      elt.className = spec + " CodeMirror-guttermarker-subtle";
+      return elt;
+    } else {
+      return spec.cloneNode(true);
+    }
+  }
+
+  function updateFoldInfo(cm, from, to) {
+    var opts = cm.state.foldGutter.options, cur = from;
+    var minSize = cm.foldOption(opts, "minFoldSize");
+    var func = cm.foldOption(opts, "rangeFinder");
+    cm.eachLine(from, to, function(line) {
+      var mark = null;
+      if (isFolded(cm, cur)) {
+        mark = marker(opts.indicatorFolded);
+      } else {
+        var pos = Pos(cur, 0);
+        var range = func && func(cm, pos);
+        if (range && range.to.line - range.from.line >= minSize)
+          mark = marker(opts.indicatorOpen);
+      }
+      cm.setGutterMarker(line, opts.gutter, mark);
+      ++cur;
+    });
+  }
+
+  function updateInViewport(cm) {
+    var vp = cm.getViewport(), state = cm.state.foldGutter;
+    if (!state) return;
+    cm.operation(function() {
+      updateFoldInfo(cm, vp.from, vp.to);
+    });
+    state.from = vp.from; state.to = vp.to;
+  }
+
+  function onGutterClick(cm, line, gutter) {
+    var state = cm.state.foldGutter;
+    if (!state) return;
+    var opts = state.options;
+    if (gutter != opts.gutter) return;
+    var folded = isFolded(cm, line);
+    if (folded) folded.clear();
+    else cm.foldCode(Pos(line, 0), opts.rangeFinder);
+  }
+
+  function onChange(cm) {
+    var state = cm.state.foldGutter;
+    if (!state) return;
+    var opts = state.options;
+    state.from = state.to = 0;
+    clearTimeout(state.changeUpdate);
+    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
+  }
+
+  function onViewportChange(cm) {
+    var state = cm.state.foldGutter;
+    if (!state) return;
+    var opts = state.options;
+    clearTimeout(state.changeUpdate);
+    state.changeUpdate = setTimeout(function() {
+      var vp = cm.getViewport();
+      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
+        updateInViewport(cm);
+      } else {
+        cm.operation(function() {
+          if (vp.from < state.from) {
+            updateFoldInfo(cm, vp.from, state.from);
+            state.from = vp.from;
+          }
+          if (vp.to > state.to) {
+            updateFoldInfo(cm, state.to, vp.to);
+            state.to = vp.to;
+          }
+        });
+      }
+    }, opts.updateViewportTimeSpan || 400);
+  }
+
+  function onFold(cm, from) {
+    var state = cm.state.foldGutter;
+    if (!state) return;
+    var line = from.line;
+    if (line >= state.from && line < state.to)
+      updateFoldInfo(cm, line, line + 1);
+  }
+});

+ 48 - 0
global/js/codemirror/fold/indent-fold.js

@@ -0,0 +1,48 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+function lineIndent(cm, lineNo) {
+  var text = cm.getLine(lineNo)
+  var spaceTo = text.search(/\S/)
+  if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1))))
+    return -1
+  return CodeMirror.countColumn(text, null, cm.getOption("tabSize"))
+}
+
+CodeMirror.registerHelper("fold", "indent", function(cm, start) {
+  var myIndent = lineIndent(cm, start.line)
+  if (myIndent < 0) return
+  var lastLineInFold = null
+
+  // Go through lines until we find a line that definitely doesn't belong in
+  // the block we're folding, or to the end.
+  for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
+    var indent = lineIndent(cm, i)
+    if (indent == -1) {
+    } else if (indent > myIndent) {
+      // Lines with a greater indent are considered part of the block.
+      lastLineInFold = i;
+    } else {
+      // If this line has non-space, non-comment content, and is
+      // indented less or equal to the start line, it is the start of
+      // another block.
+      break;
+    }
+  }
+  if (lastLineInFold) return {
+    from: CodeMirror.Pos(start.line, cm.getLine(start.line).length),
+    to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
+  };
+});
+
+});

+ 49 - 0
global/js/codemirror/fold/markdown-fold.js

@@ -0,0 +1,49 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
+  var maxDepth = 100;
+
+  function isHeader(lineNo) {
+    var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
+    return tokentype && /\bheader\b/.test(tokentype);
+  }
+
+  function headerLevel(lineNo, line, nextLine) {
+    var match = line && line.match(/^#+/);
+    if (match && isHeader(lineNo)) return match[0].length;
+    match = nextLine && nextLine.match(/^[=\-]+\s*$/);
+    if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
+    return maxDepth;
+  }
+
+  var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
+  var level = headerLevel(start.line, firstLine, nextLine);
+  if (level === maxDepth) return undefined;
+
+  var lastLineNo = cm.lastLine();
+  var end = start.line, nextNextLine = cm.getLine(end + 2);
+  while (end < lastLineNo) {
+    if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
+    ++end;
+    nextLine = nextNextLine;
+    nextNextLine = cm.getLine(end + 2);
+  }
+
+  return {
+    from: CodeMirror.Pos(start.line, firstLine.length),
+    to: CodeMirror.Pos(end, cm.getLine(end).length)
+  };
+});
+
+});

+ 182 - 0
global/js/codemirror/fold/xml-fold.js

@@ -0,0 +1,182 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  var Pos = CodeMirror.Pos;
+  function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
+
+  var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
+  var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
+  var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
+
+  function Iter(cm, line, ch, range) {
+    this.line = line; this.ch = ch;
+    this.cm = cm; this.text = cm.getLine(line);
+    this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
+    this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
+  }
+
+  function tagAt(iter, ch) {
+    var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
+    return type && /\btag\b/.test(type);
+  }
+
+  function nextLine(iter) {
+    if (iter.line >= iter.max) return;
+    iter.ch = 0;
+    iter.text = iter.cm.getLine(++iter.line);
+    return true;
+  }
+  function prevLine(iter) {
+    if (iter.line <= iter.min) return;
+    iter.text = iter.cm.getLine(--iter.line);
+    iter.ch = iter.text.length;
+    return true;
+  }
+
+  function toTagEnd(iter) {
+    for (;;) {
+      var gt = iter.text.indexOf(">", iter.ch);
+      if (gt == -1) { if (nextLine(iter)) continue; else return; }
+      if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
+      var lastSlash = iter.text.lastIndexOf("/", gt);
+      var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
+      iter.ch = gt + 1;
+      return selfClose ? "selfClose" : "regular";
+    }
+  }
+  function toTagStart(iter) {
+    for (;;) {
+      var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
+      if (lt == -1) { if (prevLine(iter)) continue; else return; }
+      if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
+      xmlTagStart.lastIndex = lt;
+      iter.ch = lt;
+      var match = xmlTagStart.exec(iter.text);
+      if (match && match.index == lt) return match;
+    }
+  }
+
+  function toNextTag(iter) {
+    for (;;) {
+      xmlTagStart.lastIndex = iter.ch;
+      var found = xmlTagStart.exec(iter.text);
+      if (!found) { if (nextLine(iter)) continue; else return; }
+      if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
+      iter.ch = found.index + found[0].length;
+      return found;
+    }
+  }
+  function toPrevTag(iter) {
+    for (;;) {
+      var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
+      if (gt == -1) { if (prevLine(iter)) continue; else return; }
+      if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
+      var lastSlash = iter.text.lastIndexOf("/", gt);
+      var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
+      iter.ch = gt + 1;
+      return selfClose ? "selfClose" : "regular";
+    }
+  }
+
+  function findMatchingClose(iter, tag) {
+    var stack = [];
+    for (;;) {
+      var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
+      if (!next || !(end = toTagEnd(iter))) return;
+      if (end == "selfClose") continue;
+      if (next[1]) { // closing tag
+        for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
+          stack.length = i;
+          break;
+        }
+        if (i < 0 && (!tag || tag == next[2])) return {
+          tag: next[2],
+          from: Pos(startLine, startCh),
+          to: Pos(iter.line, iter.ch)
+        };
+      } else { // opening tag
+        stack.push(next[2]);
+      }
+    }
+  }
+  function findMatchingOpen(iter, tag) {
+    var stack = [];
+    for (;;) {
+      var prev = toPrevTag(iter);
+      if (!prev) return;
+      if (prev == "selfClose") { toTagStart(iter); continue; }
+      var endLine = iter.line, endCh = iter.ch;
+      var start = toTagStart(iter);
+      if (!start) return;
+      if (start[1]) { // closing tag
+        stack.push(start[2]);
+      } else { // opening tag
+        for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
+          stack.length = i;
+          break;
+        }
+        if (i < 0 && (!tag || tag == start[2])) return {
+          tag: start[2],
+          from: Pos(iter.line, iter.ch),
+          to: Pos(endLine, endCh)
+        };
+      }
+    }
+  }
+
+  CodeMirror.registerHelper("fold", "xml", function(cm, start) {
+    var iter = new Iter(cm, start.line, 0);
+    for (;;) {
+      var openTag = toNextTag(iter), end;
+      if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
+      if (!openTag[1] && end != "selfClose") {
+        var startPos = Pos(iter.line, iter.ch);
+        var endPos = findMatchingClose(iter, openTag[2]);
+        return endPos && {from: startPos, to: endPos.from};
+      }
+    }
+  });
+  CodeMirror.findMatchingTag = function(cm, pos, range) {
+    var iter = new Iter(cm, pos.line, pos.ch, range);
+    if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
+    var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
+    var start = end && toTagStart(iter);
+    if (!end || !start || cmp(iter, pos) > 0) return;
+    var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
+    if (end == "selfClose") return {open: here, close: null, at: "open"};
+
+    if (start[1]) { // closing tag
+      return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
+    } else { // opening tag
+      iter = new Iter(cm, to.line, to.ch, range);
+      return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
+    }
+  };
+
+  CodeMirror.findEnclosingTag = function(cm, pos, range, tag) {
+    var iter = new Iter(cm, pos.line, pos.ch, range);
+    for (;;) {
+      var open = findMatchingOpen(iter, tag);
+      if (!open) break;
+      var forward = new Iter(cm, pos.line, pos.ch, range);
+      var close = findMatchingClose(forward, open.tag);
+      if (close) return {open: open, close: close};
+    }
+  };
+
+  // Used by addon/edit/closetag.js
+  CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
+    var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
+    return findMatchingClose(iter, name);
+  };
+});

+ 743 - 0
global/js/codemirror/javascript.js

@@ -0,0 +1,743 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+// TODO actually recognize syntax of TypeScript constructs
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+function expressionAllowed(stream, state, backUp) {
+  return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
+    (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
+}
+
+CodeMirror.defineMode("javascript", function(config, parserConfig) {
+  var indentUnit = config.indentUnit;
+  var statementIndent = parserConfig.statementIndent;
+  var jsonldMode = parserConfig.jsonld;
+  var jsonMode = parserConfig.json || jsonldMode;
+  var isTS = parserConfig.typescript;
+  var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
+
+  // Tokenizer
+
+  var keywords = function(){
+    function kw(type) {return {type: type, style: "keyword"};}
+    var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
+    var operator = kw("operator"), atom = {type: "atom", style: "atom"};
+
+    var jsKeywords = {
+      "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
+      "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
+      "var": kw("var"), "const": kw("var"), "let": kw("var"),
+      "function": kw("function"), "catch": kw("catch"),
+      "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
+      "in": operator, "typeof": operator, "instanceof": operator,
+      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
+      "this": kw("this"), "class": kw("class"), "super": kw("atom"),
+      "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
+      "await": C, "async": kw("async")
+    };
+
+    // Extend the 'normal' keywords with the TypeScript language extensions
+    if (isTS) {
+      var type = {type: "variable", style: "variable-3"};
+      var tsKeywords = {
+        // object-like things
+        "interface": kw("class"),
+        "implements": C,
+        "namespace": C,
+        "module": kw("module"),
+        "enum": kw("module"),
+
+        // scope modifiers
+        "public": kw("modifier"),
+        "private": kw("modifier"),
+        "protected": kw("modifier"),
+        "abstract": kw("modifier"),
+
+        // operators
+        "as": operator,
+
+        // types
+        "string": type, "number": type, "boolean": type, "any": type
+      };
+
+      for (var attr in tsKeywords) {
+        jsKeywords[attr] = tsKeywords[attr];
+      }
+    }
+
+    return jsKeywords;
+  }();
+
+  var isOperatorChar = /[+\-*&%=<>!?|~^]/;
+  var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
+
+  function readRegexp(stream) {
+    var escaped = false, next, inSet = false;
+    while ((next = stream.next()) != null) {
+      if (!escaped) {
+        if (next == "/" && !inSet) return;
+        if (next == "[") inSet = true;
+        else if (inSet && next == "]") inSet = false;
+      }
+      escaped = !escaped && next == "\\";
+    }
+  }
+
+  // Used as scratch variables to communicate multiple values without
+  // consing up tons of objects.
+  var type, content;
+  function ret(tp, style, cont) {
+    type = tp; content = cont;
+    return style;
+  }
+  function tokenBase(stream, state) {
+    var ch = stream.next();
+    if (ch == '"' || ch == "'") {
+      state.tokenize = tokenString(ch);
+      return state.tokenize(stream, state);
+    } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
+      return ret("number", "number");
+    } else if (ch == "." && stream.match("..")) {
+      return ret("spread", "meta");
+    } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+      return ret(ch);
+    } else if (ch == "=" && stream.eat(">")) {
+      return ret("=>", "operator");
+    } else if (ch == "0" && stream.eat(/x/i)) {
+      stream.eatWhile(/[\da-f]/i);
+      return ret("number", "number");
+    } else if (ch == "0" && stream.eat(/o/i)) {
+      stream.eatWhile(/[0-7]/i);
+      return ret("number", "number");
+    } else if (ch == "0" && stream.eat(/b/i)) {
+      stream.eatWhile(/[01]/i);
+      return ret("number", "number");
+    } else if (/\d/.test(ch)) {
+      stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
+      return ret("number", "number");
+    } else if (ch == "/") {
+      if (stream.eat("*")) {
+        state.tokenize = tokenComment;
+        return tokenComment(stream, state);
+      } else if (stream.eat("/")) {
+        stream.skipToEnd();
+        return ret("comment", "comment");
+      } else if (expressionAllowed(stream, state, 1)) {
+        readRegexp(stream);
+        stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
+        return ret("regexp", "string-2");
+      } else {
+        stream.eatWhile(isOperatorChar);
+        return ret("operator", "operator", stream.current());
+      }
+    } else if (ch == "`") {
+      state.tokenize = tokenQuasi;
+      return tokenQuasi(stream, state);
+    } else if (ch == "#") {
+      stream.skipToEnd();
+      return ret("error", "error");
+    } else if (isOperatorChar.test(ch)) {
+      stream.eatWhile(isOperatorChar);
+      return ret("operator", "operator", stream.current());
+    } else if (wordRE.test(ch)) {
+      stream.eatWhile(wordRE);
+      var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
+      return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
+                     ret("variable", "variable", word);
+    }
+  }
+
+  function tokenString(quote) {
+    return function(stream, state) {
+      var escaped = false, next;
+      if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
+        state.tokenize = tokenBase;
+        return ret("jsonld-keyword", "meta");
+      }
+      while ((next = stream.next()) != null) {
+        if (next == quote && !escaped) break;
+        escaped = !escaped && next == "\\";
+      }
+      if (!escaped) state.tokenize = tokenBase;
+      return ret("string", "string");
+    };
+  }
+
+  function tokenComment(stream, state) {
+    var maybeEnd = false, ch;
+    while (ch = stream.next()) {
+      if (ch == "/" && maybeEnd) {
+        state.tokenize = tokenBase;
+        break;
+      }
+      maybeEnd = (ch == "*");
+    }
+    return ret("comment", "comment");
+  }
+
+  function tokenQuasi(stream, state) {
+    var escaped = false, next;
+    while ((next = stream.next()) != null) {
+      if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
+        state.tokenize = tokenBase;
+        break;
+      }
+      escaped = !escaped && next == "\\";
+    }
+    return ret("quasi", "string-2", stream.current());
+  }
+
+  var brackets = "([{}])";
+  // This is a crude lookahead trick to try and notice that we're
+  // parsing the argument patterns for a fat-arrow function before we
+  // actually hit the arrow token. It only works if the arrow is on
+  // the same line as the arguments and there's no strange noise
+  // (comments) in between. Fallback is to only notice when we hit the
+  // arrow, and not declare the arguments as locals for the arrow
+  // body.
+  function findFatArrow(stream, state) {
+    if (state.fatArrowAt) state.fatArrowAt = null;
+    var arrow = stream.string.indexOf("=>", stream.start);
+    if (arrow < 0) return;
+
+    var depth = 0, sawSomething = false;
+    for (var pos = arrow - 1; pos >= 0; --pos) {
+      var ch = stream.string.charAt(pos);
+      var bracket = brackets.indexOf(ch);
+      if (bracket >= 0 && bracket < 3) {
+        if (!depth) { ++pos; break; }
+        if (--depth == 0) break;
+      } else if (bracket >= 3 && bracket < 6) {
+        ++depth;
+      } else if (wordRE.test(ch)) {
+        sawSomething = true;
+      } else if (/["'\/]/.test(ch)) {
+        return;
+      } else if (sawSomething && !depth) {
+        ++pos;
+        break;
+      }
+    }
+    if (sawSomething && !depth) state.fatArrowAt = pos;
+  }
+
+  // Parser
+
+  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
+
+  function JSLexical(indented, column, type, align, prev, info) {
+    this.indented = indented;
+    this.column = column;
+    this.type = type;
+    this.prev = prev;
+    this.info = info;
+    if (align != null) this.align = align;
+  }
+
+  function inScope(state, varname) {
+    for (var v = state.localVars; v; v = v.next)
+      if (v.name == varname) return true;
+    for (var cx = state.context; cx; cx = cx.prev) {
+      for (var v = cx.vars; v; v = v.next)
+        if (v.name == varname) return true;
+    }
+  }
+
+  function parseJS(state, style, type, content, stream) {
+    var cc = state.cc;
+    // Communicate our context to the combinators.
+    // (Less wasteful than consing up a hundred closures on every call.)
+    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
+
+    if (!state.lexical.hasOwnProperty("align"))
+      state.lexical.align = true;
+
+    while(true) {
+      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
+      if (combinator(type, content)) {
+        while(cc.length && cc[cc.length - 1].lex)
+          cc.pop()();
+        if (cx.marked) return cx.marked;
+        if (type == "variable" && inScope(state, content)) return "variable-2";
+        return style;
+      }
+    }
+  }
+
+  // Combinator utils
+
+  var cx = {state: null, column: null, marked: null, cc: null};
+  function pass() {
+    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
+  }
+  function cont() {
+    pass.apply(null, arguments);
+    return true;
+  }
+  function register(varname) {
+    function inList(list) {
+      for (var v = list; v; v = v.next)
+        if (v.name == varname) return true;
+      return false;
+    }
+    var state = cx.state;
+    cx.marked = "def";
+    if (state.context) {
+      if (inList(state.localVars)) return;
+      state.localVars = {name: varname, next: state.localVars};
+    } else {
+      if (inList(state.globalVars)) return;
+      if (parserConfig.globalVars)
+        state.globalVars = {name: varname, next: state.globalVars};
+    }
+  }
+
+  // Combinators
+
+  var defaultVars = {name: "this", next: {name: "arguments"}};
+  function pushcontext() {
+    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
+    cx.state.localVars = defaultVars;
+  }
+  function popcontext() {
+    cx.state.localVars = cx.state.context.vars;
+    cx.state.context = cx.state.context.prev;
+  }
+  function pushlex(type, info) {
+    var result = function() {
+      var state = cx.state, indent = state.indented;
+      if (state.lexical.type == "stat") indent = state.lexical.indented;
+      else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
+        indent = outer.indented;
+      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
+    };
+    result.lex = true;
+    return result;
+  }
+  function poplex() {
+    var state = cx.state;
+    if (state.lexical.prev) {
+      if (state.lexical.type == ")")
+        state.indented = state.lexical.indented;
+      state.lexical = state.lexical.prev;
+    }
+  }
+  poplex.lex = true;
+
+  function expect(wanted) {
+    function exp(type) {
+      if (type == wanted) return cont();
+      else if (wanted == ";") return pass();
+      else return cont(exp);
+    };
+    return exp;
+  }
+
+  function statement(type, value) {
+    if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
+    if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
+    if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
+    if (type == "{") return cont(pushlex("}"), block, poplex);
+    if (type == ";") return cont();
+    if (type == "if") {
+      if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
+        cx.state.cc.pop()();
+      return cont(pushlex("form"), expression, statement, poplex, maybeelse);
+    }
+    if (type == "function") return cont(functiondef);
+    if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
+    if (type == "variable") return cont(pushlex("stat"), maybelabel);
+    if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
+                                      block, poplex, poplex);
+    if (type == "case") return cont(expression, expect(":"));
+    if (type == "default") return cont(expect(":"));
+    if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
+                                     statement, poplex, popcontext);
+    if (type == "class") return cont(pushlex("form"), className, poplex);
+    if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
+    if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
+    if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
+    if (type == "async") return cont(statement)
+    return pass(pushlex("stat"), expression, expect(";"), poplex);
+  }
+  function expression(type) {
+    return expressionInner(type, false);
+  }
+  function expressionNoComma(type) {
+    return expressionInner(type, true);
+  }
+  function expressionInner(type, noComma) {
+    if (cx.state.fatArrowAt == cx.stream.start) {
+      var body = noComma ? arrowBodyNoComma : arrowBody;
+      if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
+      else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
+    }
+
+    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
+    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
+    if (type == "function") return cont(functiondef, maybeop);
+    if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
+    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
+    if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
+    if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
+    if (type == "{") return contCommasep(objprop, "}", null, maybeop);
+    if (type == "quasi") return pass(quasi, maybeop);
+    if (type == "new") return cont(maybeTarget(noComma));
+    return cont();
+  }
+  function maybeexpression(type) {
+    if (type.match(/[;\}\)\],]/)) return pass();
+    return pass(expression);
+  }
+  function maybeexpressionNoComma(type) {
+    if (type.match(/[;\}\)\],]/)) return pass();
+    return pass(expressionNoComma);
+  }
+
+  function maybeoperatorComma(type, value) {
+    if (type == ",") return cont(expression);
+    return maybeoperatorNoComma(type, value, false);
+  }
+  function maybeoperatorNoComma(type, value, noComma) {
+    var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
+    var expr = noComma == false ? expression : expressionNoComma;
+    if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
+    if (type == "operator") {
+      if (/\+\+|--/.test(value)) return cont(me);
+      if (value == "?") return cont(expression, expect(":"), expr);
+      return cont(expr);
+    }
+    if (type == "quasi") { return pass(quasi, me); }
+    if (type == ";") return;
+    if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
+    if (type == ".") return cont(property, me);
+    if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
+  }
+  function quasi(type, value) {
+    if (type != "quasi") return pass();
+    if (value.slice(value.length - 2) != "${") return cont(quasi);
+    return cont(expression, continueQuasi);
+  }
+  function continueQuasi(type) {
+    if (type == "}") {
+      cx.marked = "string-2";
+      cx.state.tokenize = tokenQuasi;
+      return cont(quasi);
+    }
+  }
+  function arrowBody(type) {
+    findFatArrow(cx.stream, cx.state);
+    return pass(type == "{" ? statement : expression);
+  }
+  function arrowBodyNoComma(type) {
+    findFatArrow(cx.stream, cx.state);
+    return pass(type == "{" ? statement : expressionNoComma);
+  }
+  function maybeTarget(noComma) {
+    return function(type) {
+      if (type == ".") return cont(noComma ? targetNoComma : target);
+      else return pass(noComma ? expressionNoComma : expression);
+    };
+  }
+  function target(_, value) {
+    if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
+  }
+  function targetNoComma(_, value) {
+    if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
+  }
+  function maybelabel(type) {
+    if (type == ":") return cont(poplex, statement);
+    return pass(maybeoperatorComma, expect(";"), poplex);
+  }
+  function property(type) {
+    if (type == "variable") {cx.marked = "property"; return cont();}
+  }
+  function objprop(type, value) {
+    if (type == "async") return cont(objprop);
+    if (type == "variable" || cx.style == "keyword") {
+      cx.marked = "property";
+      if (value == "get" || value == "set") return cont(getterSetter);
+      return cont(afterprop);
+    } else if (type == "number" || type == "string") {
+      cx.marked = jsonldMode ? "property" : (cx.style + " property");
+      return cont(afterprop);
+    } else if (type == "jsonld-keyword") {
+      return cont(afterprop);
+    } else if (type == "modifier") {
+      return cont(objprop)
+    } else if (type == "[") {
+      return cont(expression, expect("]"), afterprop);
+    } else if (type == "spread") {
+      return cont(expression);
+    }
+  }
+  function getterSetter(type) {
+    if (type != "variable") return pass(afterprop);
+    cx.marked = "property";
+    return cont(functiondef);
+  }
+  function afterprop(type) {
+    if (type == ":") return cont(expressionNoComma);
+    if (type == "(") return pass(functiondef);
+  }
+  function commasep(what, end) {
+    function proceed(type, value) {
+      if (type == ",") {
+        var lex = cx.state.lexical;
+        if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
+        return cont(function(type, value) {
+          if (type == end || value == end) return pass()
+          return pass(what)
+        }, proceed);
+      }
+      if (type == end || value == end) return cont();
+      return cont(expect(end));
+    }
+    return function(type, value) {
+      if (type == end || value == end) return cont();
+      return pass(what, proceed);
+    };
+  }
+  function contCommasep(what, end, info) {
+    for (var i = 3; i < arguments.length; i++)
+      cx.cc.push(arguments[i]);
+    return cont(pushlex(end, info), commasep(what, end), poplex);
+  }
+  function block(type) {
+    if (type == "}") return cont();
+    return pass(statement, block);
+  }
+  function maybetype(type) {
+    if (isTS && type == ":") return cont(typeexpr);
+  }
+  function maybedefault(_, value) {
+    if (value == "=") return cont(expressionNoComma);
+  }
+  function typeexpr(type) {
+    if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);}
+  }
+  function afterType(type, value) {
+    if (value == "<") return cont(commasep(typeexpr, ">"), afterType)
+    if (type == "[") return cont(expect("]"), afterType)
+  }
+  function vardef() {
+    return pass(pattern, maybetype, maybeAssign, vardefCont);
+  }
+  function pattern(type, value) {
+    if (type == "modifier") return cont(pattern)
+    if (type == "variable") { register(value); return cont(); }
+    if (type == "spread") return cont(pattern);
+    if (type == "[") return contCommasep(pattern, "]");
+    if (type == "{") return contCommasep(proppattern, "}");
+  }
+  function proppattern(type, value) {
+    if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
+      register(value);
+      return cont(maybeAssign);
+    }
+    if (type == "variable") cx.marked = "property";
+    if (type == "spread") return cont(pattern);
+    if (type == "}") return pass();
+    return cont(expect(":"), pattern, maybeAssign);
+  }
+  function maybeAssign(_type, value) {
+    if (value == "=") return cont(expressionNoComma);
+  }
+  function vardefCont(type) {
+    if (type == ",") return cont(vardef);
+  }
+  function maybeelse(type, value) {
+    if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
+  }
+  function forspec(type) {
+    if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
+  }
+  function forspec1(type) {
+    if (type == "var") return cont(vardef, expect(";"), forspec2);
+    if (type == ";") return cont(forspec2);
+    if (type == "variable") return cont(formaybeinof);
+    return pass(expression, expect(";"), forspec2);
+  }
+  function formaybeinof(_type, value) {
+    if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
+    return cont(maybeoperatorComma, forspec2);
+  }
+  function forspec2(type, value) {
+    if (type == ";") return cont(forspec3);
+    if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
+    return pass(expression, expect(";"), forspec3);
+  }
+  function forspec3(type) {
+    if (type != ")") cont(expression);
+  }
+  function functiondef(type, value) {
+    if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
+    if (type == "variable") {register(value); return cont(functiondef);}
+    if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
+  }
+  function funarg(type) {
+    if (type == "spread") return cont(funarg);
+    return pass(pattern, maybetype, maybedefault);
+  }
+  function className(type, value) {
+    if (type == "variable") {register(value); return cont(classNameAfter);}
+  }
+  function classNameAfter(type, value) {
+    if (value == "extends") return cont(expression, classNameAfter);
+    if (type == "{") return cont(pushlex("}"), classBody, poplex);
+  }
+  function classBody(type, value) {
+    if (type == "variable" || cx.style == "keyword") {
+      if (value == "static") {
+        cx.marked = "keyword";
+        return cont(classBody);
+      }
+      cx.marked = "property";
+      if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
+      return cont(functiondef, classBody);
+    }
+    if (value == "*") {
+      cx.marked = "keyword";
+      return cont(classBody);
+    }
+    if (type == ";") return cont(classBody);
+    if (type == "}") return cont();
+  }
+  function classGetterSetter(type) {
+    if (type != "variable") return pass();
+    cx.marked = "property";
+    return cont();
+  }
+  function afterExport(_type, value) {
+    if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
+    if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
+    return pass(statement);
+  }
+  function afterImport(type) {
+    if (type == "string") return cont();
+    return pass(importSpec, maybeFrom);
+  }
+  function importSpec(type, value) {
+    if (type == "{") return contCommasep(importSpec, "}");
+    if (type == "variable") register(value);
+    if (value == "*") cx.marked = "keyword";
+    return cont(maybeAs);
+  }
+  function maybeAs(_type, value) {
+    if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
+  }
+  function maybeFrom(_type, value) {
+    if (value == "from") { cx.marked = "keyword"; return cont(expression); }
+  }
+  function arrayLiteral(type) {
+    if (type == "]") return cont();
+    return pass(expressionNoComma, commasep(expressionNoComma, "]"));
+  }
+
+  function isContinuedStatement(state, textAfter) {
+    return state.lastType == "operator" || state.lastType == "," ||
+      isOperatorChar.test(textAfter.charAt(0)) ||
+      /[,.]/.test(textAfter.charAt(0));
+  }
+
+  // Interface
+
+  return {
+    startState: function(basecolumn) {
+      var state = {
+        tokenize: tokenBase,
+        lastType: "sof",
+        cc: [],
+        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
+        localVars: parserConfig.localVars,
+        context: parserConfig.localVars && {vars: parserConfig.localVars},
+        indented: basecolumn || 0
+      };
+      if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
+        state.globalVars = parserConfig.globalVars;
+      return state;
+    },
+
+    token: function(stream, state) {
+      if (stream.sol()) {
+        if (!state.lexical.hasOwnProperty("align"))
+          state.lexical.align = false;
+        state.indented = stream.indentation();
+        findFatArrow(stream, state);
+      }
+      if (state.tokenize != tokenComment && stream.eatSpace()) return null;
+      var style = state.tokenize(stream, state);
+      if (type == "comment") return style;
+      state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
+      return parseJS(state, style, type, content, stream);
+    },
+
+    indent: function(state, textAfter) {
+      if (state.tokenize == tokenComment) return CodeMirror.Pass;
+      if (state.tokenize != tokenBase) return 0;
+      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
+      // Kludge to prevent 'maybelse' from blocking lexical scope pops
+      if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
+        var c = state.cc[i];
+        if (c == poplex) lexical = lexical.prev;
+        else if (c != maybeelse) break;
+      }
+      if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
+      if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
+        lexical = lexical.prev;
+      var type = lexical.type, closing = firstChar == type;
+
+      if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
+      else if (type == "form" && firstChar == "{") return lexical.indented;
+      else if (type == "form") return lexical.indented + indentUnit;
+      else if (type == "stat")
+        return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
+      else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
+        return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
+      else if (lexical.align) return lexical.column + (closing ? 0 : 1);
+      else return lexical.indented + (closing ? 0 : indentUnit);
+    },
+
+    electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
+    blockCommentStart: jsonMode ? null : "/*",
+    blockCommentEnd: jsonMode ? null : "*/",
+    lineComment: jsonMode ? null : "//",
+    fold: "brace",
+    closeBrackets: "()[]{}''\"\"``",
+
+    helperType: jsonMode ? "json" : "javascript",
+    jsonldMode: jsonldMode,
+    jsonMode: jsonMode,
+
+    expressionAllowed: expressionAllowed,
+    skipExpression: function(state) {
+      var top = state.cc[state.cc.length - 1]
+      if (top == expression || top == expressionNoComma) state.cc.pop()
+    }
+  };
+});
+
+CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
+
+CodeMirror.defineMIME("text/javascript", "javascript");
+CodeMirror.defineMIME("text/ecmascript", "javascript");
+CodeMirror.defineMIME("application/javascript", "javascript");
+CodeMirror.defineMIME("application/x-javascript", "javascript");
+CodeMirror.defineMIME("application/ecmascript", "javascript");
+CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
+CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
+CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
+CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
+CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
+
+});

+ 394 - 0
global/js/codemirror/xml.js

@@ -0,0 +1,394 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+var htmlConfig = {
+  autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
+                    'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
+                    'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
+                    'track': true, 'wbr': true, 'menuitem': true},
+  implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
+                     'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
+                     'th': true, 'tr': true},
+  contextGrabbers: {
+    'dd': {'dd': true, 'dt': true},
+    'dt': {'dd': true, 'dt': true},
+    'li': {'li': true},
+    'option': {'option': true, 'optgroup': true},
+    'optgroup': {'optgroup': true},
+    'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
+          'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
+          'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
+          'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
+          'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
+    'rp': {'rp': true, 'rt': true},
+    'rt': {'rp': true, 'rt': true},
+    'tbody': {'tbody': true, 'tfoot': true},
+    'td': {'td': true, 'th': true},
+    'tfoot': {'tbody': true},
+    'th': {'td': true, 'th': true},
+    'thead': {'tbody': true, 'tfoot': true},
+    'tr': {'tr': true}
+  },
+  doNotIndent: {"pre": true},
+  allowUnquoted: true,
+  allowMissing: true,
+  caseFold: true
+}
+
+var xmlConfig = {
+  autoSelfClosers: {},
+  implicitlyClosed: {},
+  contextGrabbers: {},
+  doNotIndent: {},
+  allowUnquoted: false,
+  allowMissing: false,
+  caseFold: false
+}
+
+CodeMirror.defineMode("xml", function(editorConf, config_) {
+  var indentUnit = editorConf.indentUnit
+  var config = {}
+  var defaults = config_.htmlMode ? htmlConfig : xmlConfig
+  for (var prop in defaults) config[prop] = defaults[prop]
+  for (var prop in config_) config[prop] = config_[prop]
+
+  // Return variables for tokenizers
+  var type, setStyle;
+
+  function inText(stream, state) {
+    function chain(parser) {
+      state.tokenize = parser;
+      return parser(stream, state);
+    }
+
+    var ch = stream.next();
+    if (ch == "<") {
+      if (stream.eat("!")) {
+        if (stream.eat("[")) {
+          if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
+          else return null;
+        } else if (stream.match("--")) {
+          return chain(inBlock("comment", "-->"));
+        } else if (stream.match("DOCTYPE", true, true)) {
+          stream.eatWhile(/[\w\._\-]/);
+          return chain(doctype(1));
+        } else {
+          return null;
+        }
+      } else if (stream.eat("?")) {
+        stream.eatWhile(/[\w\._\-]/);
+        state.tokenize = inBlock("meta", "?>");
+        return "meta";
+      } else {
+        type = stream.eat("/") ? "closeTag" : "openTag";
+        state.tokenize = inTag;
+        return "tag bracket";
+      }
+    } else if (ch == "&") {
+      var ok;
+      if (stream.eat("#")) {
+        if (stream.eat("x")) {
+          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
+        } else {
+          ok = stream.eatWhile(/[\d]/) && stream.eat(";");
+        }
+      } else {
+        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
+      }
+      return ok ? "atom" : "error";
+    } else {
+      stream.eatWhile(/[^&<]/);
+      return null;
+    }
+  }
+  inText.isInText = true;
+
+  function inTag(stream, state) {
+    var ch = stream.next();
+    if (ch == ">" || (ch == "/" && stream.eat(">"))) {
+      state.tokenize = inText;
+      type = ch == ">" ? "endTag" : "selfcloseTag";
+      return "tag bracket";
+    } else if (ch == "=") {
+      type = "equals";
+      return null;
+    } else if (ch == "<") {
+      state.tokenize = inText;
+      state.state = baseState;
+      state.tagName = state.tagStart = null;
+      var next = state.tokenize(stream, state);
+      return next ? next + " tag error" : "tag error";
+    } else if (/[\'\"]/.test(ch)) {
+      state.tokenize = inAttribute(ch);
+      state.stringStartCol = stream.column();
+      return state.tokenize(stream, state);
+    } else {
+      stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
+      return "word";
+    }
+  }
+
+  function inAttribute(quote) {
+    var closure = function(stream, state) {
+      while (!stream.eol()) {
+        if (stream.next() == quote) {
+          state.tokenize = inTag;
+          break;
+        }
+      }
+      return "string";
+    };
+    closure.isInAttribute = true;
+    return closure;
+  }
+
+  function inBlock(style, terminator) {
+    return function(stream, state) {
+      while (!stream.eol()) {
+        if (stream.match(terminator)) {
+          state.tokenize = inText;
+          break;
+        }
+        stream.next();
+      }
+      return style;
+    };
+  }
+  function doctype(depth) {
+    return function(stream, state) {
+      var ch;
+      while ((ch = stream.next()) != null) {
+        if (ch == "<") {
+          state.tokenize = doctype(depth + 1);
+          return state.tokenize(stream, state);
+        } else if (ch == ">") {
+          if (depth == 1) {
+            state.tokenize = inText;
+            break;
+          } else {
+            state.tokenize = doctype(depth - 1);
+            return state.tokenize(stream, state);
+          }
+        }
+      }
+      return "meta";
+    };
+  }
+
+  function Context(state, tagName, startOfLine) {
+    this.prev = state.context;
+    this.tagName = tagName;
+    this.indent = state.indented;
+    this.startOfLine = startOfLine;
+    if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
+      this.noIndent = true;
+  }
+  function popContext(state) {
+    if (state.context) state.context = state.context.prev;
+  }
+  function maybePopContext(state, nextTagName) {
+    var parentTagName;
+    while (true) {
+      if (!state.context) {
+        return;
+      }
+      parentTagName = state.context.tagName;
+      if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
+          !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
+        return;
+      }
+      popContext(state);
+    }
+  }
+
+  function baseState(type, stream, state) {
+    if (type == "openTag") {
+      state.tagStart = stream.column();
+      return tagNameState;
+    } else if (type == "closeTag") {
+      return closeTagNameState;
+    } else {
+      return baseState;
+    }
+  }
+  function tagNameState(type, stream, state) {
+    if (type == "word") {
+      state.tagName = stream.current();
+      setStyle = "tag";
+      return attrState;
+    } else {
+      setStyle = "error";
+      return tagNameState;
+    }
+  }
+  function closeTagNameState(type, stream, state) {
+    if (type == "word") {
+      var tagName = stream.current();
+      if (state.context && state.context.tagName != tagName &&
+          config.implicitlyClosed.hasOwnProperty(state.context.tagName))
+        popContext(state);
+      if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
+        setStyle = "tag";
+        return closeState;
+      } else {
+        setStyle = "tag error";
+        return closeStateErr;
+      }
+    } else {
+      setStyle = "error";
+      return closeStateErr;
+    }
+  }
+
+  function closeState(type, _stream, state) {
+    if (type != "endTag") {
+      setStyle = "error";
+      return closeState;
+    }
+    popContext(state);
+    return baseState;
+  }
+  function closeStateErr(type, stream, state) {
+    setStyle = "error";
+    return closeState(type, stream, state);
+  }
+
+  function attrState(type, _stream, state) {
+    if (type == "word") {
+      setStyle = "attribute";
+      return attrEqState;
+    } else if (type == "endTag" || type == "selfcloseTag") {
+      var tagName = state.tagName, tagStart = state.tagStart;
+      state.tagName = state.tagStart = null;
+      if (type == "selfcloseTag" ||
+          config.autoSelfClosers.hasOwnProperty(tagName)) {
+        maybePopContext(state, tagName);
+      } else {
+        maybePopContext(state, tagName);
+        state.context = new Context(state, tagName, tagStart == state.indented);
+      }
+      return baseState;
+    }
+    setStyle = "error";
+    return attrState;
+  }
+  function attrEqState(type, stream, state) {
+    if (type == "equals") return attrValueState;
+    if (!config.allowMissing) setStyle = "error";
+    return attrState(type, stream, state);
+  }
+  function attrValueState(type, stream, state) {
+    if (type == "string") return attrContinuedState;
+    if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
+    setStyle = "error";
+    return attrState(type, stream, state);
+  }
+  function attrContinuedState(type, stream, state) {
+    if (type == "string") return attrContinuedState;
+    return attrState(type, stream, state);
+  }
+
+  return {
+    startState: function(baseIndent) {
+      var state = {tokenize: inText,
+                   state: baseState,
+                   indented: baseIndent || 0,
+                   tagName: null, tagStart: null,
+                   context: null}
+      if (baseIndent != null) state.baseIndent = baseIndent
+      return state
+    },
+
+    token: function(stream, state) {
+      if (!state.tagName && stream.sol())
+        state.indented = stream.indentation();
+
+      if (stream.eatSpace()) return null;
+      type = null;
+      var style = state.tokenize(stream, state);
+      if ((style || type) && style != "comment") {
+        setStyle = null;
+        state.state = state.state(type || style, stream, state);
+        if (setStyle)
+          style = setStyle == "error" ? style + " error" : setStyle;
+      }
+      return style;
+    },
+
+    indent: function(state, textAfter, fullLine) {
+      var context = state.context;
+      // Indent multi-line strings (e.g. css).
+      if (state.tokenize.isInAttribute) {
+        if (state.tagStart == state.indented)
+          return state.stringStartCol + 1;
+        else
+          return state.indented + indentUnit;
+      }
+      if (context && context.noIndent) return CodeMirror.Pass;
+      if (state.tokenize != inTag && state.tokenize != inText)
+        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
+      // Indent the starts of attribute names.
+      if (state.tagName) {
+        if (config.multilineTagIndentPastTag !== false)
+          return state.tagStart + state.tagName.length + 2;
+        else
+          return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
+      }
+      if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
+      var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
+      if (tagAfter && tagAfter[1]) { // Closing tag spotted
+        while (context) {
+          if (context.tagName == tagAfter[2]) {
+            context = context.prev;
+            break;
+          } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
+            context = context.prev;
+          } else {
+            break;
+          }
+        }
+      } else if (tagAfter) { // Opening tag spotted
+        while (context) {
+          var grabbers = config.contextGrabbers[context.tagName];
+          if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
+            context = context.prev;
+          else
+            break;
+        }
+      }
+      while (context && context.prev && !context.startOfLine)
+        context = context.prev;
+      if (context) return context.indent + indentUnit;
+      else return state.baseIndent || 0;
+    },
+
+    electricInput: /<\/[\s\w:]+>$/,
+    blockCommentStart: "<!--",
+    blockCommentEnd: "-->",
+
+    configuration: config.htmlMode ? "html" : "xml",
+    helperType: config.htmlMode ? "html" : "xml",
+
+    skipAttribute: function(state) {
+      if (state.state == attrValueState)
+        state.state = attrState
+    }
+  };
+});
+
+CodeMirror.defineMIME("text/xml", "xml");
+CodeMirror.defineMIME("application/xml", "xml");
+if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
+  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
+
+});

+ 28 - 0
global/js/global.js

@@ -0,0 +1,28 @@
+$(function(){
+/*侧滑*/
+$(".opensidebar").click(function(){
+    $(".wrapSlide").animate({width:"800"}).addClass("open");
+});
+$("body").click(function(event){
+        var e = event || window.event; //浏览器兼容性
+        if(!$(event.target).is('a')) {
+            var elem = event.target || e.srcElement;
+            while (elem) { //循环判断至跟节点,防止点击的是div子元素
+                if (elem.className == "opensidebar" || elem.className == 'wrapSlide open') {
+                    return false;
+                }
+                elem = elem.parentNode;
+            }
+            $(".wrapSlide").animate({width:"0"}).removeClass("open")// 关闭处理
+        }
+
+    });
+/*侧滑*/
+/*工具提示*/
+$('*[data-toggle=tooltip]').mouseover(function() { 
+ $(this).tooltip('show'); 
+  });
+/*工具提示*/
+});
+
+

File diff suppressed because it is too large
+ 5 - 0
global/js/jquery-1.9.1.min.js


+ 13 - 0
global/js/npm.js

@@ -0,0 +1,13 @@
+// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
+require('../../js/transition.js')
+require('../../js/alert.js')
+require('../../js/button.js')
+require('../../js/carousel.js')
+require('../../js/collapse.js')
+require('../../js/dropdown.js')
+require('../../js/modal.js')
+require('../../js/tooltip.js')
+require('../../js/popover.js')
+require('../../js/scrollspy.js')
+require('../../js/tab.js')
+require('../../js/affix.js')

+ 33 - 0
index.php

@@ -0,0 +1,33 @@
+<?php
+
+include './protected/config/common.conf.php';
+include './protected/config/routes.conf.php';
+include './protected/config/db.conf.php';
+#Just include this for production mode
+//include $config['BASE_PATH'].'deployment/deploy.php';
+include $config['BASE_PATH'] . 'Doo.php';
+include $config['BASE_PATH'] . 'app/DooConfig.php';
+
+# Uncomment for auto loading the framework classes.
+spl_autoload_register('Doo::autoload');
+
+Doo::conf()->set($config);
+
+# remove this if you wish to see the normal PHP error view.
+//include $config['BASE_PATH'] . 'diagnostic/debug.php';
+
+# database usage
+//Doo::useDbReplicate();	#for db replication master-slave usage
+//Doo::db()->setMap($dbmap);
+Doo::db()->setDb($dbconfig, $config['APP_MODE']);
+//Doo::db()->sql_tracking = true;	#for debugging/profiling purpose
+
+Doo::app()->route = $route;
+
+# Uncomment for DB profiling
+//Doo::logger()->beginDbProfile('doowebsite');
+Doo::app()->run();
+//Doo::logger()->endDbProfile('doowebsite');
+//Doo::logger()->rotateFile(20);
+//Doo::logger()->writeDbProfiles();
+?>

+ 291 - 0
jlzfver.sql

@@ -0,0 +1,291 @@
+-- phpMyAdmin SQL Dump
+-- version 4.7.0
+-- https://www.phpmyadmin.net/
+--
+-- Host: 10.252.250.130
+-- Generation Time: 2017-08-03 09:46:05
+-- 服务器版本: 10.0.17-MariaDB-1~trusty-log
+-- PHP Version: 7.0.15-0ubuntu0.16.04.4
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+SET AUTOCOMMIT = 0;
+START TRANSACTION;
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+
+--
+-- Database: `jlzfver`
+--
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `fc_category`
+--
+
+CREATE TABLE `fc_category` (
+  `cateid` int(11) UNSIGNED NOT NULL,
+  `catename` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '类别名',
+  `parentid` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '父类id,默认为0,都是父类',
+  `itemid` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '项目id,默认为0,无项目'
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='类别表';
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `fc_item`
+--
+
+CREATE TABLE `fc_item` (
+  `itemid` int(11) UNSIGNED NOT NULL,
+  `itemname` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
+  `code` varchar(10) COLLATE utf8_unicode_ci NOT NULL COMMENT '项目领取码'
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='项目表';
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `fc_log`
+--
+
+CREATE TABLE `fc_log` (
+  `id` int(11) UNSIGNED NOT NULL,
+  `userid` int(11) UNSIGNED NOT NULL,
+  `reportid` int(11) UNSIGNED NOT NULL,
+  `verid` int(11) UNSIGNED NOT NULL,
+  `content` text COLLATE utf8_unicode_ci NOT NULL COMMENT '操作内容',
+  `addtime` int(15) UNSIGNED NOT NULL COMMENT '添加时间'
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='用户操作记录表';
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `fc_report`
+--
+
+CREATE TABLE `fc_report` (
+  `reportid` int(11) UNSIGNED NOT NULL,
+  `reportname` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
+  `areacate` tinyint(4) UNSIGNED NOT NULL DEFAULT '3' COMMENT '适用地区',
+  `itemid` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '所属项目,默认为0,通用',
+  `cateid` int(11) UNSIGNED NOT NULL COMMENT '所属类别',
+  `parentid` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '所属类别父类,默认为0,都为父类',
+  `userid` int(11) UNSIGNED NOT NULL COMMENT '谁创建本报表',
+  `edittime` int(15) UNSIGNED NOT NULL COMMENT '最新更新时间'
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='报表';
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `fc_user`
+--
+
+CREATE TABLE `fc_user` (
+  `id` int(11) UNSIGNED NOT NULL,
+  `username` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
+  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='管理员用户表';
+
+--
+-- 转存表中的数据 `fc_user`
+--
+
+INSERT INTO `fc_user` (`id`, `username`, `password`) VALUES
+(1, '纵横知道', '$2a$08$X2qbaqmSATLNPmrjVoV9AuYFo2i28omEBWsHc16eK0R1VNtTzF/C6'),
+(2, '纵横', '$2a$08$/s0ayZBQGcOrOwSJ8RIyUu62RL0dnwzn4BGcax53MN6wd4Tlz9302');
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `fc_version`
+--
+
+CREATE TABLE `fc_version` (
+  `verid` int(11) UNSIGNED NOT NULL,
+  `reportid` int(11) UNSIGNED NOT NULL COMMENT '报表id',
+  `vername` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '版本名称,以时间为格式',
+  `content` text COLLATE utf8_unicode_ci NOT NULL COMMENT '内容',
+  `xmlheader` text COLLATE utf8_unicode_ci NOT NULL COMMENT 'xml头文件代码',
+  `xmlbody` text COLLATE utf8_unicode_ci NOT NULL COMMENT 'xml报表内容',
+  `status` tinyint(2) UNSIGNED NOT NULL COMMENT '状态,0为未发布,1为草稿,2为发布',
+  `addtime` int(15) UNSIGNED NOT NULL COMMENT '版本添加时间',
+  `edittime` int(15) UNSIGNED NOT NULL COMMENT '最新编辑时间'
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='版本表';
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `sfu_hosts`
+--
+
+CREATE TABLE `sfu_hosts` (
+  `id` int(10) UNSIGNED NOT NULL,
+  `serverid` mediumint(9) NOT NULL COMMENT '服务器主键id',
+  `hostname` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '客户机名称',
+  `domain` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '域名',
+  `sales` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '销售负责人',
+  `status` tinyint(4) NOT NULL COMMENT '状态',
+  `webver` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '云端版本信息',
+  `softver` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '软件版本信息',
+  `created_at` timestamp NULL DEFAULT NULL,
+  `updated_at` timestamp NULL DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='客户机表';
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `sfu_servers`
+--
+
+CREATE TABLE `sfu_servers` (
+  `id` int(10) UNSIGNED NOT NULL,
+  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
+  `ip` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
+  `created_at` timestamp NULL DEFAULT NULL,
+  `updated_at` timestamp NULL DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+-- --------------------------------------------------------
+
+--
+-- 表的结构 `sfu_upgradelogs`
+--
+
+CREATE TABLE `sfu_upgradelogs` (
+  `id` int(10) UNSIGNED NOT NULL,
+  `hid` mediumint(9) NOT NULL COMMENT 'hosts主键',
+  `scondition` tinyint(1) UNSIGNED NOT NULL COMMENT '版本信息 1:更高版本 2:当前版本',
+  `version` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '软件版本号',
+  `jsondata` text COLLATE utf8_unicode_ci NOT NULL,
+  `created_at` timestamp NULL DEFAULT NULL,
+  `updated_at` timestamp NULL DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+--
+-- Indexes for dumped tables
+--
+
+--
+-- Indexes for table `fc_category`
+--
+ALTER TABLE `fc_category`
+  ADD PRIMARY KEY (`cateid`),
+  ADD KEY `catename` (`catename`,`parentid`);
+
+--
+-- Indexes for table `fc_item`
+--
+ALTER TABLE `fc_item`
+  ADD PRIMARY KEY (`itemid`),
+  ADD KEY `itemname` (`itemname`),
+  ADD KEY `code` (`code`);
+
+--
+-- Indexes for table `fc_log`
+--
+ALTER TABLE `fc_log`
+  ADD PRIMARY KEY (`id`),
+  ADD KEY `userid` (`userid`,`reportid`,`verid`);
+
+--
+-- Indexes for table `fc_report`
+--
+ALTER TABLE `fc_report`
+  ADD PRIMARY KEY (`reportid`),
+  ADD KEY `reportname` (`reportname`,`itemid`,`cateid`),
+  ADD KEY `parentid` (`parentid`),
+  ADD KEY `userid` (`userid`);
+
+--
+-- Indexes for table `fc_user`
+--
+ALTER TABLE `fc_user`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `fc_version`
+--
+ALTER TABLE `fc_version`
+  ADD PRIMARY KEY (`verid`),
+  ADD KEY `reportid` (`reportid`,`vername`),
+  ADD KEY `status` (`status`),
+  ADD KEY `vername` (`vername`),
+  ADD KEY `addtime` (`addtime`);
+
+--
+-- Indexes for table `sfu_hosts`
+--
+ALTER TABLE `sfu_hosts`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `sfu_servers`
+--
+ALTER TABLE `sfu_servers`
+  ADD PRIMARY KEY (`id`);
+
+--
+-- Indexes for table `sfu_upgradelogs`
+--
+ALTER TABLE `sfu_upgradelogs`
+  ADD PRIMARY KEY (`id`),
+  ADD KEY `scondition` (`scondition`);
+
+--
+-- 在导出的表使用AUTO_INCREMENT
+--
+
+--
+-- 使用表AUTO_INCREMENT `fc_category`
+--
+ALTER TABLE `fc_category`
+  MODIFY `cateid` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=47;
+--
+-- 使用表AUTO_INCREMENT `fc_item`
+--
+ALTER TABLE `fc_item`
+  MODIFY `itemid` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=14;
+--
+-- 使用表AUTO_INCREMENT `fc_log`
+--
+ALTER TABLE `fc_log`
+  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1085;
+--
+-- 使用表AUTO_INCREMENT `fc_report`
+--
+ALTER TABLE `fc_report`
+  MODIFY `reportid` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=185;
+--
+-- 使用表AUTO_INCREMENT `fc_user`
+--
+ALTER TABLE `fc_user`
+  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
+--
+-- 使用表AUTO_INCREMENT `fc_version`
+--
+ALTER TABLE `fc_version`
+  MODIFY `verid` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=341;
+--
+-- 使用表AUTO_INCREMENT `sfu_hosts`
+--
+ALTER TABLE `sfu_hosts`
+  MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
+--
+-- 使用表AUTO_INCREMENT `sfu_servers`
+--
+ALTER TABLE `sfu_servers`
+  MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
+--
+-- 使用表AUTO_INCREMENT `sfu_upgradelogs`
+--
+ALTER TABLE `sfu_upgradelogs`
+  MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;COMMIT;
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

+ 254 - 0
protected/class/PasswordHash.php

@@ -0,0 +1,254 @@
+<?php
+
+#
+# Portable PHP password hashing framework.
+#
+# Version 0.3 / genuine.
+#
+# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
+# the public domain.  Revised in subsequent years, still public domain.
+#
+# There's absolutely no warranty.
+#
+# The homepage URL for this framework is:
+#
+#	http://www.openwall.com/phpass/
+#
+# Please be sure to update the Version line if you edit this file in any way.
+# It is suggested that you leave the main version number intact, but indicate
+# your project name (after the slash) and add your own revision information.
+#
+# Please do not change the "private" password hashing method implemented in
+# here, thereby making your hashes incompatible.  However, if you must, please
+# change the hash type identifier (the "$P$") to something different.
+#
+# Obviously, since this code is in the public domain, the above are not
+# requirements (there can be none), but merely suggestions.
+#
+
+class PasswordHash
+{
+
+    var $itoa64;
+    var $iteration_count_log2;
+    var $portable_hashes;
+    var $random_state;
+
+    function __construct($iteration_count_log2, $portable_hashes)
+    {
+        $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+
+        if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
+            $iteration_count_log2 = 8;
+        $this->iteration_count_log2 = $iteration_count_log2;
+
+        $this->portable_hashes = $portable_hashes;
+
+        $this->random_state = microtime();
+        if (function_exists('getmypid'))
+            $this->random_state .= getmypid();
+    }
+
+    function get_random_bytes($count)
+    {
+        $output = '';
+        if (is_readable('/dev/urandom') &&
+            ($fh = @fopen('/dev/urandom', 'rb'))
+        ) {
+            $output = fread($fh, $count);
+            fclose($fh);
+        }
+
+        if (strlen($output) < $count) {
+            $output = '';
+            for ($i = 0; $i < $count; $i += 16) {
+                $this->random_state = md5(microtime() . $this->random_state);
+                $output .=
+                    pack('H*', md5($this->random_state));
+            }
+            $output = substr($output, 0, $count);
+        }
+
+        return $output;
+    }
+
+    function encode64($input, $count)
+    {
+        $output = '';
+        $i = 0;
+        do {
+            $value = ord($input[$i++]);
+            $output .= $this->itoa64[$value & 0x3f];
+            if ($i < $count)
+                $value |= ord($input[$i]) << 8;
+            $output .= $this->itoa64[($value >> 6) & 0x3f];
+            if ($i++ >= $count)
+                break;
+            if ($i < $count)
+                $value |= ord($input[$i]) << 16;
+            $output .= $this->itoa64[($value >> 12) & 0x3f];
+            if ($i++ >= $count)
+                break;
+            $output .= $this->itoa64[($value >> 18) & 0x3f];
+        } while ($i < $count);
+
+        return $output;
+    }
+
+    function gensalt_private($input)
+    {
+        $output = '$P$';
+        $output .= $this->itoa64[min($this->iteration_count_log2 +
+            ((PHP_VERSION >= '5') ? 5 : 3), 30)];
+        $output .= $this->encode64($input, 6);
+
+        return $output;
+    }
+
+    function crypt_private($password, $setting)
+    {
+        $output = '*0';
+        if (substr($setting, 0, 2) == $output)
+            $output = '*1';
+
+        $id = substr($setting, 0, 3);
+        # We use "$P$", phpBB3 uses "$H$" for the same thing
+        if ($id != '$P$' && $id != '$H$')
+            return $output;
+
+        $count_log2 = strpos($this->itoa64, $setting[3]);
+        if ($count_log2 < 7 || $count_log2 > 30)
+            return $output;
+
+        $count = 1 << $count_log2;
+
+        $salt = substr($setting, 4, 8);
+        if (strlen($salt) != 8)
+            return $output;
+
+        # We're kind of forced to use MD5 here since it's the only
+        # cryptographic primitive available in all versions of PHP
+        # currently in use.  To implement our own low-level crypto
+        # in PHP would result in much worse performance and
+        # consequently in lower iteration counts and hashes that are
+        # quicker to crack (by non-PHP code).
+        if (PHP_VERSION >= '5') {
+            $hash = md5($salt . $password, TRUE);
+            do {
+                $hash = md5($hash . $password, TRUE);
+            } while (--$count);
+        } else {
+            $hash = pack('H*', md5($salt . $password));
+            do {
+                $hash = pack('H*', md5($hash . $password));
+            } while (--$count);
+        }
+
+        $output = substr($setting, 0, 12);
+        $output .= $this->encode64($hash, 16);
+
+        return $output;
+    }
+
+    function gensalt_extended($input)
+    {
+        $count_log2 = min($this->iteration_count_log2 + 8, 24);
+        # This should be odd to not reveal weak DES keys, and the
+        # maximum valid value is (2**24 - 1) which is odd anyway.
+        $count = (1 << $count_log2) - 1;
+
+        $output = '_';
+        $output .= $this->itoa64[$count & 0x3f];
+        $output .= $this->itoa64[($count >> 6) & 0x3f];
+        $output .= $this->itoa64[($count >> 12) & 0x3f];
+        $output .= $this->itoa64[($count >> 18) & 0x3f];
+
+        $output .= $this->encode64($input, 3);
+
+        return $output;
+    }
+
+    function gensalt_blowfish($input)
+    {
+        # This one needs to use a different order of characters and a
+        # different encoding scheme from the one in encode64() above.
+        # We care because the last character in our encoded string will
+        # only represent 2 bits.  While two known implementations of
+        # bcrypt will happily accept and correct a salt string which
+        # has the 4 unused bits set to non-zero, we do not want to take
+        # chances and we also do not want to waste an additional byte
+        # of entropy.
+        $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+        $output = '$2a$';
+        $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
+        $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
+        $output .= '$';
+
+        $i = 0;
+        do {
+            $c1 = ord($input[$i++]);
+            $output .= $itoa64[$c1 >> 2];
+            $c1 = ($c1 & 0x03) << 4;
+            if ($i >= 16) {
+                $output .= $itoa64[$c1];
+                break;
+            }
+
+            $c2 = ord($input[$i++]);
+            $c1 |= $c2 >> 4;
+            $output .= $itoa64[$c1];
+            $c1 = ($c2 & 0x0f) << 2;
+
+            $c2 = ord($input[$i++]);
+            $c1 |= $c2 >> 6;
+            $output .= $itoa64[$c1];
+            $output .= $itoa64[$c2 & 0x3f];
+        } while (1);
+
+        return $output;
+    }
+
+    function HashPassword($password)
+    {
+        $random = '';
+
+        if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
+            $random = $this->get_random_bytes(16);
+            $hash = crypt($password, $this->gensalt_blowfish($random));
+            if (strlen($hash) == 60)
+                return $hash;
+        }
+
+        if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
+            if (strlen($random) < 3)
+                $random = $this->get_random_bytes(3);
+            $hash = crypt($password, $this->gensalt_extended($random));
+            if (strlen($hash) == 20)
+                return $hash;
+        }
+
+        if (strlen($random) < 6)
+            $random = $this->get_random_bytes(6);
+        $hash = $this->crypt_private($password, $this->gensalt_private($random));
+        if (strlen($hash) == 34)
+            return $hash;
+
+        # Returning '*' on error is safe here, but would _not_ be safe
+        # in a crypt(3)-like function used _both_ for generating new
+        # hashes and for validating passwords against existing hashes.
+        return '*';
+    }
+
+    function CheckPassword($password, $stored_hash)
+    {
+        $hash = $this->crypt_private($password, $stored_hash);
+        if ($hash[0] == '*')
+            $hash = crypt($password, $stored_hash);
+
+        return $hash == $stored_hash;
+    }
+
+}
+
+?>

+ 661 - 0
protected/class/client.php

@@ -0,0 +1,661 @@
+<?php
+
+class client {
+
+    private $ps_api_url, $ps_auth_key, $ps_vsersion;
+
+    /**
+     * 析构函数
+     * @param $ps_api_url 接口域名
+     * @param $ps_auth_key 加密密匙
+     */
+    public function __construct($ps_api_url = '127.0.0.1', $ps_auth_key = '', $ps_vsersion = '1') {
+        $this->ps_api_url = $ps_api_url;
+        $this->ps_auth_key = $ps_auth_key;
+        $this->ps_vsersion = $ps_vsersion;
+    }
+
+    /**
+     * 用户注册
+     * @param string $username 	用户名
+     * @param string $password 	密码
+     * @param string $email		email
+     * @param string $regip		注册ip
+     * @param string $random	密码随机数
+     * @return int {-1:用户名已经存在 ;-2:email已存在;-3:email格式错误;-4:用户名禁止注册;-5:邮箱禁止注册;int(uid):成功}
+     */
+    public function ps_member_register($username, $password, $email, $regip = '', $random = '') {
+        if (!$this->_is_email($email)) {
+            return -3;
+        }
+
+        return $this->_ps_send('register', array('username' => $username, 'password' => $password, 'email' => $email, 'regip' => $regip, 'random' => $random));
+    }
+
+    /**
+     * 用户登陆
+     * @param string $username 	用户名
+     * @param string $password 	密码
+     * @param int $isemail	email
+     * @return int {-2;密码错误;-1:用户名不存在;array(userinfo):用户信息}
+     */
+    public function zhsso_member_login($username, $password, $isemail = 0) {
+        if ($isemail == 1) {
+            if (!$this->_is_email($username)) {
+                return -3;
+            }
+            $return = $this->_ps_send('login', array('email' => $username, 'userpasswd' => $password));
+        } else if($isemail == 2 ) {
+            if (!$this->_is_mobile($username)) {
+                return -3;
+            }
+            $return = $this->_ps_send('login', array('mobile' => $username, 'userpasswd' => $password));
+        } else {
+
+            $return = $this->_ps_send('login', array('username' => $username, 'userpasswd' => $password));
+        }
+        return $return;
+    }
+
+    /**
+     * 获取用户信息通过COOKIE UID
+     */
+    public function zhsso_getuserinfo_by_uid($uid=0) {
+
+        return $this->_ps_send('getuserinfo', array('uid' => $uid));
+    }
+
+    public function zhsso_checkauth($auth="") {
+
+        return $this->_ps_send('checkauth', array('auth' => $auth));
+    }
+
+
+    /**
+     * 同步登陆
+     * @param string $uid
+     * @return string javascript用户同步登陆js
+     */
+    public function ps_member_synlogin($uid) {
+        $uid = intval($uid);
+        return $this->_ps_send('synlogin', array('uid' => $uid));
+    }
+
+    /**
+     * 同步退出
+     * @param string $uid
+     * @return string javascript用户同步退出js
+     */
+    public function ps_member_synlogout() {
+        return $this->_ps_send('synlogout', array());
+    }
+
+    /**
+     * 编辑用户
+     * @param string $username		用户名
+     * @param string $email			email
+     * @param string $password		旧密码
+     * @param string $newpassword	新密码
+     * @param int $uid				phpsso用户uid
+     * @param string $random	 	密码随机数
+     * @return int {-1:用户不存在;-2:旧密码错误;-3:email已经存在 ;-4:email格式错误;1:成功;0:未作修改}
+     */
+    public function zhsso_member_edit($uid = '', $password = '', $newpassword = '', $useranswer = '') {
+///	if ($email && !$this->_is_email($email)) {
+//	    return -4;
+//	}
+        // TODO:增加判断输出返回值
+        return $this->_ps_send('edit', array('uid' => $uid, 'password' => $password, 'newpassword' => $newpassword, 'useranswer' => $useranswer));
+    }
+
+    public function setPayWay($uid, $idcards, $alipay, $tenpay) {
+        return $this->_ps_send('payway', array('uid' => $uid, 'idbank' => $idcards, 'alipay' => $alipay, 'tenpay' => $tenpay));
+    }
+
+    /**
+     * 删除用户头像
+     * @param int $uid				phpsso用户uid
+     * @return int {1:成功;0:失败}
+     */
+    public function ps_deleteavatar($uid) {
+        return $this->_ps_send('deleteavatar', array('uid' => $uid));
+    }
+
+    /**
+     * 获取用户信息
+     * @param $mix 用户id/用户名/email
+     * @param $type {1:用户id;2:用户名;3:email}
+     * @return $mix {-1:用户不存在;userinfo:用户信息}
+     */
+    public function ps_get_member_info($mix, $type = 1) {
+        if ($type == 1) {
+            $userinfo = $this->_ps_send('getuserinfo', array('uid' => $mix));
+        } elseif ($type == 2) {
+            $userinfo = $this->_ps_send('getuserinfo', array('username' => $mix));
+        } elseif ($type == 3) {
+            if (!$this->_is_email($mix)) {
+                return -4;
+            }
+            $userinfo = $this->_ps_send('getuserinfo', array('email' => $mix));
+        }
+        if ($userinfo) {
+            return $userinfo;
+        } else {
+            return -1;
+        }
+    }
+
+    function url_exists($url) {
+        $h = get_headers($url);
+        if (!$h || !isset($h[0]))
+            return false;
+        $status = $h[0];
+        return preg_match("/.*200\s{1}OK/i", $status) ? true : false;
+    }
+
+    /**
+     * 删除用户
+     * @param mix {1:用户id;2:用户名;3:email} 如果是用户id可以为数组
+     * @return int {-1:用户不存在;1:删除成功}
+     */
+    public function ps_delete_member($mix, $type = 1) {
+        if ($type == 1) {
+            $res = $this->_ps_send('delete', array('uid' => $mix));
+        } elseif ($type == 2) {
+            $res = $this->_ps_send('delete', array('username' => $mix));
+        } elseif ($type == 3) {
+            if (!$this->_is_email($mix)) {
+                return -4;
+            }
+            $res = $this->_ps_send('delete', array('email' => $mix));
+        }
+        return $res;
+    }
+
+    /**
+     * 检查用户是否可以注册
+     * @param string $username
+     * @return int {-4:用户名禁止注册;-1:用户名已经存在 ;1:成功}
+     */
+    public function ps_checkname($username) {
+        return $this->_ps_send('checkname', array('username' => $username));
+    }
+
+    /**
+     * 检查邮箱是否可以注册
+     * @param string $email
+     * @return int {-1:email已经存在 ;-5:邮箱禁止注册;1:成功}
+     */
+    public function ps_checkemail($email) {
+        return $this->_ps_send('checkemail', array('email' => $email));
+    }
+
+    /**
+     * 获取应用列表信息
+     */
+    public function zhsso_getuserinfo() {
+        $uid = $this->authcode($_COOKIE[Doo::conf()->COOKIEPRE_WK . '_userid']);
+        return $this->_ps_send('getuserinfo', array('uid' => $uid));
+    }
+
+    /**
+     * 获取积分兑换比例列表
+     */
+    public function ps_getcreditlist() {
+        return $this->_ps_send('getcredit', array());
+    }
+
+    /**
+     * 兑换积分
+     * 用于何其他应用之间积分兑换
+     * @param int $uid			phpssouid
+     * @param int $from			本系统积分类型id
+     * @param int $toappid 		目标系统应用appid
+     * @param int $to			目标系统积分类型id
+     * @param int $credit		本系统扣除积分数
+     * @return bool 			{1:成功;0:失败}
+     */
+    public function ps_changecredit($uid, $from, $toappid, $to, $credit) {
+        return $this->_ps_send('changecredit', array('uid' => $uid, 'from' => $from, 'toappid' => $toappid, 'to' => $to, 'credit' => $credit));
+    }
+
+    /**
+     * 根据phpsso uid获取头像url
+     * @param int $uid 用户id
+     * @return array 四个尺寸用户头像数组
+     */
+    public function ps_getavatar($uid) {
+        $dir1 = ceil($uid / 10000);
+        $dir2 = ceil($uid % 10000 / 1000);
+        $url = $this->ps_api_url . 'data/avatar/' . $dir1 . '/' . $dir2 . '/' . $uid . '/';
+        $avatar = array('180' => $url . '180x180.jpg', '90' => $url . '90x90.jpg', '45' => $url . '45x45.jpg', '30' => $url . '30x30.jpg');
+        return $avatar;
+    }
+
+    /**
+     * 获取上传头像flash的html代码
+     * @param int $uid 用户id
+     */
+    public function ps_getavatar_upload_html($uid) {
+        $auth_data = $this->authcode($uid, 'ENCODE');
+//	echo $auth_data;
+//	list($a, $encodestr) = explode('=', $auth_data);
+        $upurl = base64_encode($this->ps_api_url . 'api/uploadavatar/' . rawurlencode($auth_data));
+//	$upurl = base64_encode($this->ps_api_url . '/index.php?m=phpsso&c=index&a=uploadavatar&auth_data=' . $auth_data);
+        $str = <<<EOF
+				<div id="phpsso_uploadavatar_flash"></div>
+				<script language="javascript" type="text/javascript" src="{$this->ps_api_url}global/v1/js/swfobject.js"></script>
+				<script type="text/javascript">
+					var flashvars = {
+						'upurl':"{$upurl}&callback=return_avatar&"
+					};
+					var params = {
+						'align':'middle',
+						'play':'true',
+						'loop':'false',
+						'scale':'showall',
+						'wmode':'window',
+						'devicefont':'true',
+						'id':'Main',
+						'bgcolor':'#ffffff',
+						'name':'Main',
+						'allowscriptaccess':'always'
+					};
+					var attributes = {
+
+					};
+					swfobject.embedSWF("{$this->ps_api_url}global/v1/swf/main.swf", "phpsso_uploadavatar_flash", "490", "434", "9.0.0","{$this->ps_api_url}global/v1/swf/expressInstall.swf", flashvars, params, attributes);
+
+					function return_avatar(data) {
+						if(data == 1) {
+							window.location.reload();
+						}
+					}
+				</script>
+EOF;
+        return $str;
+    }
+
+    /**
+     * 字符串加密、解密函数
+     *
+     *
+     * @param	string	$txt		字符串
+     * @param	string	$operation	ENCODE为加密,DECODE为解密,可选参数,默认为ENCODE,
+     * @param	string	$key		密钥:数字、字母、下划线
+     * @param	string	$expiry		过期时间
+     * @return	string
+     */
+    function sys_auth($string, $operation = 'ENCODE', $key = '', $expiry = 0) {
+        $key_length = 4;
+        $key = md5($key != '' ? $key : $this->ps_auth_key);
+        $fixedkey = hash('md5', $key);
+        $egiskeys = md5(substr($fixedkey, 16, 16));
+        $runtokey = $key_length ? ($operation == 'ENCODE' ? substr(hash('md5', microtime(true)), -$key_length) : substr($string, 0, $key_length)) : '';
+        $keys = hash('md5', substr($runtokey, 0, 16) . substr($fixedkey, 0, 16) . substr($runtokey, 16) . substr($fixedkey, 16));
+        $string = $operation == 'ENCODE' ? sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $egiskeys), 0, 16) . $string : base64_decode(substr($string, $key_length));
+
+        $i = 0;
+        $result = '';
+        $string_length = strlen($string);
+        for ($i = 0; $i < $string_length; $i++) {
+            $result .= chr(ord($string{$i}) ^ ord($keys{$i % 32}));
+        }
+        if ($operation == 'ENCODE') {
+            return $runtokey . str_replace('=', '', base64_encode($result));
+        } else {
+            if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $egiskeys), 0, 16)) {
+                return substr($result, 26);
+            } else {
+                return '';
+            }
+        }
+    }
+
+    /**
+     * 获取应用列表信息
+     */
+    public function zhsso_getUserbyName($uname) {
+        return $this->_ps_send('getuserinfo', array('username' => $uname));
+    }
+
+    /**
+     * 将数组转换为字符串
+     *
+     * @param	array	$data		数组
+     * @param	bool	$isformdata	如果为0,则不使用new_stripslashes处理,可选参数,默认为1
+     * @return	string	返回字符串,如果,data为空,则返回空
+     */
+    public function array2string($data, $isformdata = 1) {
+        if ($data == '')
+            return '';
+        if ($isformdata)
+            $data = new_stripslashes($data);
+        return var_export($data, TRUE);
+    }
+
+    public function auth_data($data) {
+        $s = $sep = '';
+//	foreach ($data as $k => $v) {
+//	    if (is_array($v)) {
+//		$s2 = $sep2 = '';
+//		foreach ($v as $k2 => $v2) {
+//		    $s2 .= "$sep2{$k}[$k2]=" . $this->_ps_stripslashes($v2);
+//		    $sep2 = '&';
+//		}
+//		$s .= $sep . $s2;
+//	    } else {
+//		$s .= "$sep$k=" . $this->_ps_stripslashes($v);
+//	    }
+//	    $sep = '&';
+//	}
+        $s = http_build_query($data);
+        $auth_s = 'data=' . urlencode($this->authcode($s, 'ENCODE'));
+        return $auth_s;
+    }
+
+    /**
+     * 发送数据
+     * @param $action 操作
+     * @param $data 数据
+     */
+    private function _ps_send($action, $data = null) {
+
+        return $this->_ps_post($this->ps_api_url . "api/" . $action, 500000, $this->auth_data($data));
+    }
+
+    /**
+     *  post数据
+     *  @param string $url		post的url
+     *  @param int $limit		返回的数据的长度
+     *  @param string $post		post数据,字符串形式username='dalarge'&password='123456'
+     *  @param string $cookie	模拟 cookie,字符串形式username='dalarge'&password='123456'
+     *  @param string $ip		ip地址
+     *  @param int $timeout		连接超时时间
+     *  @param bool $block		是否为阻塞模式
+     *  @return string			返回字符串
+     */
+    private function _ps_post($url, $limit = 0, $post = '', $cookie = '', $ip = '', $timeout = 15, $block = true) {
+        $return = '';
+        $matches = parse_url($url);
+        $host = $matches['host'];
+//	$path = $matches['path'] ? $matches['path'] . ($matches['query'] ? '?' . $matches['query'] : '') : '/';
+        $path = $matches['path'] ? $matches['path'] : '/';
+        $port = !empty($matches['port']) ? $matches['port'] : 80;
+        $siteurl = $this->_get_url();
+        if ($post) {
+            $out = "POST $path HTTP/1.1\r\n";
+            $out .= "Accept: */*\r\n";
+            $out .= "Referer: " . $siteurl . "\r\n";
+            $out .= "Accept-Language: zh-cn\r\n";
+            $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
+            $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
+            $out .= "Host: $host\r\n";
+            $out .= 'Content-Length: ' . strlen($post) . "\r\n";
+            $out .= "Connection: Close\r\n";
+            $out .= "Cache-Control: no-cache\r\n";
+            $out .= "Cookie: $cookie\r\n\r\n";
+            $out .= $post;
+        } else {
+            $out = "GET $path HTTP/1.1\r\n";
+            $out .= "Accept: */*\r\n";
+            $out .= "Referer: " . $siteurl . "\r\n";
+            $out .= "Accept-Language: zh-cn\r\n";
+            $out .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
+            $out .= "Host: $host\r\n";
+            $out .= "Connection: Close\r\n";
+            $out .= "Cookie: $cookie\r\n\r\n";
+        }
+        $fp = @fsockopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout);
+        if (!$fp)
+            return '';
+
+        stream_set_blocking($fp, $block);
+        stream_set_timeout($fp, $timeout);
+        @fwrite($fp, $out);
+        $status = stream_get_meta_data($fp);
+
+        if ($status['timed_out'])
+            return '';
+        while (!feof($fp)) {
+            if (($header = @fgets($fp)) && ($header == "\r\n" || $header == "\n"))
+                break;
+        }
+
+        $stop = false;
+        while (!feof($fp) && !$stop) {
+            $data = fread($fp, ($limit == 0 || $limit > 8192 ? 8192 : $limit));
+            $return .= $data;
+            if ($limit) {
+                $limit -= strlen($data);
+                $stop = $limit <= 0;
+            }
+        }
+        @fclose($fp);
+
+        //部分虚拟主机返回数值有误,暂不确定原因,过滤返回数据格式
+        $return_arr = explode("\n", $return);
+        if (isset($return_arr[1])) {
+            $return = trim($return_arr[1]);
+        }
+        unset($return_arr);
+
+        return $return;
+    }
+
+    /**
+     * 过滤字符串
+     * @param $string
+     */
+    private function _ps_stripslashes($string) {
+        !defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
+        if (MAGIC_QUOTES_GPC) {
+            return stripslashes($string);
+        } else {
+            return $string;
+        }
+    }
+
+    /**
+     * 获取当前页面完整URL地址
+     */
+    private function _get_url() {
+        $sys_protocal = isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://';
+        $php_self = $_SERVER['PHP_SELF'] ? $this->_safe_replace($_SERVER['PHP_SELF']) : $this->_safe_replace($_SERVER['SCRIPT_NAME']);
+        $path_info = isset($_SERVER['PATH_INFO']) ? $this->_safe_replace($_SERVER['PATH_INFO']) : '';
+        $relate_url = isset($_SERVER['REQUEST_URI']) ? $this->_safe_replace($_SERVER['REQUEST_URI']) : $php_self . (isset($_SERVER['QUERY_STRING']) ? '?' . $this->_safe_replace($_SERVER['QUERY_STRING']) : $path_info);
+        return $sys_protocal . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '') . $relate_url;
+    }
+
+    /**
+     * 安全过滤函数
+     *
+     * @param $string
+     * @return string
+     */
+    private function _safe_replace($string) {
+        $string = str_replace('%20', '', $string);
+        $string = str_replace('%27', '', $string);
+        $string = str_replace('%2527', '', $string);
+        $string = str_replace('*', '', $string);
+        $string = str_replace('"', '&quot;', $string);
+        $string = str_replace("'", '', $string);
+        $string = str_replace('"', '', $string);
+        $string = str_replace(';', '', $string);
+        $string = str_replace('<', '&lt;', $string);
+        $string = str_replace('>', '&gt;', $string);
+        $string = str_replace("{", '', $string);
+        $string = str_replace('}', '', $string);
+        $string = str_replace('\\', '', $string);
+        return $string;
+    }
+
+    /**
+     * 金额增加
+     * @param string $userid 	用户唯一标示符
+     * @param string $m 	操作金额
+     * @param int $appid	应用程序ID,标示操作来源{wenku,ask}
+     * @return int {0;金额增加失败;1:金额增加成功;}
+     */
+    public function zhsso_member_madd($userid, $m, $appid) {
+        if (empty($userid) || empty($m) || empty($appid))
+            return false;
+        return $this->_ps_send('madd', array('uid' => $userid, 'bank' => $m, 'appid' => $appid));
+    }
+
+    /**
+     * 获取充值订单数据
+     * @param unknown_type $userid
+     */
+    public function getPayOrder($userid) {
+        if (empty($userid))
+            return false;
+        return $this->_ps_send('getPayOrder', array('uid' => $userid));
+    }
+
+    /**
+     * 金额减少
+     * @param string $userid 	用户唯一标示符
+     * @param string $m 	操作金额
+     * @param int $appid	应用程序ID,标示操作来源{wenku,ask}
+     * @return int {-1;金额不够减;0;金额减少失败;1:金额减少成功;}
+     */
+    public function zhsso_member_msub($userid, $m, $appid) {
+        if (empty($userid) || empty($m) || empty($appid))
+            return false;
+        return $this->_ps_send('msub', array('uid' => $userid, 'bank' => $m, 'appid' => $appid));
+    }
+
+    /**
+     * 判断email格式是否正确
+     * @param $string email
+     */
+    private function _is_email($email) {
+        return strlen($email) > 6 && preg_match("/^[\w\-\.]+@[\w\-\.]+(\.\w+)+$/", $email);
+    }
+
+    /**
+     * 判断手机格式是否正确
+     * @param $string email
+     */
+    private function _is_mobile($mobile) {
+        if(preg_match("/^1[34578]{1}\d{9}$/",$mobile)){
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+
+    /**
+     * 判断email格式是否正确
+     * @param $string email
+     */
+    public function getUserName() {
+        $username = self::get_cookie('_username');
+        if ($username) {
+            return $username;
+        } else {
+            return FALSE;
+        }
+    }
+
+    /**
+     * 判断email格式是否正确
+     * @param $string email
+     */
+    public function getAuth() {
+        $auth = self::get_cookie('auth');
+        if ($auth) {
+            return $auth;
+        } else {
+            return FALSE;
+        }
+    }
+
+    /**
+     * 判断email格式是否正确
+     * @param $string email
+     */
+    public function getUserID() {
+        $userid = self::get_cookie('_userid');
+        if ($userid) {
+            return $userid;
+        } else {
+            return FALSE;
+        }
+    }
+
+    public function get_cookie($var, $default = '') {
+
+        $varvar = COOKIEPRE_WD . $var;
+
+        return isset($_COOKIE[$varvar]) ? $this->authcode($_COOKIE[$varvar]) : $default;
+    }
+
+    /**
+     *
+     * 网络传输、cookie加密函数
+     * @param type $string
+     * @param type $operation
+     * @param type $key
+     * @param type $expiry
+     * @return string
+     */
+    function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
+        $ckey_length = 4;
+        $key = md5($key != '' ? $key : AUTHKEY);
+        $keya = md5(substr($key, 0, 16));
+        $keyb = md5(substr($key, 16, 16));
+        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
+
+        $cryptkey = $keya . md5($keya . $keyc);
+        $key_length = strlen($cryptkey);
+
+        $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
+        $string_length = strlen($string);
+
+        $result = '';
+        $box = range(0, 255);
+
+        $rndkey = array();
+        for ($i = 0; $i <= 255; $i++) {
+            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
+        }
+
+        for ($j = $i = 0; $i < 256; $i++) {
+            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
+            $tmp = $box[$i];
+            $box[$i] = $box[$j];
+            $box[$j] = $tmp;
+        }
+
+        for ($a = $j = $i = 0; $i < $string_length; $i++) {
+            $a = ($a + 1) % 256;
+            $j = ($j + $box[$a]) % 256;
+            $tmp = $box[$a];
+            $box[$a] = $box[$j];
+            $box[$j] = $tmp;
+            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
+        }
+
+        if ($operation == 'DECODE') {
+            if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
+                return substr($result, 26);
+            } else {
+                return '';
+            }
+        } else {
+            return $keyc . str_replace('=', '', base64_encode($result));
+        }
+    }
+
+    public function logoutz() {
+//	header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
+        setcookie(Doo::conf()->COOKIEPRE_WK . 'auth', '', 0, '/', 'localhost', 0);
+        setcookie(Doo::conf()->COOKIEPRE_WK . '_username', '', 0, '/', 'localhost', 0);
+        setcookie(Doo::conf()->COOKIEPRE_WK . '_userid', '', 0, '/', 'localhost', 0);
+    }
+
+}
+
+?>

+ 117 - 0
protected/config/common.conf.php

@@ -0,0 +1,117 @@
+<?php
+
+/*
+ * Common configuration that can be used throughout the application
+ * Please refer to DooConfig class in the API doc for a complete list of configurations
+ * Access via Singleton, eg. Doo::conf()->BASE_PATH;
+ */
+error_reporting(E_ALL | E_STRICT);
+date_default_timezone_set('Asia/Shanghai');
+
+/**
+ * for benchmark purpose, call Doo::benchmark() for time used.
+ */
+//$config['START_TIME'] = microtime(true);
+//For framework use. Must be defined. Use full absolute paths and end them with '/'      eg. /var/www/project/
+$config['SITE_PATH'] = realpath('..') . '/vc/';
+//$config['PROTECTED_FOLDER'] = 'protected/';
+$config['BASE_PATH'] = realpath('..') . '/dooframework/';
+
+//for production mode use 'prod'
+$config['APP_MODE'] = 'dev';
+
+//----------------- optional, if not defined, default settings are optimized for production mode ----------------
+//if your root directory is /var/www/ and you place this in a subfolder eg. 'app', define SUBFOLDER = '/app/'
+
+$config['SUBFOLDER'] = str_replace($_SERVER['DOCUMENT_ROOT'], '', str_replace('\\', '/', $config['SITE_PATH']));
+if (strpos($config['SUBFOLDER'], '/') !== 0) {
+    $config['SUBFOLDER'] = '/' . $config['SUBFOLDER'];
+}
+
+$config['APP_URL'] = 'http://' . $_SERVER['HTTP_HOST'] . $config['SUBFOLDER'];
+//$config['AUTOROUTE'] = TRUE;
+$config['DEBUG_ENABLED'] = False;
+
+//$config['TEMPLATE_COMPILE_ALWAYS'] = TRUE;
+//register functions to be used with your template files
+//$config['TEMPLATE_GLOBAL_TAGS'] = array('url', 'url2', 'time', 'isset', 'empty');
+
+/**
+ * Path to store logs/profiles when using with the logger tool. This is needed for writing log files and using the log viewer tool
+ */
+//$config['LOG_PATH'] = '/var/logs/';
+
+
+/**
+ * defined either Document or Route to be loaded/executed when requested page is not found
+ * A 404 route must be one of the routes defined in routes.conf.php (if autoroute on, make sure the controller and method exist)
+ * Error document must be more than 512 bytes as IE sees it as a normal 404 sent if < 512b
+ */
+//$config['ERROR_404_DOCUMENT'] = 'error.php';
+$config['ERROR_404_ROUTE'] = '/error';
+
+
+/**
+ * Settings for memcache server connections, you don't have to set if using localhost only.
+ * host, port, persistent, weight
+ * $config['MEMCACHE'] = array(
+ *                       array('192.168.1.31', '11211', true, 40),
+ *                       array('192.168.1.23', '11211', true, 80)
+ *                     );
+ */
+/**
+ * Defines modules that are allowed to be accessed from an auto route URI.
+ * Example, we have a module in SITE_PATH/PROTECTED_FOLDER/module/example
+ * It can be accessed via http://localhost/example/controller/method/parameters
+ *
+ * $config['MODULES'] = array('example');
+ *
+ */
+/**
+ * Unique string ID of the application to be used with PHP 5.3 namespace and auto loading of namespaced classes
+ * If you wish to use namespace with the framework, your classes must have a namespace starting with this ID.
+ * Example below is located at /var/www/app/protected/controller/test and can be access via autoroute http://localhost/test/my/method
+ * <?php
+ * namespace myapp\controller\test;
+ * class MyController extends \DooController {
+ *     .....
+ * } ?>
+ *
+ * You would need to enable autoload to use Namespace classes in index.php
+ * spl_autoload_register('Doo::autoload');
+ *
+ * $config['APP_NAMESPACE_ID'] = 'myapp';
+ *
+ */
+/**
+ * To enable autoloading, add directories which consist of the classes needed in your application.
+ *
+ * $config['AUTOLOAD'] = array(
+  //internal directories, live in the app
+  'class', 'model', 'module/example/controller',
+  //external directories, live outside the app
+  '/var/php/library/classes'
+  );
+ */
+/**
+ * you can include self defined config, retrieved via Doo::conf()->variable
+ * Use lower case for you own settings for future Compability with DooPHP
+ */
+//$config['pagesize'] = 10;
+$config['AUTHKEY'] = 'z685b7q4V8ifR7F9T71eUdH8p9k5i135G6p6C9Mek4m3q7y7Uba2XbXdKfXbr9Af';
+//$config['COOKIEPRE'] = 'p6C4m3_NZ_';
+//$config['COOKIEPRE_WK'] = 'GLgxZR_WK_';
+// 最后的斜杠要带
+$config['ZHSSO'] = 'http://sso.smartcost.com.cn/';
+define ( "COOKIE_WEB_SITE", "vc.6jlzf.cn" );
+
+
+define ( 'SYSTEM_DAILY_LOGIN', 2);
+define ( "USERNAME_ONFINE", - 1 );
+define ( "PASSWORD_ERROR", - 2 );
+define ( "WEB_SITE", "http://vc.6jlzf.cn" );
+define ( "REAL_PATH", realpath ( '..' ) );
+define ( "SITE_PATH", REAL_PATH . "/vc/" );
+define ( "ZHSSO", "http://sso.smartcost.com.cn/" );
+define ( "BASE_PATH", REAL_PATH . "/dooframework/" );
+define ( "AUTHKEY", "z685b7q4V8ifR7F9T71eUdH8p9k5i135G6p6C9Mek4m3q7y7Uba2XbXdKfXbr9Af" );

+ 36 - 0
protected/config/db.conf.php

@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * Example Database connection settings and DB relationship mapping
+ * $dbmap[Table A]['has_one'][Table B] = array('foreign_key'=> Table B's column that links to Table A );
+ * $dbmap[Table B]['belongs_to'][Table A] = array('foreign_key'=> Table A's column where Table B links to );
+
+
+  //Food relationship
+  $dbmap['Food']['belongs_to']['FoodType'] = array('foreign_key'=>'id');
+  $dbmap['Food']['has_many']['Article'] = array('foreign_key'=>'food_id');
+  $dbmap['Food']['has_one']['Recipe'] = array('foreign_key'=>'food_id');
+  $dbmap['Food']['has_many']['Ingredient'] = array('foreign_key'=>'food_id', 'through'=>'food_has_ingredient');
+
+  //Food Type
+  $dbmap['FoodType']['has_many']['Food'] = array('foreign_key'=>'food_type_id');
+
+  //Article
+  $dbmap['Article']['belongs_to']['Food'] = array('foreign_key'=>'id');
+
+  //Recipe
+  $dbmap['Recipe']['belongs_to']['Food'] = array('foreign_key'=>'id');
+
+  //Ingredient
+  $dbmap['Ingredient']['has_many']['Food'] = array('foreign_key'=>'ingredient_id', 'through'=>'food_has_ingredient');
+
+ */
+//$dbconfig[ Environment or connection name] = array(Host, Database, User, Password, DB Driver, Make Persistent Connection?);
+/**
+ * Database settings are case sensitive.
+ * To set collation and charset of the db connection, use the key 'collate' and 'charset'
+ * array('localhost', 'database', 'root', '1234', 'mysql', true, 'collate'=>'utf8_unicode_ci', 'charset'=>'utf8');
+ */
+$dbconfig['dev'] = array('localhost','jlzfver','sfu','1qaz2wsx','mysql',false, 'collate' => 'utf8_unicode_ci', 'charset' => 'utf8');
+
+?>

+ 113 - 0
protected/config/routes.conf.php

@@ -0,0 +1,113 @@
+<?php
+
+$route['*']['/'] = array('BaseController', 'login');
+$route['*']['/login'] = array('BaseController', 'login');
+$route['*']['/login/do'] = array('BaseController', 'do_login');
+$route['*']['/exit'] = array('MainController', 'fc_exit');
+
+//报表管理
+$route['*']['/reportlist/:status'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/:status/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/:status/item/:itemid'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/:status/item/:itemid/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/:status/sort/:sort'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/:status/sort/:sort/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/:status/item/:itemid/sort/:sort'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/:status/item/:itemid/sort/:sort/page/:pindex'] = array('MainController', 'ReportList');
+
+$route['*']['/reportlist'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/area/:area'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/area/:area/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate/area/:area'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate/area/:area/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/sort/:sort'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/sort/:sort/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/area/:area/sort/:sort'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/area/:area/sort/:sort/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate/sort/:sort'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate/sort/:sort/page/:pindex'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate/area/:area/sort/:sort'] = array('MainController', 'ReportList');
+$route['*']['/reportlist/cate/:cate/area/:area/sort/:sort/page/:pindex'] = array('MainController', 'ReportList');
+
+$route['*']['/addreport'] = array('MainController', 'AddReport');
+$route['*']['/addreport/:status'] = array('MainController', 'AddReport');
+$route['*']['/addreport/:status/item/:itemid'] = array('MainController', 'AddReport');
+$route['*']['/setreport'] = array('MainController', 'SetReport');
+$route['*']['/deletereport/:reportid'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid/pindex/:pindex'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/item/:itemid'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/item/:itemid/pindex/:pindex'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/sort/:sort'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/sort/:sort/pindex/:pindex'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid/sort/:sort'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid/sort/:sort/pindex/:pindex'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/item/:itemid/sort/:sort'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/item/:itemid/sort/:sort/pindex/:pindex'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/area/:area'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/area/:area'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/area/:area/pindex/:pindex'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid/area/:area'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid/area/:area/pindex/:pindex'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid/area/:area/sort/:sort'] = array('MainController', 'DelReport');
+$route['*']['/deletereport/:reportid/cate/:cateid/area/:area/sort/:sort/pindex/:pindex'] = array('MainController', 'DelReport');
+
+//版本管理
+$route['*']['/versionlist/:reportid'] = array('MainController', 'VersionList');
+$route['*']['/addversion/:reportid'] = array('MainController', 'AddVersion');
+$route['*']['/version/:verid'] = array('MainController', 'UpdateVersion');
+$route['*']['/setversion'] = array('MainController', 'SetVersion');
+$route['*']['/deleteversion/:verid'] = array('MainController', 'DelVersion');
+$route['*']['/version/:verid/update/data'] = array('MainController', 'UpdateDataVersion');
+
+//类别管理
+$route['*']['/catelist'] = array('MainController', 'CateList');
+$route['*']['/catelist/page/:pindex'] = array('MainController', 'CateList');
+$route['*']['/catelist/:status'] = array('MainController', 'CateList');
+$route['*']['/catelist/:status/item/:itemid'] = array('MainController', 'CateList');
+$route['*']['/catelist/:status/item/:itemid/page/:pindex'] = array('MainController', 'CateList');
+$route['*']['/addcate'] = array('MainController', 'AddCate');
+$route['*']['/getcateparentlist'] = array('MainController', 'CateParentList');
+$route['*']['/getchild'] = array('MainController', 'GetCateChild');
+$route['*']['/getcatechild'] = array('MainController', 'GetCateChildList');
+$route['*']['/getcateparentbyitem'] = array('MainController', 'GetCateParentList');
+$route['*']['/updatecate'] = array('MainController', 'UpdateCate');
+$route['*']['/deletecate/:cateid'] = array('MainController', 'DelCate');
+$route['*']['/deletecate/:cateid/item/:itemid'] = array('MainController', 'DelCate');
+$route['*']['/deletecate/:cateid/item/:itemid/page/:pindex'] = array('MainController', 'DelCate');
+$route['*']['/deletecate/:cateid/page/:pindex'] = array('MainController', 'DelCate');
+//项目管理
+$route['*']['/itemlist'] = array('MainController', 'ItemList');
+$route['*']['/itemlist/page/:pindex'] = array('MainController', 'ItemList');
+$route['*']['/additem'] = array('MainController', 'AddItem');
+$route['*']['/deleteitem/:itemid'] = array('MainController', 'DelItem');
+$route['*']['/updateitem'] = array('MainController', 'UpdateItem');
+
+
+//软件调用接口
+$route['*']['/api/getreportmsg'] = array('ApiController', 'ReportMsg');
+$route['*']['/api/getreportmsg/:update'] = array('ApiController', 'ReportMsg');
+$route['*']['/api/downloadurl/:reportid'] = array('ApiController', 'DownloadReport');
+$route['*']['/api/downloadurl/:reportid/:version'] = array('ApiController', 'DownloadReport');
+$route['*']['/api/getxml/:reportid/:xml/:filesize'] = array('ApiController', 'DownloadUrl');
+$route['*']['/api/getversionmsg/:reportid'] = array('ApiController', 'VersionMsg');
+$route['*']['/api/report/update/get'] = array('ApiController', 'GetUpdateReport');
+
+
+// jlzf 服务器版本管理
+$route['*']['/hostlist'] = array('HostController', 'hostList');
+$route['*']['/hostlist/page/:pindex'] = array('HostController', 'hostList');
+$route['*']['/hostlist/:op'] = array('HostController', 'hostList');
+$route['*']['/hostlist/:op/page/:pindex'] = array('HostController', 'hostList');
+$route['*']['/addhosts'] = array('HostController', 'addHosts');
+$route['*']['/edithosts/:id'] = array('HostController', 'editHosts');
+$route['*']['/update/hosts/webversion/status'] = array('HostController', 'updateWebVerStatus');
+$route['*']['/hosts/upgradeinfo'] = array('HostController', 'upgradeinfoHosts');
+
+
+//$route['*']['/updatepwd'] = array('BaseController', 'updatePassword');
+
+?>

+ 218 - 0
protected/controller/ApiController.php

@@ -0,0 +1,218 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: smartcost
+ * Date: 2016/12/13
+ * Time: 11:56
+ */
+class ApiController extends DooController {
+
+    /**
+     * 共用报表信息调用接口,根据领取码获取项目报表列表
+     *
+     */
+    public function ReportMsg(){
+        Doo::loadModel('report');
+        $report = new Report();
+        $name = '';
+        $addsql = isset($this->params['update']) && $this->params['update'] == 'all' ? '' : ' AND `fc_report`.itemid=0';
+        if(isset($_POST['itemcode'])){
+            Doo::loadModel('item');
+            $items = new Item();
+            $itemmsg = $items->getRowbyCode($_POST['itemcode']);
+            $name = '项目';
+            if(!empty($itemmsg)){
+                $addsql = ' AND `fc_report`.itemid='.$itemmsg['itemid'];
+            }else{
+                $arr = array('status' => 'true', 'msg' => '当前'.$name.'报表为空', 'info' => '');
+                echo $this->decodeUnicode(json_encode($arr));
+                exit;
+            }
+        }
+        if(isset($_POST['areacate']) && is_numeric($_POST['areacate'])){
+            $addsql .= ' AND (`fc_report`.areacate=3 OR `fc_report`.areacate='.$_POST['areacate'].')';
+        }
+        $sql = 'SELECT `fc_report`.reportid,reportname,areacate,cateid,parentid,`fc_report`.edittime,`fc_report`.itemid FROM `fc_report` left join `fc_version` on `fc_report`.reportid=`fc_version`.reportid where `fc_report`.reportid=`fc_version`.reportid'.$addsql.' and `fc_version`.status=2 group by `fc_report`.reportid order by `fc_report`.edittime desc';
+        $query = Doo::db ()->query ( $sql );
+        $reportlist = $query->fetchAll ();
+        if(!empty($reportlist)){
+            foreach ($reportlist as $k => $v) {
+                Doo::loadModel('category');
+                $category = new Category();
+                if($v['parentid'] != 0){
+                    $catename = $category->getnamebyid($v['parentid']).'/'.$category->getnamebyid($v['cateid']);
+                }else{
+                    $catename = $category->getnamebyid($v['cateid']);
+                }
+                $reportlist[$k]['catename'] = $catename;
+
+                $reportlist[$k]['edittime'] = date('YmdHis',$v['edittime']);
+
+                Doo::loadModel('version');
+                $versions = new Version();
+                $reportlist[$k]['desc'] = $versions->getRowbyVername(date('YmdHis',$v['edittime']))['content'];
+
+                unset($reportlist[$k]['cateid']);
+                unset($reportlist[$k]['parentid']);
+            }
+            $arr = array('status' => 'true', 'msg' => '', 'info' => $reportlist);
+            echo $this->decodeUnicode(json_encode($arr));
+            exit;
+        }
+        $arr = array('status' => 'true', 'msg' => '当前'.$name.'报表为空', 'info' => '');
+        echo $this->decodeUnicode(json_encode($arr));
+        exit;
+    }
+
+    /*
+     * 报表更新调用接口
+     *
+     */
+    public function GetUpdateReport(){
+        Doo::loadModel('report');
+        $report = new Report();
+        if(isset($_POST['idlist'])){
+            $idlist = explode(',',$_POST['idlist']);
+            $infoarr = array();
+            foreach($idlist as $k => $v){
+                $reportmsg = $report->getRowbyid($v);
+                $infoarr[$k]['id'] = $v;
+                $infoarr[$k]['edittime'] = !empty($reportmsg) ? date('YmdHis',$reportmsg['edittime']) : '';
+            }
+            $arr = array('status' => 'true', 'msg' => '', 'info' => $infoarr);
+            echo $this->decodeUnicode(json_encode($arr));
+            exit;
+        }else{
+            $arr = array('status' => 'false', 'msg' => '传递的参数有误', 'info' => '');
+            echo $this->decodeUnicode(json_encode($arr));
+            exit;
+        }
+    }
+
+    /**
+     * 下载最新报表或对应版本报表
+     *
+     */
+    public function DownloadReport(){
+        if(isset($this->params['reportid']) && is_numeric($this->params['reportid'])){
+            Doo::loadModel('version');
+            $version = new Version();
+            if(isset($this->params['version'])){
+                $vermsg = $version->getOne(array('select' => 'verid,addtime', 'where' => 'status!=0 and reportid='.$this->params['reportid'].' and vername="'.$this->params['version'].'"', 'desc' => 'addtime', 'asArray' => TRUE));
+            }else{
+                $vermsg = $version->getOne(array('select' => 'verid,addtime', 'where' => 'status!=0 and reportid='.$this->params['reportid'], 'desc' => 'addtime', 'asArray' => TRUE));
+            }
+            if(!empty($vermsg)){
+                include (DOO::conf()->SITE_PATH . 'protected/plugin/io.han.php');
+                $this->IoHandler = new IoHandler();
+                $baseurl = '/opt/www/vc/';
+                $verurl = $this->params['reportid'].'/'.$vermsg['verid'].'_'.date('YmdHis',$vermsg['addtime']);
+                $vername = $baseurl."jlbb/".$verurl.'.xml';
+                if($this->IoHandler->ReadFile($vername)){
+                    $arr = array('status' => 'true', 'msg' => '', 'info' => array('downloadurl' => Doo::conf()->APP_URL.'api/getxml/'.$verurl.'/'.filesize($vername)));
+                    echo $this->decodeUnicode(json_encode($arr));
+                    exit;
+                }else{
+                    $arr = array('status' => 'false', 'msg' => '本报表不存在下载地址', 'info' => '');
+                    echo $this->decodeUnicode(json_encode($arr));
+                    exit;
+                }
+            }else{
+                $arr = array('status' => 'false', 'msg' => '当前报表不存在版本信息,无法下载', 'info' => '');
+                echo $this->decodeUnicode(json_encode($arr));
+                exit;
+            }
+        }else{
+            $arr = array('status' => 'false', 'msg' => '请传入报表id值', 'info' => '');
+            echo $this->decodeUnicode(json_encode($arr));
+            exit;
+        }
+    }
+
+    /**
+     * 获取报表最近3个版本
+     *
+     */
+    public function VersionMsg(){
+        if(isset($this->params['reportid']) && is_numeric($this->params['reportid']) ){
+            Doo::loadModel('version');
+            $version = new Version();
+            $verlist = $version->find(array('select' => 'verid,vername,content,addtime', 'where' => 'status=2 and reportid='.$this->params['reportid'], 'desc' => 'addtime','limit' => 3, 'asArray' => TRUE));
+            if(!empty($verlist)){
+                include (DOO::conf()->SITE_PATH . 'protected/plugin/io.han.php');
+                $this->IoHandler = new IoHandler();
+                foreach($verlist as $k => $v){
+                    $baseurl = '/opt/www/vc/';
+                    $verurl = $this->params['reportid'].'/'.$v['verid'].'_'.date('YmdHis',$v['addtime']);
+                    $vername = $baseurl."jlbb/".$verurl.'.xml';
+                    if($this->IoHandler->ReadFile($vername)){
+                        $verlist[$k]['downloadurl'] = Doo::conf()->APP_URL.'api/getxml/'.$verurl.'/'.filesize($vername);
+                    }else{
+                        $arr = array('status' => 'false', 'msg' => $v['vername'].'版本不存在下载地址', 'info' => '');
+                        echo $this->decodeUnicode(json_encode($arr));
+                        exit;
+                    }
+                    unset($verlist[$k]['verid']);
+                    unset($verlist[$k]['addtime']);
+                }
+                $arr = array('status' => 'true', 'msg' => '', 'info' => $verlist);
+                echo $this->decodeUnicode(json_encode($arr));
+                exit;
+
+            }else{
+                $arr = array('status' => 'false', 'msg' => '本报表不存在版本信息', 'info' => '');
+                echo $this->decodeUnicode(json_encode($arr));
+                exit;
+            }
+        }else{
+            $arr = array('status' => 'false', 'msg' => '请传入报表id值', 'info' => '');
+            echo $this->decodeUnicode(json_encode($arr));
+            exit;
+        }
+
+    }
+
+    public function DownloadUrl(){
+        $pathf = '/opt/www/vc/jlbb/';
+        $reportid = $this->params['reportid'];
+        $xmlname = $this->params['xml'];
+        $size = $this->params['filesize'];
+        $url = $pathf.'/'.$reportid.'/'.$xmlname.'.xml';
+        $this->file_down($url,$xmlname,$size);
+        exit;
+    }
+
+    /**
+     * 文件下载
+     * @param $filepath 文件路径
+     * @param $filename 文件名称
+     */
+    function file_down($filepath, $filename = '', $filesize, $filetype = 'xml') {
+        if (ob_get_length() !== false)
+            @ob_end_clean();
+        header('Pragma: public');
+        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+        header('Cache-Control: no-store, no-cache, must-revalidate');
+        header('Cache-Control: pre-check=0, post-check=0, max-age=0');
+        header('Content-Transfer-Encoding: binary');
+        header('Content-Encoding: none');
+        header('Content-type: ' . $filetype);
+        header('Content-Disposition: attachment; filename="' . iconv("UTF-8", "GBK", $filename ). '.' . $filetype .'"');
+        header('Content-length: ' . $filesize);
+        @readfile($filepath);
+        exit;
+    }
+
+
+
+    function decodeUnicode($str) {
+        return preg_replace_callback('/\\\\u([0-9a-f]{4})/i',
+            create_function(
+                '$matches',
+                'return mb_convert_encoding(pack("H*", $matches[1]), "UTF-8", "UCS-2BE");'
+            ),
+            $str);
+    }
+
+}

+ 209 - 0
protected/controller/BaseController.php

@@ -0,0 +1,209 @@
+<?php
+
+session_start(); // starts new or resumes existing session
+session_regenerate_id(true); // regenerates SESSIONID to prevent hijacking
+/**
+ * 核心控制
+ * @author cp
+ */
+Doo::loadClass('PasswordHash');
+
+class BaseController extends DooController {
+
+	public $data;
+	public $userinfo;
+	public $__ph;
+
+	function __construct() {
+		$this->__ph = new PasswordHash(8, FALSE);
+		$this->data['rootUrl'] = Doo::conf()->APP_URL;
+	}
+
+	public function login() {
+		$this->data['message'] = '';
+		$this->data['_token_'] = $this->generateFormHash($this->create_randomstr());
+		$this->render('login-fc', $this->data);
+	}
+
+	/**
+	 * 进入后台
+	 */
+	function do_login() {
+
+		if(!isset($_POST['name']) || empty($_POST['name'])){
+			$this->data['message'] = '帐号不能为空';
+			$this->data['_token_'] = $this->generateFormHash($this->create_randomstr());
+			$this->render('login-fc',$this->data);die;
+		}
+
+		if(!isset($_POST['password']) || empty($_POST['password'])){
+			$this->data['message'] = '密码不能为空';
+			$this->data['_token_'] = $this->generateFormHash($this->create_randomstr());
+			$this->render('login-fc',$this->data);die;
+		}
+		if (!$this->isValidFormHash($_POST['tokenform'])) {
+			$this->data['message'] = '';
+			$this->data['_token_'] = $this->generateFormHash($this->create_randomstr());
+			$this->render('login-fc',$this->data);die;
+		}
+
+		$data ['name'] = $_POST['name'];
+
+		$data ['password'] = $_POST['password'];
+
+		$user = $this->checkLogin($data);
+
+		if (!empty ( $user )) {
+
+			$userinfo = $this->authcode ( $user ['username'], "tr" );
+
+			setcookie ( "jlzf_main", $userinfo, time () + 3600 * 12, "/", COOKIE_WEB_SITE );
+
+			return '/reportlist';
+//			header ( 'Content-Type:text/html;charset=utf-8' );
+//			@header ( "Location: " . COOKIE_WEB_SITE . "/m/userlist" );
+		}else{
+			$this->data['message'] = '账号或密码错误!';
+			$this->render('login-fc',$this->data);die;
+//			header ( 'Content-Type:text/html;charset=utf-8' );
+//			@header ( "Location: " . COOKIE_WEB_SITE . "/m/login" );
+		}
+	}
+
+	function checkLogin($data) {
+		Doo::loadModel('fcuser');
+		$users = new Fcuser();
+        $userArray = $users->getRowByuser($data['name']);
+        if (isset($userArray) && $userArray && $this->__ph->CheckPassword($data['password'], $userArray['password'])) {
+            return $userArray;
+        } else {
+            return FALSE;
+        }
+    }
+
+//    public function updatePassword(){
+//        Doo::loadModel('fcuser');
+//        $users = new Fcuser();
+//        $userlist = $users->find(array('asArray' => TRUE));
+//        foreach($userlist as $k => $v){
+//            $users1 = new Fcuser();
+//            $users1->id = $v['id'];
+//            $users1->password = $this->__ph->HashPassword($v['password']);
+//            $users1->update();
+//        }
+//        echo 'ok';
+//        exit;
+//    }
+	
+	/**
+	 * FC系统登录
+	 */
+	function admin_init(){
+	//是否已经登录纵横
+
+		if (isset ( $_COOKIE ['jlzf_main'] )) {
+
+			$userinfo=$this->authcode ($_COOKIE ['jlzf_main']);
+
+			Doo::loadModel('fcuser');
+        	$users = new fcuser();
+
+			$this->userinfo=$users->getRowByuser($userinfo);
+
+		}else{
+			setcookie ( "jlzf_main", "", time () + 3600 * 12, "/", COOKIE_WEB_SITE );
+			//无权限进入后台
+			header ( 'Content-Type:text/html;charset=utf-8' );
+			@header ( "Location: /login");
+		}
+
+		if (!empty ( $this->userinfo )) {
+			//跳转前台登录
+			$userinfo = $this->authcode ( $this->userinfo['username'], "tr" );
+			//header ( 'Content-Type:text/html;charset=utf-8' );
+			//@header ( "Location: /"  );
+			setcookie ( "jlzf_main", $userinfo, time () + 3600 * 12, "/", COOKIE_WEB_SITE );
+			return $this->userinfo;
+
+		} else {
+			setcookie ( "jlzf_main", "", time () + 3600 * 12, "/", COOKIE_WEB_SITE );
+			//无权限进入后台
+			header ( 'Content-Type:text/html;charset=utf-8' );
+			@header ( "Location: /login");
+		}
+	}
+
+	function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
+		$ckey_length = 4;
+		if (! $key) {
+			$key = "ZHKT";
+		}
+		$key = md5 ( $key );
+		$keya = md5 ( substr ( $key, 0, 16 ) );
+		$keyb = md5 ( substr ( $key, 16, 16 ) );
+		$keyc = $ckey_length ? ($operation == 'DECODE' ? substr ( $string, 0, $ckey_length ) : substr ( md5 ( microtime () ), - $ckey_length )) : '';
+
+		$cryptkey = $keya . md5 ( $keya . $keyc );
+		$key_length = strlen ( $cryptkey );
+
+		$string = $operation == 'DECODE' ? base64_decode ( substr ( $string, $ckey_length ) ) : sprintf ( '%010d', $expiry ? $expiry + time () : 0 ) . substr ( md5 ( $string . $keyb ), 0, 16 ) . $string;
+		$string_length = strlen ( $string );
+
+		$result = '';
+		$box = range ( 0, 255 );
+
+		$rndkey = array ();
+		for($i = 0; $i <= 255; $i ++) {
+			$rndkey [$i] = ord ( $cryptkey [$i % $key_length] );
+		}
+
+		for($j = $i = 0; $i < 256; $i ++) {
+			$j = ($j + $box [$i] + $rndkey [$i]) % 256;
+			$tmp = $box [$i];
+			$box [$i] = $box [$j];
+			$box [$j] = $tmp;
+		}
+
+		for($a = $j = $i = 0; $i < $string_length; $i ++) {
+			$a = ($a + 1) % 256;
+			$j = ($j + $box [$a]) % 256;
+			$tmp = $box [$a];
+			$box [$a] = $box [$j];
+			$box [$j] = $tmp;
+			$result .= chr ( ord ( $string [$i] ) ^ ($box [($box [$a] + $box [$j]) % 256]) );
+		}
+
+		if ($operation == 'DECODE') {
+			if ((substr ( $result, 0, 10 ) == 0 || substr ( $result, 0, 10 ) - time () > 0) && substr ( $result, 10, 16 ) == substr ( md5 ( substr ( $result, 26 ) . $keyb ), 0, 16 )) {
+				return substr ( $result, 26 );
+			} else {
+				return '';
+			}
+		} else {
+			return $keyc . str_replace ( '=', '', base64_encode ( $result ) );
+		}
+	}
+
+	function generateFormHash($salt)
+    {
+        $hash = sha1(mt_rand(1, 1000000) . $salt);
+        $_SESSION['csrf_hash'] = $hash;
+        return $hash;
+    }
+
+    function isValidFormHash($hash)
+    {
+        return $_SESSION['csrf_hash'] === $hash;
+    }
+
+    /**
+     * 生成随机字符串
+     * @param string $lenth 长度
+     * @return string 字符串
+     */
+    function create_randomstr($lenth = 6)
+    {
+        return $this->random($lenth, '123456789abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ');
+    }
+}
+?>

+ 260 - 0
protected/controller/HostController.php

@@ -0,0 +1,260 @@
+<?php
+Doo::loadModel('hosts');
+Doo::loadModel('servers');
+Doo::loadModel('upgradelogs');
+Doo::loadHelper('DooPager');
+/**
+ * Created by PhpStorm.
+ * User: ellisran
+ * Date: 2016/11/17
+ * Time: 11:48
+ */
+
+class HostController extends DooController {
+
+    public $data,$__hosts, $__servers,$__upgradelogs;
+
+    function __construct() {
+        $this->data['rootUrl'] = Doo::conf()->APP_URL;
+        include ('./protected/controller/BaseController.php');
+        $this->base = new BaseController ();
+        $userinfo = $this->base->admin_init();
+        $this->data['uid'] = $userinfo['id'];
+        $this->data['username'] = $userinfo['username'];
+        $this->__hosts = new Hosts();
+        $this->__servers = new Servers();
+        $this->__upgradelogs = new UpgradeLogs();
+        $this->data['currpage'] = 'server';
+    }
+
+    public function hostList(){
+        //获取服务器
+        $serverarr = $this->__servers->getAllServer();
+        $sql = $pagesql = '';
+        if(isset($_GET['op']) && is_numeric($_GET['op'])){
+            $sql = 'serverid='.$_GET['op'];
+            $pagesql = '/'.$_GET['op'];
+            $this->data['op'] = $_GET['op'];
+        }elseif(isset($this->params['op']) && is_numeric($this->params['op'])){
+            $sql = 'serverid='.$this->params['op'];
+            $pagesql = '/'.$this->params['op'];
+            $this->data['op'] = $this->params['op'];
+        }else{
+            $sql = ' 1';
+        }
+
+        $totalArchive = $this->__hosts->count(array('where' => $sql, 'asArray' => TRUE));
+        $pager = new DooPager(Doo::conf()->APP_URL . "hostlist".$pagesql."/page", $totalArchive, 15, 15);
+        if (isset($this->params['pindex']))
+            $pager->paginate(intval($this->params['pindex']));
+        else
+            $pager->paginate(1);
+        if ($pager->limit != ' -15,15')
+            $hostarr = $this->__hosts->getServerHosts($sql,$pager->limit);
+
+        if(isset($hostarr) && !empty($hostarr)){
+            foreach($hostarr as $k => $v){
+                $servermsg = $this->__servers->getRowbyID($v['serverid']);
+                $hostarr[$k]['servername'] = $servermsg['name'];
+                $hostarr[$k]['serverip'] = $servermsg['ip'];
+
+                //获取软件最后一个是否有更高版本
+                $hostarr[$k]['condition'] = 2;
+                $rowData = $this->__upgradelogs->getRowLast($v['id']);
+                if(!empty($rowData)){
+                    if($rowData['version'] != $v['softver']){
+                        $hostarr[$k]['softver'] = $rowData['version'];
+                        $hostarr[$k]['condition'] = $rowData['scondition'];
+                    }
+                }
+            }
+        }
+        $this->data['server'] = $serverarr;
+        $this->data['hosts'] = isset($hostarr) ? $hostarr : '';
+        $this->data['pager'] = $pager->output;
+        $this->render ( "server-list", $this->data, TRUE);
+    }
+
+    public function editHosts(){
+        if(isset($this->params['id']) && is_numeric($this->params['id'])){
+            $hostmsg = $this->__hosts->getRowbyID($this->params['id']);
+            if(!empty($hostmsg)){
+                $result = $this->updateWebAndStatus($hostmsg['id'],$hostmsg['domain'],$hostmsg['webver']);
+                $hostmsg['webver'] = $result['version'];
+
+                //获取更高版本软件版本号
+                $rowData = $this->__upgradelogs->getRowbyhidcond($hostmsg['id'],1);
+                if(!empty($rowData)){
+                    $hostmsg['highsoftver'] = $rowData['version'];
+                }else{
+                    $hostmsg['highsoftver'] = '';
+                }
+
+                $this->data['host'] = $hostmsg;
+
+                //获取是否关闭了客户端登录
+                if($result['onoff'] != 2){
+                    $this->data['onoff'] = $result['onoff'];
+                }else{
+                    $this->data['errormsg'] = '通讯异常,无法获取客户端是否禁止状态';
+                }
+
+                if(isset($_POST['hostname'])){
+                    //获取云端版本
+                    $data = array('url' => 'http://'.$_POST['domain'].'/api/upgrade/v1/get/web/version');
+                    $datamsg = $this->_httpClient($data);
+                    if($datamsg){
+                        $this->__hosts->id = $this->params['id'];
+                        $this->__hosts->serverid = $_POST['server'];
+                        $this->__hosts->hostname = $_POST['hostname'];
+                        $this->__hosts->domain = $_POST['domain'];
+                        $this->__hosts->sales = $_POST['sales'];
+                        $this->__hosts->status = 1;
+                        $this->__hosts->updated_at = date('Y-m-d H:i:s', time());
+                        $this->__hosts->update();
+                        return '/hostlist';
+                    }else{
+                        $this->data['errormsg'] = '该域名不存在版本信息,无法修改';
+                    }
+                }
+            }else{
+                $this->data['errormsg'] = '不存在该客户机';
+            }
+        }
+        $serverarr = $this->__servers->getAllServer();
+        $this->data['server'] = $serverarr;
+        $this->render ( "edit-server", $this->data, TRUE);
+    }
+
+    public function addHosts(){
+        if(isset($_POST['hostname'])){
+            //获取云端版本
+            $data = array('url' => 'http://'.$_POST['domain'].'/api/upgrade/v1/get/web/version');
+            $datamsg = $this->_httpClient($data);
+            if($datamsg){
+                $this->__hosts->serverid = $_POST['server'];
+                $this->__hosts->hostname = $_POST['hostname'];
+                $this->__hosts->domain = $_POST['domain'];
+                $this->__hosts->sales = $_POST['sales'];
+                $this->__hosts->status = 1;
+                $this->__hosts->webver = json_decode($datamsg)->version;
+                $this->__hosts->softver = $_POST['swversion'];
+                $this->__hosts->created_at = date('Y-m-d H:i:s', time());
+                $this->__hosts->updated_at = date('Y-m-d H:i:s', time());
+                $this->__hosts->insert();
+                return '/hostlist';
+            }else{
+                $this->data['errormsg'] = '该域名不存在版本信息';
+            }
+        }
+        $serverarr = $this->__servers->getAllServer();
+        $this->data['server'] = $serverarr;
+        $this->render ( "add-server", $this->data, TRUE);
+    }
+
+    public function updateWebVerStatus(){
+        $hostmsg = $this->__hosts->getRowbyID($_POST['id']);
+        if(!empty($hostmsg)){
+            $result = $this->updateWebAndStatus($_POST['id'],$_POST['domain'],$_POST['version']);
+            exit(json_encode($result));
+        }else{
+            exit(json_encode(array('msg' => 404)));
+        }
+    }
+
+    //升级
+    public function upgradeinfoHosts(){
+        $hostmsg = $this->__hosts->getRowbyID($_POST['domainid']);
+        $data = array(
+            'condition' => $_POST['scondition'],
+            'version' => $_POST['sversion'],
+            'download' => $_POST['sdownload'],
+            'desc' => $_POST['sdesc']
+        );
+        $rowData = $this->__upgradelogs->getRowbyhidcond($_POST['domainid'],$_POST['scondition']);
+        if(empty($rowData)){
+            $this->__upgradelogs->hid = $_POST['domainid'];
+            $this->__upgradelogs->scondition = $_POST['scondition'];
+            $this->__upgradelogs->version = $_POST['sversion'];
+            $this->__upgradelogs->jsondata = json_encode($data);
+            $this->__upgradelogs->created_at = date('Y-m-d H:i:s', time());
+            $this->__upgradelogs->updated_at = date('Y-m-d H:i:s', time());
+            $this->__upgradelogs->insert();
+        }else{
+            $this->__upgradelogs->id = $rowData['id'];
+            $this->__upgradelogs->version = $_POST['sversion'];
+            $this->__upgradelogs->jsondata = json_encode($data);
+            $this->__upgradelogs->updated_at = date('Y-m-d H:i:s', time());
+            $this->__upgradelogs->update();
+        }
+
+        if($_POST['scondition'] == 2){
+            $this->__hosts->id = $_POST['domainid'];
+            $this->__hosts->softver = $_POST['sversion'];
+            $this->__hosts->updated_at = date('Y-m-d H:i:s', time());
+            $this->__hosts->update();
+
+            $result = $this->_httpClient($data2 = array('url'=> 'http://'.$hostmsg['domain'].'/api/upgrade/v1/set/upgrade/info', 'msg' => array('json' => json_encode($data))), 'post');
+            if($result && json_decode($result)->onoff == 1) {
+                exit(json_encode(array('onoff' => 1, 'softver' => $_POST['sversion'], 'condition' => $_POST['scondition'])));
+            }else{
+                exit(json_encode(array('onoff' => 0)));
+            }
+        }
+        exit(json_encode(array('onoff' => 1, 'softver' => $_POST['sversion'], 'condition' => $_POST['scondition'])));
+//        exit(json_encode(array('onoff' => 0)));
+    }
+
+    //更新web版本和通讯状态
+    function updateWebAndStatus($id,$domain,$oldwebver){
+        //获取云端版本
+        $data = array('url' => 'http://'.$domain.'/api/upgrade/v1/get/version/status');
+        $datamsg = $this->_httpClient($data);
+        if($datamsg){
+            $change = 0;
+            if(json_decode($datamsg)->version != $oldwebver){
+                $this->__hosts->id = $id;
+                $this->__hosts->webver = json_decode($datamsg)->version;
+                $this->__hosts->status = 1;
+                $this->__hosts->updated_at = date('Y-m-d H:i:s', time());
+                $this->__hosts->update();
+                $change = 1;
+            }
+            return array('version' => json_decode($datamsg)->version, 'onoff' => json_decode($datamsg)->onoff, 'change' => $change);
+        }else{
+            $this->__hosts->id = $id;
+            $this->__hosts->webver = '';
+            $this->__hosts->status = 2;
+            $this->__hosts->updated_at = date('Y-m-d H:i:s', time());
+            $this->__hosts->update();
+            return array('version' => '', 'onoff' => 2, 'change' => 2);
+        }
+    }
+
+    /**
+     * POST或者GET方式访问计量支付接口
+     * @param string $data
+     * @return mixed
+     */
+    private function _httpClient($data, $type = 'get') {
+        try {
+            $ch = curl_init();
+//            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept:text/plain;charset=utf-8', 'Content-Type:application/x-www-form-urlencoded','charset=utf-8'));
+            curl_setopt($ch, CURLOPT_URL,$data['url']);
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+            curl_setopt($ch, CURLOPT_HEADER, 0);
+            if($type == 'post'){
+                curl_setopt($ch, CURLOPT_POST, 1);
+                curl_setopt($ch, CURLOPT_POSTFIELDS, $data['msg']);
+            }
+            curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+//            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+            $res = curl_exec($ch);
+            curl_close($ch);
+            return $res;
+        } catch (Exception $e) {
+            return false;
+        }
+    }
+}

+ 875 - 0
protected/controller/MainController.php

@@ -0,0 +1,875 @@
+<?php
+
+
+/**
+ * Created by PhpStorm.
+ * User: ellisran
+ * Date: 2016/11/17
+ * Time: 11:48
+ */
+
+class MainController extends DooController {
+
+    public $data;
+
+    function __construct() {
+        $this->data['rootUrl'] = Doo::conf()->APP_URL;
+        include ('./protected/controller/BaseController.php');
+        $this->base = new BaseController ();
+        $userinfo = $this->base->admin_init();
+        $this->data['uid'] = $userinfo['id'];
+        $this->data['username'] = $userinfo['username'];
+        $this->data['currpage'] = 'report';
+    }
+
+    public function fc_exit() {
+        session_destroy();
+        setcookie ( "jlzf_main", "", time () + 3600 * 12, "/", COOKIE_WEB_SITE );
+        return '/';
+    }
+
+    //报表管理
+    public function ReportList(){
+        Doo::loadModel('report');
+        $report = new Report();
+        Doo::loadModel('category');
+        $category = new Category();
+        Doo::loadModel('item');
+        $item = new Item();
+        $pagesql = '';
+        $sql = '';
+        $sortsql = '';
+        if(isset($this->params['area']) && is_numeric($this->params['area'])){
+            $pagesql .= '/area/'.$this->params['area'];
+            $sql .= ' AND areacate='.$this->params['area'];
+            $this->data['area'] = $this->params['area'];
+        }
+        if(isset($this->params['sort'])){
+            $pagesql .= '/sort/'.$this->params['sort'];
+            if($this->params['sort'] == 'report'){
+                $sortsql = 'report';
+            }
+            $this->data['sort'] = $this->params['sort'];
+        }
+        if(isset($this->params['status']) && $this->params['status'] == 1){
+            $this->data['dingzhi'] = true;
+            $itemlist = $item->getAllMsg();
+            $this->data['itemlist'] = $itemlist;
+            $this->data['itemid'] = 0;
+            if(isset($this->params['itemid']) && $this->params['itemid'] != 0){
+                $this->data['item'] = $item->getRowbyid($this->params['itemid']);
+                $this->data['itemid'] = $this->params['itemid'];
+                $totalArchive = $report->count(array('where' => 'itemid=0', 'asArray' => TRUE));
+                $pager = new DooPager(Doo::conf()->APP_URL . "reportlist/1/item/".$this->params['itemid'].$pagesql."/page", $totalArchive, 15, 10);
+                if (isset($this->params['pindex'])){
+                    $this->data['pindex'] = $this->params['pindex'];
+                    $pager->paginate(intval($this->params['pindex']));
+                } else
+                    $pager->paginate(1);
+                if ($pager->limit != ' -15,15')
+                    $this->data['reportlist'] = $report->getitemRowbylimit($pager->limit,$this->params['itemid'],$sortsql);
+            }else{
+                $totalArchive = $report->count(array('where' => 'itemid!=0', 'asArray' => TRUE));
+                $pager = new DooPager(Doo::conf()->APP_URL . "reportlist/1".$pagesql."/page", $totalArchive, 15, 10);
+                if (isset($this->params['pindex'])){
+                    $this->data['pindex'] = $this->params['pindex'];
+                    $pager->paginate(intval($this->params['pindex']));
+                } else
+                    $pager->paginate(1);
+                if ($pager->limit != ' -15,15')
+                    $this->data['reportlist'] = $report->getAllitemRowbylimit($pager->limit,$sortsql);
+            }
+        }else{
+            $this->data['catelist'] = $category->getAlllist();
+            $cateparentlist = $category->getparentlist();
+            $this->data['cateparentlist'] = $cateparentlist;
+            $this->data['cateid'] = '';
+            if(isset($this->params['cate']) && $this->params['cate'] != 0){
+                $this->data['cateid'] = $this->params['cate'];
+                $totalArchive = $report->count(array('where' => 'itemid=0 and (cateid='.$this->params['cate'].' or parentid='.$this->params['cate'].')'.$sql, 'asArray' => TRUE));
+                $pager = new DooPager(Doo::conf()->APP_URL . "reportlist/cate/".$this->params['cate'].$pagesql."page", $totalArchive, 15, 10);
+                if (isset($this->params['pindex'])){
+                    $this->data['pindex'] = $this->params['pindex'];
+                    $pager->paginate(intval($this->params['pindex']));
+                } else
+                    $pager->paginate(1);
+                if ($pager->limit != ' -15,15')
+                    $this->data['reportlist'] = $report->getcateRowbylimit($pager->limit,$this->params['cate'],$sql,$sortsql);
+            }else{
+                $totalArchive = $report->count(array('where' => 'itemid=0'.$sql, 'asArray' => TRUE));
+                $pager = new DooPager(Doo::conf()->APP_URL . "reportlist".$pagesql."/page", $totalArchive, 15, 10);
+                if (isset($this->params['pindex'])){
+                    $this->data['pindex'] = $this->params['pindex'];
+                    $pager->paginate(intval($this->params['pindex']));
+                } else
+                    $pager->paginate(1);
+                if ($pager->limit != ' -15,15')
+                    $this->data['reportlist'] = $report->getitemRowbylimit($pager->limit,0,$sortsql,$sql);
+            }
+        }
+        if(isset($this->data['reportlist'])) {
+            foreach ($this->data['reportlist'] as $k => $v) {
+                Doo::loadModel('version');
+                $version = new Version();
+                $versionnum = $version->count(array('where' => 'status!=0 and reportid='.$v['reportid'], 'asArray' => TRUE));
+                $this->data['reportlist'][$k]['versionnum'] = $versionnum;
+
+                Doo::loadModel('category');
+                $category2 = new Category();
+                if($v['parentid'] != 0){
+                    $catename = $category2->getnamebyid($v['parentid']).'/'.$category2->getnamebyid($v['cateid']);
+                }else{
+                    $catename = $category2->getnamebyid($v['cateid']);
+                }
+                $this->data['reportlist'][$k]['catename'] = $catename;
+
+                $this->data['reportlist'][$k]['edittime'] = $versionnum != 0 ? date('YmdHis',$v['edittime']) : '';
+
+                if($v['itemid'] != 0){
+                    $this->data['reportlist'][$k]['itemname'] = $item->getnamebyid($v['itemid']);
+                }
+            }
+        }
+        $this->data['pager'] = $pager->output;
+        $this->render ( "form-list", $this->data, TRUE);
+    }
+
+    public function AddReport(){
+        if(isset($this->params['status']) && $this->params['status'] == 1){
+            //定制添加报表
+            $this->data['dingzhi'] = true;
+            Doo::loadModel('item');
+            $item = new Item();
+            $itemlist = $item->getAllMsg();
+            $this->data['itemlist'] = $itemlist;
+            if(isset($this->params['itemid'])){
+                $this->data['itemid'] = $this->params['itemid'];
+                //通用添加报表
+                Doo::loadModel('category');
+                $category = new Category();
+                $cateparentlist = $category->getparentlist($this->params['itemid']);
+                $this->data['cateparentlist'] = $cateparentlist;
+            }else{
+                $this->data['itemid'] = '';
+            }
+        }else{
+            //通用添加报表
+            Doo::loadModel('category');
+            $category = new Category();
+            $cateparentlist = $category->getparentlist();
+            $this->data['cateparentlist'] = $cateparentlist;
+        }
+        $this->render ( "add-form", $this->data, TRUE);
+    }
+
+    public function SetReport(){
+        if(isset($_POST['itemselect']) && $_POST['itemselect'] == 0){
+            exit('项目不能为空');
+        }
+        if(!isset($_POST['parentselect']) || $_POST['parentselect'] == 0){
+            exit('类别不能为空');
+        }
+        if(!isset($_POST['reportname']) || empty($_POST['reportname'])){
+            exit('报表名不能为空');
+        }
+        Doo::loadModel('report');
+        $report = new Report();
+        if(isset($_POST['reportid'])){
+            $report->reportid = $_POST['reportid'];
+            $report->itemid = isset($_POST['itemselect']) ? $_POST['itemselect'] : 0;
+            $report->parentid = isset($_POST['cateselect']) ? $_POST['parentselect'] : 0;
+            $report->cateid = isset($_POST['cateselect']) ? $_POST['cateselect'] : $_POST['parentselect'];
+            $report->reportname = $_POST['reportname'];
+            $report->areacate = isset($_POST['areaselect']) ? $_POST['areaselect'] : 3;
+            $report->update();
+
+            //路由返回
+            $returnurl = '/reportlist';
+
+            if(isset($_POST['itemid'])) {
+                $returnurl .= '/1';
+            }
+            if(isset($_POST['itemid']) && $_POST['itemid'] != 0){
+                $returnurl .= '/item/'.$_POST['itemid'];
+            }
+            if(isset($_POST['cateid']) && !empty($_POST['cateid'])){
+                $returnurl .= '/cate/'.$_POST['cateid'];
+            }
+            if(isset($_POST['area']) && is_numeric($_POST['area'])){
+                $returnurl .= '/area/'.$_POST['area'];
+            }
+            if(isset($_POST['sort']) && $_POST['sort'] == 'report'){
+                $returnurl .= '/sort/report';
+            }
+            if(isset($_POST['pindex'])){
+                $returnurl .= '/page/'.$_POST['pindex'];
+            }
+
+            return $returnurl;
+
+        }else{
+            $reports = array(
+                'reportname' => $_POST['reportname'],
+                'areacate' => isset($_POST['areaselect']) ? $_POST['areaselect'] : 3,
+                'itemid' => isset($_POST['itemselect']) ? $_POST['itemselect'] : 0,
+                'parentid' => isset($_POST['cateselect']) ? $_POST['parentselect'] : 0,
+                'cateid' => isset($_POST['cateselect']) ? $_POST['cateselect'] : $_POST['parentselect'],
+                'userid' => $this->data['uid'],
+                'edittime' => time()
+            );
+            $reportid = $report->_insertAttributes('report', $reports);
+
+            return '/versionlist/'.$reportid;
+        }
+    }
+
+    public function DelReport(){
+        $reportId = $this->params['reportid'];
+        Doo::loadModel('report');
+        $report = new Report();
+        $report->reportid = $reportId;
+        $report->delete();
+
+        Doo::loadModel('version');
+        $version = new Version();
+        $version->reportid = $reportId;
+        $version->delete();
+
+        Doo::loadModel('log');
+        $log = new Log();
+        $log->reportid = $reportId;
+        $log->delete();
+
+        include (DOO::conf()->SITE_PATH . 'protected/plugin/io.han.php');
+        $this->IoHandler = new IoHandler();
+        //调用定义物理路径
+        $t=DOO::conf()->SITE_PATH."jlbb/".$reportId;
+        $this->IoHandler->RemoveDir($t);
+
+        //路由返回
+        $returnurl = '/reportlist';
+
+        if(isset($_POST['itemid'])) {
+            $returnurl .= '/1';
+        }
+        if(isset($_POST['itemid']) && $_POST['itemid'] != 0){
+            $returnurl .= '/item/'.$_POST['itemid'];
+        }
+        if(isset($_POST['cateid']) && !empty($_POST['cateid'])){
+            $returnurl .= '/cate/'.$_POST['cateid'];
+        }
+        if(isset($_POST['area']) && is_numeric($_POST['area'])){
+            $returnurl .= '/area/'.$_POST['area'];
+        }
+        if(isset($_POST['sort']) && $_POST['sort'] == 'report'){
+            $returnurl .= '/sort/report';
+        }
+        if(isset($_POST['pindex'])){
+            $returnurl .= '/page/'.$_POST['pindex'];
+        }
+
+        return $returnurl;
+    }
+
+    //版本管理
+    public function VersionList(){
+        if(isset($this->params['reportid'])){
+            Doo::loadModel('version');
+            $version = new Version();
+            $versionlist = $version->getRowbyreport($this->params['reportid']);
+            $this->data['versionlist'] = $versionlist;
+            $this->data['reportid'] = $this->params['reportid'];
+            $this->render('formver-list', $this->data, TRUE);die;
+        }
+        return '/reportlist';
+    }
+
+    public function AddVersion(){
+        if(isset($this->params['reportid'])){
+            echo "生成版本中,请稍后...";
+            Doo::loadModel('report');
+            $report = new Report();
+            $reportmsg = $report->getRowbyid($this->params['reportid']);
+            Doo::loadModel('item');
+            $item = new Item();
+            if($reportmsg['itemid'] != 0){
+                $reportcate = 1;
+                $itemname = $item->getnamebyid($reportmsg['itemid']);
+            }else{
+                $reportcate = 0;
+                $itemname = '';
+            }
+
+            Doo::loadModel('category');
+            $category = new Category();
+            if($reportmsg['parentid'] != 0){
+                $parentname = $category->getnamebyid($reportmsg['parentid']);
+            }else{
+                $parentname = '';
+            }
+            $catename = $category->getnamebyid($reportmsg['cateid']);
+            $time = time();
+            $version = array(
+                'vername' => date('YmdHis',$time),
+                'reportid' => $reportmsg['reportid'],
+                'reportname' => $reportmsg['reportname'],
+                'reportcate' => $reportcate,
+                'itemname' => $itemname,
+                'catename' => $catename,
+                'parentname' => $parentname
+            );
+            if(!empty($version['parentname'])){
+                $name1 = '分类="1"  分类名称="'.$version['parentname'].'"  子分类="1"  子分类名称="'.$version['catename'].'"';
+            }else{
+                $name1 = '分类="1"  分类名称="'.$version['catename'].'"  ';
+            }
+
+            $createXML = '';
+            Doo::loadModel('version');
+            $version2 = new Version();
+            $version2->reportid = $version['reportid'];
+            $version2->vername = date('YmdHis',$time);
+            $version2->xmlbody = $createXML;
+            $version2->status = 1;
+            $version2->addtime = $time;
+            $version2->edittime = $time;
+            $verid = $version2->insert();
+
+            Doo::loadModel('log');
+            $log = new Log();
+            $log->reportid = $version['reportid'];
+            $log->userid = $this->data['uid'];
+            $log->verid = $verid;
+            $log->vername = $version['vername'];
+            $log->addtime = $time;
+            $log->content = date('Y-m-d H:i:s',$time).' '.$this->data['username'].' 创建版本'.$version['vername'];
+            $log->insert();
+
+            include (DOO::conf()->SITE_PATH . 'protected/plugin/io.han.php');
+            $this->IoHandler = new IoHandler();
+            //调用定义物理路径
+            $t=DOO::conf()->SITE_PATH."jlbb/".$version['reportid'];
+            $this->IoHandler->MakeDir($t);
+
+            $xmlName = $verid.'_'.date('YmdHis',$time).'.xml';
+
+            $xml = trim($createXML);
+            $myfile = fopen($t.'/'.$xmlName, "w");
+            fwrite($myfile, $xml);
+            fclose($myfile);
+
+//            $this->data['verid'] = $verid;
+//            $this->data['version'] = $version;
+//            $this->data['reportid'] = $this->params['reportid'];
+
+//            $log2 = new Log();
+//            $loglist = $log2->getListbyverid($verid);
+//            $this->data['loglist'] = $loglist;
+//            $this->render('add-formver', $this->data, TRUE);die;
+            return '/version/'.$verid.'?status=new';
+        }
+        return '/reportlist';
+    }
+
+    public function UpdateVersion(){
+        if(isset($this->params['verid'])) {
+            Doo::loadModel('version');
+            $version = new Version();
+            $versionmsg = $version->getRowbyid($this->params['verid']);
+            $this->data['version'] = $versionmsg;
+            Doo::loadModel('report');
+            $report = new Report();
+            $reportmsg = $report->getRowbyid($versionmsg['reportid']);
+            Doo::loadModel('item');
+            $item = new Item();
+            if($reportmsg['itemid'] != 0){
+                $reportcate = 1;
+                $itemname = $item->getnamebyid($reportmsg['itemid']);
+            }else{
+                $reportcate = 0;
+                $itemname = '';
+            }
+
+            Doo::loadModel('category');
+            $category = new Category();
+            if($reportmsg['parentid'] != 0){
+                $parentname = $category->getnamebyid($reportmsg['parentid']);
+            }else{
+                $parentname = '';
+            }
+            $catename = $category->getnamebyid($reportmsg['cateid']);
+            $this->data['version']['reportid'] = $reportmsg['reportid'];
+            $this->data['version']['reportname'] = $reportmsg['reportname'];
+            $this->data['version']['reportcate'] = $reportcate;
+            $this->data['version']['itemname'] = $itemname;
+            $this->data['version']['parentname'] = $parentname;
+            $this->data['version']['catename'] = $catename;
+
+            Doo::loadModel('log');
+//            $log = new Log();
+//            $log->verid = $this->params['verid'];
+//            $log->reportid = $versionmsg['reportid'];
+//            $log->userid = $this->data['uid'];
+//            $log->addtime = time();
+//            $log->content = date('Y-m-d H:i:s',time()).' '.$this->data['username'].' 编辑';
+//            $log->insert();
+
+            $log2 = new Log();
+            $loglist = $log2->getListbyverid($this->params['verid']);
+            $this->data['loglist'] = $loglist;
+
+            if(isset($_GET['status']) && $_GET['status'] == 'new'){
+                $this->data['status'] = 1;
+            }
+            $this->render('edit-formver', $this->data, TRUE);
+            die;
+        }
+        return '/reportlist';
+    }
+
+    public function SetVersion(){
+        Doo::loadModel('report');
+        $report = new Report();
+        Doo::loadModel('version');
+        $version = new Version();
+        Doo::loadModel('log');
+        $log = new Log();
+        $time = isset($_POST['vername']) ? strtotime($_POST['vername']) : time();
+
+        if(isset($_POST['verid']) && !empty($version->getRowbyid($_POST['verid']))){
+            $version->verid = $_POST['verid'];
+            $version->content = trim($_POST['content']);
+//            $version->xmlheader = trim($_POST['editor']);
+            $version->xmlbody = trim($_POST['editor']);
+            $version->status = isset($_POST['caogao']) ? 1 : 2;
+            $version->edittime = time();
+            if(isset($_POST['firsttime'])){
+//                $version->addtime = $time;
+                $addtime = $time;
+
+                $report->edittime = $time;
+                $report->reportid = $_POST['reportid'];
+                $report->update();
+            }else{
+                $version2 = new Version();
+                $addtime = $version2->getvertime($_POST['verid']);
+            }
+            $version->update();
+
+            //调用定义物理路径
+            $t=DOO::conf()->SITE_PATH."jlbb/".$_POST['reportid'];
+
+            $xmlName = $_POST['verid'].'_'.date('YmdHis',$addtime).'.xml';
+
+            $editor = iconv("UTF-8", "GB2312", $_POST['editor']);
+            $xml = trim($editor);
+            $myfile = fopen($t.'/'.$xmlName, "w");
+            fwrite($myfile, $xml);
+            fclose($myfile);
+
+            $log->verid = $_POST['verid'];
+            $log->reportid = $_POST['reportid'];
+            $log->userid = $this->data['uid'];
+            $log->addtime = time();
+            if(isset($_POST['caogao'])){
+                $log->content = date('Y-m-d H:i:s',time()).' '.$this->data['username'].' 编辑并保存到草稿';
+            }elseif(isset($_POST['online'])){
+                $log->content = date('Y-m-d H:i:s',time()).' '.$this->data['username'].' 发布';
+            }else{
+                $log->content = date('Y-m-d H:i:s',time()).' '.$this->data['username'].' 修改过版本';
+            }
+            $log->insert();
+        }
+
+        return '/versionlist/'.$_POST['reportid'];
+    }
+
+    public function DelVersion(){
+        $verId = $this->params['verid'];
+        Doo::loadModel('version');
+        $version = new Version();
+        Doo::loadModel('log');
+        $log = new Log();
+
+        $reportid = $version->getreportidbyid($verId);
+        $addtime = $version->getvertime($verId);
+
+        $version->verid = $verId;
+        $version->delete();
+
+        //调整报表更新时间,防止软件接口报错
+        Doo::loadModel('report');
+        $report = new Report();
+        $reportmsg = $report->getRowbyid($reportid);
+        if($reportmsg['edittime'] == $addtime){
+            //获取本报表的最新一期版本
+            $vermsg = $version->getLastVerbyrid($reportid);
+            if(!empty($vermsg)){
+                $report->reportid = $reportid;
+                $report->edittime = $vermsg['addtime'];
+                $report->update();
+            }
+        }
+
+        include (DOO::conf()->SITE_PATH . 'protected/plugin/io.han.php');
+        $this->IoHandler = new IoHandler();
+        $t=DOO::conf()->SITE_PATH."jlbb/".$reportid;
+        $xmlName = $verId.'_'.date('YmdHis',$addtime).'.xml';
+        $this->IoHandler->DeleteFile($t.'/'.$xmlName);
+
+        $log->verid = $verId;
+        $log->delete();
+
+        return '/versionlist/'.$reportid;
+    }
+
+    //自动更新报表信息 2分钟执行一次
+    public function UpdateDataVersion(){
+        if(isset($this->params['verid']) && is_numeric($this->params['verid'])){
+            Doo::loadModel('version');
+            $version = new Version();
+            $vermsg = $version->getRowbyid($this->params['verid']);
+            if(!empty($vermsg)){
+                $version->verid = $vermsg['verid'];
+                $version->content = $_POST['content'];
+                $version->xmlbody = trim($_POST['editor']);
+                $version->edittime = time();
+                $version->update();
+
+                //调用定义物理路径
+                $t=DOO::conf()->SITE_PATH."jlbb/".$vermsg['reportid'];
+
+                $xmlName = $vermsg['verid'].'_'.date('YmdHis',$vermsg['addtime']).'.xml';
+                $editor = iconv("UTF-8", "GB2312", $_POST['editor']);
+                $xml = trim($editor);
+                $myfile = fopen($t.'/'.$xmlName, "w");
+                fwrite($myfile, $xml);
+                fclose($myfile);
+
+                exit(json_encode(array('status' => 200, 'msg' => date('Y-m-d H:i:s').' 自动保存')));
+            }
+        }
+        exit(json_encode(array('status' => 400, 'msg' => '参数有误')));
+    }
+
+    //项目管理
+    public function ItemList(){
+        Doo::loadModel('item');
+        Doo::loadHelper('DooPager');
+        $item = new Item();
+        $totalArchive = $item->count();
+        $pager = new DooPager(Doo::conf()->APP_URL . "itemlist/page", $totalArchive, 15, 10);
+        if (isset($this->params['pindex']))
+            $pager->paginate(intval($this->params['pindex']));
+        else
+            $pager->paginate(1);
+        if ($pager->limit != ' -15,15')
+            $this->data['itemlist'] = $item->getRowbylimit($pager->limit);
+        if(isset($this->data['itemlist'])){
+            foreach($this->data['itemlist'] as $k => $v){
+                Doo::loadModel('category');
+                $category = new Category();
+                $catenum = $category->count(array('where' => 'itemid='.$v['itemid']));
+                $this->data['itemlist'][$k]['catenum'] = $catenum;
+
+                Doo::loadModel('report');
+                $report = new Report();
+                $reportnum = $report->count(array('where' => 'itemid='.$v['itemid']));
+                $this->data['itemlist'][$k]['reportnum'] = $reportnum;
+            }
+        }
+        $this->data['pager'] = $pager->output;
+        $this->render ( "edit-formpoj", $this->data, TRUE);
+    }
+
+    public function AddItem(){
+        $name = $_POST['itemname'];
+        Doo::loadModel('item');
+        $item = new Item();
+        $code = $this->MadeCode();
+        $item->itemname = $name;
+        $item->code = $code;
+        $item->insert();
+
+        return '/itemlist';
+    }
+
+    public function DelItem(){
+        $itemId = $this->params['itemid'];
+        Doo::loadModel('category');
+        $category = new Category();
+        Doo::loadModel('item');
+        $catenum = $category->count(array('where' => 'itemid='.$itemId));
+        if($catenum != 0){
+            exit('该项目下包含类别,无法删除');
+        }
+        Doo::loadModel('report');
+        $report = new Report();
+        $reportnum = $report->count(array('where' => 'itemid='.$itemId));
+        if($reportnum != 0){
+            exit('该项目下包含报表,无法删除');
+        }
+
+        Doo::loadModel('item');
+        $item = new Item();
+        $item->itemid = $itemId;
+        $item->delete();
+
+        return '/itemlist';
+    }
+
+    public function UpdateItem(){
+        $itemname = $_POST['itemname'];
+        Doo::loadModel('item');
+        $item = new Item();
+        $item->itemname = $itemname;
+        $item->itemid = $_POST['itemid'];
+        $result = $item->update();
+        if($result){
+            echo 1;
+            exit;
+        }
+        exit;
+    }
+
+    //类别管理
+    public function CateList(){
+        Doo::loadHelper('DooPager');
+        Doo::loadModel('category');
+        $category = new Category();
+        if(isset($this->params['status']) && $this->params['status'] == 1){
+            //定制类别
+            $this->data['dingzhi'] = true;
+            Doo::loadModel('item');
+            $item = new Item();
+            $itemlist = $item->getAllMsg();
+            $this->data['itemlist'] = $itemlist;
+            $this->data['itemid'] = '';
+            if(isset($this->params['itemid']) && !empty($this->params['itemid'])){
+                $this->data['item'] = $item->getRowbyid($this->params['itemid']);
+                $this->data['itemid'] = $this->params['itemid'];
+                $itemid = $this->params['itemid'];
+            }else{
+                $itemid = $item->getfisrtitemid();
+                $this->data['itemid'] = $itemid;
+            }
+            $this->data['itemname'] = $item->getnamebyid($itemid);
+            $cateparentlist = $category->getparentlist($itemid);
+            $this->data['cateparentlist'] = $cateparentlist;
+            $totalArchive = $category->count(array('where' => 'itemid='.$itemid));
+            $pager = new DooPager(Doo::conf()->APP_URL . "catelist/1/item/".$itemid."/page", $totalArchive, 15, 10);
+            if (isset($this->params['pindex'])){
+                $pager->paginate(intval($this->params['pindex']));
+                $this->data['pindex'] = $this->params['pindex'];
+            } else
+                $pager->paginate(1);
+            if ($pager->limit != ' -15,15')
+                $this->data['catelist'] = $category->getRowbylimit($pager->limit,$itemid);
+            if(isset($this->data['catelist'])){
+                foreach($this->data['catelist'] as $k => $v){
+                    if($v['parentid'] == 0){
+                        $parentname = '';
+                    }else{
+                        $parentname = $category->getnamebyid($v['parentid']);
+                    }
+                    $this->data['catelist'][$k]['parentname'] = $parentname;
+                    $this->data['catelist'][$k]['hadchild'] = $category->hadChild($v['cateid']);
+                    Doo::loadModel('report');
+                    $report = new Report();
+                    $reportnum = $report->count(array('where' => 'cateid='.$v['cateid'].' or parentid='.$v['cateid']));
+                    $this->data['catelist'][$k]['reportnum'] = $reportnum;
+                }
+            }
+            $this->data['pager'] = $pager->output;
+        }else{
+            //通用类别
+            $cateparentlist = $category->getparentlist();
+            $this->data['cateparentlist'] = $cateparentlist;
+            $totalArchive = $category->count(array('where' => 'itemid=0'));
+            $pager = new DooPager(Doo::conf()->APP_URL . "catelist/page", $totalArchive, 15, 10);
+            if (isset($this->params['pindex'])){
+                $pager->paginate(intval($this->params['pindex']));
+                $this->data['pindex'] = $this->params['pindex'];
+            }else
+                $pager->paginate(1);
+            if ($pager->limit != ' -15,15')
+                $this->data['catelist'] = $category->getRowbylimit($pager->limit);
+            if(isset($this->data['catelist'])){
+                foreach($this->data['catelist'] as $k => $v){
+                    if($v['parentid'] == 0){
+                        $parentname = '';
+                    }else{
+                        $parentname = $category->getnamebyid($v['parentid']);
+                    }
+                    $this->data['catelist'][$k]['parentname'] = $parentname;
+                    $this->data['catelist'][$k]['hadchild'] = $category->hadChild($v['cateid']);
+                    Doo::loadModel('report');
+                    $report = new Report();
+                    $reportnum = $report->count(array('where' => 'cateid='.$v['cateid'].' or parentid='.$v['cateid']));
+                    $this->data['catelist'][$k]['reportnum'] = $reportnum;
+                }
+            }
+            $this->data['pager'] = $pager->output;
+        }
+        $this->render ( "edit-formcate", $this->data, TRUE);
+    }
+
+    public function AddCate(){
+        Doo::loadModel('category');
+        $category = new Category();
+        $category->catename = $_POST['catename'];
+        $category->parentid = $_POST['parentselect'];
+        $category->itemid = isset($_POST['itemselect']) ? $_POST['itemselect'] : 0;
+        $category->insert();
+        if(isset($_POST['itemselect'])){
+            return '/catelist/1/item/'.$_POST['itemselect'];
+        }else{
+            return '/catelist';
+        }
+    }
+
+    public function UpdateCate(){
+        Doo::loadModel('category');
+        $category = new Category();
+
+        $category->cateid = $_POST['cateid'];
+        $category->catename = $_POST['catename'];
+        $category->parentid = $_POST['parentselect'];
+        $category->itemid = isset($_POST['itemselect']) ? $_POST['itemselect'] : 0;
+        $category->update();
+
+        if(isset($_POST['itemselect']) && isset($_POST['itemid']) && $_POST['itemid'] != $_POST['itemselect']){
+            Doo::loadModel('category');
+            $category2 = new Category();
+            $catechildren = $category2->getchildbyparent($_POST['cateid']);
+            if(!empty($catechildren)){
+                foreach($catechildren as $k => $v){
+                    $category2->cateid = $v['cateid'];
+                    $category2->itemid = $_POST['itemselect'];
+                    $category2->update();
+                }
+            }
+        }
+
+        $returnurl = '/catelist';
+
+        if(isset($_POST['itemselect'])){
+            $returnurl .= '/1/item/'.$_POST['itemselect'];
+        }
+        if(isset($_POST['pindex'])){
+            $returnurl .= '/page/'.$_POST['pindex'];
+        }
+
+        return $returnurl;
+
+//        if(isset($_POST['itemselect']) && isset($_POST['itemid']) && $_POST['itemid'] == $_POST['itemselect'] && isset($_POST['pindex'])){
+//            return '/catelist/1/item/'.$_POST['itemselect'].'/page/'.$_POST['pindex'];
+//        }elseif(isset($_POST['itemselect']) && isset($_POST['itemid']) && $_POST['itemid'] != $_POST['itemselect'] && isset($_POST['pindex'])){
+//            return '/catelist/1/item/'.$_POST['itemselect'];
+//        }elseif(isset($_POST['itemselect']) && !isset($_POST['pindex'])){
+//            return '/catelist/1/item/'.$_POST['itemselect'];
+//        }elseif(!isset($_POST['itemselect']) && isset($_POST['pindex'])){
+//            return '/catelist/page/'.$_POST['pindex'];
+//        }else{
+//            return '/catelist';
+//        }
+
+    }
+
+    public function DelCate(){
+        $cateId = $this->params['cateid'];
+        Doo::loadModel('category');
+        $category = new Category();
+        $bool = $category->hadChild($cateId);
+        if($bool != 0){
+            exit('该类别下包含子类别,无法删除');
+        }
+
+        Doo::loadModel('report');
+        $report = new Report();
+        $reportnum = $report->count(array('where' => 'cateid='.$cateId.' or parentid='.$cateId));
+        if($reportnum != 0){
+            exit('该类别下包含报表,无法删除');
+        }
+
+        $category->cateid = $cateId;
+        $category->delete();
+
+        if(isset($this->params['itemid']) && isset($this->params['pindex'])){
+            return '/catelist/1/item/'.$this->params['itemid'].'/page/'.$this->params['pindex'];
+        }elseif(isset($this->params['itemid']) && !isset($this->params['pindex'])){
+            return '/catelist/1/item/'.$this->params['itemid'];
+        }elseif(!isset($this->params['itemid']) && isset($this->params['pindex'])){
+            return '/catelist/page/'.$this->params['pindex'];
+        }else{
+            return '/catelist';
+        }
+    }
+
+    public function CateParentList(){
+        if(isset($_GET['itemid'])) {
+            Doo::loadModel('category');
+            $category = new Category();
+            $cateparentlist = $category->getparentlist($_GET['itemid']);
+            if (!empty($cateparentlist)) {
+                echo json_encode(array('code' => 200, 'parentlist' => $cateparentlist));
+                exit;
+            }
+        }
+        echo json_encode(array('code' => 400)),
+        exit;
+    }
+
+    public function GetCateChild(){
+        if(isset($_GET['cateid'])){
+            Doo::loadModel('category');
+            $category = new Category();
+            $hadchild = $category->hadChild($_GET['cateid']);
+            if($hadchild){
+                echo true;
+                exit;
+            }
+        }
+        exit;
+    }
+
+    public function GetCateChildList(){
+        if(isset($_GET['parentid']) && $_GET['parentid'] != 0){
+            Doo::loadModel('category');
+            $category = new Category();
+            $childlist = $category->getChildList($_GET['parentid']);
+            if(!empty($childlist)){
+                echo json_encode(array('code' => 200, 'childlist' => $childlist));
+                exit;
+            }
+        }
+        echo json_encode(array('code' => 400));
+        exit;
+    }
+
+    public function GetCateParentList(){
+        if(isset($_GET['itemid']) && $_GET['itemid'] != 0){
+            Doo::loadModel('category');
+            $category = new Category();
+            $parentlist = $category->getparentlist($_GET['itemid']);
+            if(!empty($parentlist)){
+                echo json_encode(array('code' => 200, 'parentlist' => $parentlist));
+                exit;
+            }
+        }
+        echo json_encode(array('code' => 400));
+        exit;
+    }
+
+    //随机生成6位的项目领取码
+    private function MadeCode(){
+        $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+        $code = '';
+        for($i = 0; $i < 6; $i++){
+            $index = rand(0,61);
+            var_dump($index);
+            $code .= substr($string,$index,1);
+        }
+        return $code;
+    }
+}

+ 58 - 0
protected/model/category.php

@@ -0,0 +1,58 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+/**
+ * Created by PhpStorm.
+ * User: ellisran
+ * Date: 2016/9/22
+ * Time: 16:20
+ */
+class Category extends DooModel {
+    public $cateid;
+    public $catename;
+    public $parentid;
+    public $itemid;
+
+    public $_table = 'fc_category';
+    public $_primarykey = 'cateid';
+    public $_fields = array('cateid', 'catename', 'parentid', 'itemid');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getAlllist($itemid = 0) {
+        return $this->find(array('select' => 'cateid,catename', 'where' => 'itemid='.$itemid, 'asArray' => TRUE));
+    }
+
+    public function getparentlist($itemid = 0) {
+        return $this->find(array('select' => 'cateid,catename', 'where' => 'parentid=0 and itemid='.$itemid, 'asArray' => TRUE));
+    }
+
+    public function getRowbylimit($limit,$itemid = 0) {
+        return $this->find(array('where' => 'itemid='.$itemid, 'desc' => 'cateid', 'limit' => $limit, 'asArray' => TRUE));
+    }
+
+    public function getnamebyid($id) {
+        $cate = $this->getOne(array('select' => 'catename', 'where' => 'cateid='.$id, 'asArray' => TRUE));
+        return $cate['catename'];
+    }
+
+    public function getchildbyparent($parentid) {
+        return $this->find(array('select' => 'cateid', 'where' => 'parentid='.$parentid, 'asArray' => TRUE));
+    }
+
+    public function hadChild($parentid) {
+        $total = $this->count(array('where' => 'parentid='.$parentid, 'asArray' => TRUE));
+        if($total == 0){
+            return 0;
+        }else{
+            return 1;
+        }
+    }
+
+    public function getChildList($parentid) {
+        return $this->find(array('select' => 'cateid,catename','where' => 'parentid='.$parentid, 'asArray' => TRUE));
+    }
+
+}

+ 30 - 0
protected/model/fcuser.php

@@ -0,0 +1,30 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+/**
+ * Created by PhpStorm.
+ * User: ellisran
+ * Date: 2016/9/22
+ * Time: 16:20
+ */
+class Fcuser extends DooModel {
+    public $id;
+    public $username;
+    public $password;
+
+    public $_table = 'fc_user';
+    public $_primarykey = 'id';
+    public $_fields = array('id', 'username', 'password');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getRowByUsername($data){
+        return $this->getOne(array('where' => 'username=? and password=?', 'param' => array($data['name'],$data['password']), 'asArray' => TRUE));
+    }
+
+    public function getRowByuser($username){
+        return $this->getOne(array('where' => 'username="'.$username.'"', 'asArray' => TRUE));
+    }
+}

+ 33 - 0
protected/model/hosts.php

@@ -0,0 +1,33 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+
+class Hosts extends DooModel {
+    public $id;
+    public $serverid;
+    public $hostname;
+    public $domain;
+    public $sales;
+    public $status;
+    public $webver;
+    public $softver;
+    public $created_at;
+    public $updated_at;
+
+    public $_table = 'sfu_hosts';
+    public $_primarykey = 'id';
+    public $_fields = array('id', 'serverid', 'hostname', 'domain', 'sales', 'status', 'webver', 'softver', 'created_at', 'updated_at');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getServerHosts($sql,$limit){
+        return $this->find(array('where' => $sql, 'desc' => 'id', 'limit' => $limit, 'asArray' => TRUE));
+    }
+
+    public function getRowbyID($id){
+        return $this->getOne(array('where' => 'id='.$id, 'asArray' => TRUE));
+    }
+
+}

+ 49 - 0
protected/model/item.php

@@ -0,0 +1,49 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+/**
+ * Created by PhpStorm.
+ * User: ellisran
+ * Date: 2016/9/22
+ * Time: 16:20
+ */
+class Item extends DooModel {
+    public $itemid;
+    public $itemname;
+    public $code;
+
+    public $_table = 'fc_item';
+    public $_primarykey = 'itemid';
+    public $_fields = array('itemid', 'itemname', 'code');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getRowbylimit($limit){
+        return $this->find(array('desc' => 'itemid','limit'=>$limit,'asArray' => TRUE));
+    }
+
+    public function getAllMsg(){
+        return $this->find(array('select' => 'itemid,itemname','desc' => 'itemid','asArray' => TRUE));
+    }
+
+    public function getRowbyid($id){
+        return $this->getOne(array('select' => 'itemid,itemname,code', 'where' => 'itemid='.$id, 'asArray' => TRUE));
+    }
+
+    public function getfisrtitemid(){
+        $item = $this->getOne(array('select' => 'itemid', 'desc' => 'itemid', 'limit' => 1, 'asArray' => TRUE));
+        return $item['itemid'];
+    }
+
+    public function getnamebyid($id){
+        $item = $this->getOne(array('select' => 'itemname', 'where' => 'itemid='.$id, 'asArray' => TRUE));
+        return $item['itemname'];
+    }
+
+    public function getRowbyCode($code){
+        return $this->getOne(array('select' => 'itemid,itemname,code', 'where' => 'code="'.$code.'"', 'asArray' => TRUE));
+    }
+
+}

+ 30 - 0
protected/model/log.php

@@ -0,0 +1,30 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+/**
+ * Created by PhpStorm.
+ * User: ellisran
+ * Date: 2016/9/22
+ * Time: 16:20
+ */
+class Log extends DooModel {
+    public $id;
+    public $userid;
+    public $reportid;
+    public $verid;
+    public $content;
+    public $addtime;
+
+    public $_table = 'fc_log';
+    public $_primarykey = 'id';
+    public $_fields = array('id', 'userid', 'reportid', 'verid', 'content', 'addtime');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getListbyverid($verid){
+        return $this->find(array('select' => 'content', 'where' => 'verid='.$verid,  'asc' => 'addtime', 'asArray' => TRUE));
+    }
+
+}

+ 23 - 0
protected/model/migrations.php

@@ -0,0 +1,23 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+
+class Migrations extends DooModel {
+    public $id;
+    public $serverid;
+    public $hostname;
+    public $domain;
+    public $sales;
+    public $status;
+    public $created_at;
+    public $updated_at;
+
+    public $_table = 'sfu_hosts';
+    public $_primarykey = 'id';
+    public $_fields = array('id', 'serverid', 'hostname', 'domain', 'sales', 'status', 'created_at', 'updated_at');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+}

+ 23 - 0
protected/model/passwordreset.php

@@ -0,0 +1,23 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+
+class PasswordResets extends DooModel {
+    public $id;
+    public $serverid;
+    public $hostname;
+    public $domain;
+    public $sales;
+    public $status;
+    public $created_at;
+    public $updated_at;
+
+    public $_table = 'sfu_hosts';
+    public $_primarykey = 'id';
+    public $_fields = array('id', 'serverid', 'hostname', 'domain', 'sales', 'status', 'created_at', 'updated_at');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+}

+ 56 - 0
protected/model/report.php

@@ -0,0 +1,56 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+/**
+ * Created by PhpStorm.
+ * User: ellisran
+ * Date: 2016/9/22
+ * Time: 16:20
+ */
+class Report extends DooModel {
+    public $reportid;
+    public $reportname;
+    public $areacate;
+    public $itemid;
+    public $cateid;
+    public $parentid;
+    public $userid;
+    public $edittime;
+
+    public $_table = 'fc_report';
+    public $_primarykey = 'reportid';
+    public $_fields = array('reportid', 'reportname', 'areacate', 'itemid', 'cateid', 'parentid', 'userid','edittime');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getitemRowbylimit($limit,$itemid = 0,$sort = '',$sql = ''){
+        if($sort == 'report'){
+            return $this->find(array('where' => 'itemid='.$itemid.$sql, 'asc' => 'reportname', 'limit' => $limit, 'asArray' => TRUE));
+        }else{
+            return $this->find(array('where' => 'itemid='.$itemid.$sql, 'desc' => 'edittime', 'limit' => $limit, 'asArray' => TRUE));
+        }
+    }
+
+    public function getAllitemRowbylimit($limit,$sort = ''){
+        if($sort == 'report'){
+            return $this->find(array('where' => 'itemid!=0', 'asc' => 'reportname', 'limit' => $limit, 'asArray' => TRUE));
+        }else{
+            return $this->find(array('where' => 'itemid!=0', 'desc' => 'edittime', 'limit' => $limit, 'asArray' => TRUE));
+        }
+    }
+
+    public function getcateRowbylimit($limit,$cateid = 0,$sql = '',$sort = ''){
+        if($sort == 'report') {
+            return $this->find(array('where' => 'itemid=0 and (cateid=' . $cateid . ' or parentid=' . $cateid . ')' . $sql, 'asc' => 'reportname', 'limit' => $limit, 'asArray' => TRUE));
+        }else{
+            return $this->find(array('where' => 'itemid=0 and (cateid=' . $cateid . ' or parentid=' . $cateid . ')' . $sql, 'desc' => 'edittime', 'limit' => $limit, 'asArray' => TRUE));
+        }
+    }
+
+    public function getRowbyid($id){
+        return $this->getOne(array('where' => 'reportid='.$id, 'asArray' => TRUE));
+    }
+
+}

+ 28 - 0
protected/model/servers.php

@@ -0,0 +1,28 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+
+class Servers extends DooModel {
+    public $id;
+    public $name;
+    public $ip;
+    public $created_at;
+    public $updated_at;
+
+    public $_table = 'sfu_servers';
+    public $_primarykey = 'id';
+    public $_fields = array('id', 'name', 'ip', 'created_at', 'updated_at');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getAllServer() {
+        return $this->find(array('asArray' => TRUE));
+    }
+
+    public function getRowbyID($id) {
+        return $this->getOne(array('where' => 'id='.$id, 'asArray' => TRUE));
+    }
+
+}

+ 30 - 0
protected/model/upgradelogs.php

@@ -0,0 +1,30 @@
+<?php
+
+Doo::loadCore('db/DooModel');
+
+class UpgradeLogs extends DooModel {
+    public $id;
+    public $hid;
+    public $scondition;
+    public $version;
+    public $jsondata;
+    public $created_at;
+    public $updated_at;
+
+    public $_table = 'sfu_upgradelogs';
+    public $_primarykey = 'id';
+    public $_fields = array('id', 'hid', 'scondition', 'version', 'jsondata', 'created_at', 'updated_at');
+
+    public function __construct() {
+        parent::setupModel(__CLASS__);
+    }
+
+    public function getRowLast($id){
+        return $this->getOne(array('where' => 'hid='.$id, 'desc' => 'id', 'asArray' => TRUE));
+    }
+
+    public function getRowbyhidcond($hid,$condition){
+        return $this->getOne(array('where' => 'hid=? and scondition=?', 'param' => array($hid,$condition), 'asArray' => TRUE));
+    }
+
+}

+ 0 - 0
protected/model/version.php


Some files were not shown because too many files changed in this diff