Browse Source

feat(云机分辨率): 增加分辨率修改菜单。

zengzhixiang 2 years ago
parent
commit
01e8946555
100 changed files with 10481 additions and 1146 deletions
  1. 190 108
      static/screenAndroid/WXdraw.js
  2. 190 14
      static/screenAndroid/WXtrialInterface.html
  3. 590 439
      static/screenAndroid/css/WXtrialInterface.css
  4. 173 113
      static/screenIos/WXdraw.js
  5. 204 13
      static/screenIos/WXtrialInterface.html
  6. 519 370
      static/screenIos/css/WXtrialInterface.css
  7. 67 50
      static/screenIos/decoder.js
  8. 62 39
      static/screenIos/helper.js
  9. BIN
      static/static/img/phone-size-active.png
  10. 24 0
      static/static/lib/doT-1.1.3/.eslintrc.yml
  11. 33 0
      static/static/lib/doT-1.1.3/.gitignore
  12. 8 0
      static/static/lib/doT-1.1.3/.travis.yml
  13. 24 0
      static/static/lib/doT-1.1.3/LICENSE-DOT.txt
  14. 106 0
      static/static/lib/doT-1.1.3/README.md
  15. 110 0
      static/static/lib/doT-1.1.3/benchmarks/compileBench.js
  16. 22 0
      static/static/lib/doT-1.1.3/benchmarks/genspeed.html
  17. 22 0
      static/static/lib/doT-1.1.3/benchmarks/index.html
  18. 628 0
      static/static/lib/doT-1.1.3/benchmarks/jslitmus.js
  19. 138 0
      static/static/lib/doT-1.1.3/benchmarks/templatesBench.js
  20. 140 0
      static/static/lib/doT-1.1.3/benchmarks/templating/doT.js
  21. 56 0
      static/static/lib/doT-1.1.3/benchmarks/templating/doU.js
  22. 52 0
      static/static/lib/doT-1.1.3/bin/dot-packer
  23. 21 0
      static/static/lib/doT-1.1.3/bower.json
  24. 144 0
      static/static/lib/doT-1.1.3/doT.js
  25. 1 0
      static/static/lib/doT-1.1.3/doT.min.js
  26. 56 0
      static/static/lib/doT-1.1.3/doU.js
  27. 135 0
      static/static/lib/doT-1.1.3/examples/advancedsnippet.txt
  28. 54 0
      static/static/lib/doT-1.1.3/examples/browsersample.html
  29. 19 0
      static/static/lib/doT-1.1.3/examples/customdoT.js
  30. 1 0
      static/static/lib/doT-1.1.3/examples/express/index.js
  31. 25 0
      static/static/lib/doT-1.1.3/examples/express/lib/app.js
  32. 18 0
      static/static/lib/doT-1.1.3/examples/express/lib/render/index.js
  33. 10 0
      static/static/lib/doT-1.1.3/examples/express/package.json
  34. 5 0
      static/static/lib/doT-1.1.3/examples/express/templates/dashboard.jst
  35. 34 0
      static/static/lib/doT-1.1.3/examples/express/templates/login.jst
  36. 13 0
      static/static/lib/doT-1.1.3/examples/snippet.txt
  37. 13 0
      static/static/lib/doT-1.1.3/examples/views/multidef.def.jst
  38. 2 0
      static/static/lib/doT-1.1.3/examples/views/one.def
  39. 17 0
      static/static/lib/doT-1.1.3/examples/views/two.dot.jst
  40. 21 0
      static/static/lib/doT-1.1.3/examples/withdoT.js
  41. 150 0
      static/static/lib/doT-1.1.3/index.js
  42. 54 0
      static/static/lib/doT-1.1.3/package.json
  43. 55 0
      static/static/lib/doT-1.1.3/test/conditionals.test.js
  44. 29 0
      static/static/lib/doT-1.1.3/test/defines.test.js
  45. 76 0
      static/static/lib/doT-1.1.3/test/dot.test.js
  46. 39 0
      static/static/lib/doT-1.1.3/test/iteration.test.js
  47. 59 0
      static/static/lib/doT-1.1.3/test/process.test.js
  48. 1 0
      static/static/lib/doT-1.1.3/test/templates/test.def
  49. 2 0
      static/static/lib/doT-1.1.3/test/templates/test.dot
  50. 2 0
      static/static/lib/doT-1.1.3/test/templates/test.jst
  51. 11 0
      static/static/lib/doT-1.1.3/test/util.js
  52. 20 0
      static/static/lib/swiper/LICENSE
  53. 11 0
      static/static/lib/swiper/README.md
  54. 4 0
      static/static/lib/swiper/angular/angular/src/public-api.d.ts
  55. 4 0
      static/static/lib/swiper/angular/angular/src/swiper-events.d.ts
  56. 27 0
      static/static/lib/swiper/angular/angular/src/swiper-slide.directive.d.ts
  57. 255 0
      static/static/lib/swiper/angular/angular/src/swiper.component.d.ts
  58. 9 0
      static/static/lib/swiper/angular/angular/src/swiper.module.d.ts
  59. 10 0
      static/static/lib/swiper/angular/angular/src/utils/get-params.d.ts
  60. 1 0
      static/static/lib/swiper/angular/angular/src/utils/params-list.d.ts
  61. 9 0
      static/static/lib/swiper/angular/angular/src/utils/utils.d.ts
  62. 8 0
      static/static/lib/swiper/angular/esm2020/angular/src/public-api.mjs
  63. 2 0
      static/static/lib/swiper/angular/esm2020/angular/src/swiper-events.mjs
  64. 65 0
      static/static/lib/swiper/angular/esm2020/angular/src/swiper-slide.directive.mjs
  65. 1023 0
      static/static/lib/swiper/angular/esm2020/angular/src/swiper.component.mjs
  66. 19 0
      static/static/lib/swiper/angular/esm2020/angular/src/swiper.module.mjs
  67. 47 0
      static/static/lib/swiper/angular/esm2020/angular/src/utils/get-params.mjs
  68. 118 0
      static/static/lib/swiper/angular/esm2020/angular/src/utils/params-list.mjs
  69. 52 0
      static/static/lib/swiper/angular/esm2020/angular/src/utils/utils.mjs
  70. 2 0
      static/static/lib/swiper/angular/esm2020/swiper-angular.mjs
  71. 5 0
      static/static/lib/swiper/angular/esm2020/swiper_angular.mjs
  72. 1327 0
      static/static/lib/swiper/angular/fesm2015/swiper_angular.mjs
  73. 1 0
      static/static/lib/swiper/angular/fesm2015/swiper_angular.mjs.map
  74. 1320 0
      static/static/lib/swiper/angular/fesm2020/swiper_angular.mjs
  75. 1 0
      static/static/lib/swiper/angular/fesm2020/swiper_angular.mjs.map
  76. 32 0
      static/static/lib/swiper/angular/package.json
  77. 1 0
      static/static/lib/swiper/angular/swiper-angular.d.ts
  78. 5 0
      static/static/lib/swiper/angular/swiper_angular.d.ts
  79. 46 0
      static/static/lib/swiper/components-shared/get-changed-params.js
  80. 61 0
      static/static/lib/swiper/components-shared/get-params.js
  81. 33 0
      static/static/lib/swiper/components-shared/mount-swiper.js
  82. 4 0
      static/static/lib/swiper/components-shared/params-list.js
  83. 14 0
      static/static/lib/swiper/components-shared/update-on-virtual-data.js
  84. 136 0
      static/static/lib/swiper/components-shared/update-swiper.js
  85. 53 0
      static/static/lib/swiper/components-shared/utils.js
  86. 44 0
      static/static/lib/swiper/core/breakpoints/getBreakpoint.js
  87. 6 0
      static/static/lib/swiper/core/breakpoints/index.js
  88. 85 0
      static/static/lib/swiper/core/breakpoints/setBreakpoint.js
  89. 38 0
      static/static/lib/swiper/core/check-overflow/index.js
  90. 54 0
      static/static/lib/swiper/core/classes/addClasses.js
  91. 6 0
      static/static/lib/swiper/core/classes/index.js
  92. 9 0
      static/static/lib/swiper/core/classes/removeClasses.js
  93. 656 0
      static/static/lib/swiper/core/core.js
  94. 123 0
      static/static/lib/swiper/core/defaults.js
  95. 122 0
      static/static/lib/swiper/core/events-emitter.js
  96. 97 0
      static/static/lib/swiper/core/events/index.js
  97. 13 0
      static/static/lib/swiper/core/events/onClick.js
  98. 43 0
      static/static/lib/swiper/core/events/onResize.js
  99. 35 0
      static/static/lib/swiper/core/events/onScroll.js
  100. 0 0
      static/static/lib/swiper/core/events/onTouchEnd.js

+ 190 - 108
static/screenAndroid/WXdraw.js

@@ -1,5 +1,5 @@
 //蒙版
-var canvas_bak = document.getElementById("box");
+var canvas_bak = document.getElementById('box');
 
 var winHeight = window.screen.height - window.innerHeight;
 var vowidth = window.screen.width;
@@ -8,9 +8,9 @@ var numse = window.screen.height;
 
 // 计算title top 头部 连接断开,是否准备重连?
 if (numse <= 70) {
-  var voheight = window.screen.height - winHeight - 34 - 20
+  var voheight = window.screen.height - winHeight - 34 - 20;
 } else {
-  var voheight = window.screen.height - topwinHeightDraw - 20
+  var voheight = window.screen.height - topwinHeightDraw - 20;
 }
 
 // 画笔大小
@@ -24,7 +24,8 @@ var videoWidth, videoHeight;
 var isControl = true; // 是否是观看模式
 var isAuth = parameters['authPhone']; // 是否是获取的云手机
 
-var wsss, errorTime = 0;
+var wsss,
+  errorTime = 0;
 var first = true;
 function throttle(fn, delay) {
   var flag = true;
@@ -40,20 +41,20 @@ function throttle(fn, delay) {
 }
 
 function doConnectDirectives() {
-  videoWidth = Number(resolvingPower) ? Number(resolvingPower) : 720
-  videoHeight = videoWidth === 720 ? 1280 : 1920
+  videoWidth = Number(resolvingPower) ? Number(resolvingPower) : 720;
+  videoHeight = videoWidth === 720 ? 1280 : 1920;
   wsss = new WebSocket(cUrl);
   wsss.binaryType = 'arraybuffer';
 
   wsss.onopen = function () {
     // 进入发起询问
     var pings2 = {
-      "type": "forwardMsg",
-      "data": {
-        "code": "3000",
-        "desc": "询问是否有在控制" // 可选
-      }
-    }
+      type: 'forwardMsg',
+      data: {
+        code: '3000',
+        desc: '询问是否有在控制', // 可选
+      },
+    };
     wsss.send(JSON.stringify(pings2));
   };
   wsss.onerror = function (evt) {
@@ -64,47 +65,67 @@ function doConnectDirectives() {
     }
   };
   wsss.onmessage = function (res) {
-    console.log('res', res)
-    var result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
-    console.log('result.type', result.type)
+    console.log('res', res);
+    var result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
+    console.log('result.type', result.type);
     if (result.type === 'cutting') {
       if (result.data.status === 0) {
-        $.toast('复制成功', "text");
+        $.toast('复制成功', 'text');
       } else {
-        $.toast(result.msg, "text");
+        $.toast(result.msg, 'text');
       }
-      return
+      return;
     }
-    if (result.type === 'forwardMsg' && isAuth !== 'none') {
-      if (result.data.code === 4000 || result.data.code === 3000) {
-        if (isAuth === 'huo') {
-          $.confirm("授权方已收回控制权,您进入观看屏幕模式", function () {
-            //点击确认后的回调函数
-            isControl = false;
-          }, function () {
-            isControl = false;
-            //点击取消后的回调函数
-            quit();
-          });
-        } else {
-          $.confirm("当前云手机正在授控,是否请求获取云手机控制权?", function () {
-            //点击确认后的回调函数
-            var ping = {
-              "type": "forwardMsg",
-              "data": {
-                "code": "5000",
-                "desc": "控制权限收回" // 可选
-              }
-            }
-            wsss.send(JSON.stringify(ping));
-            isControl = true;
-          }, function () {
-            //点击取消后的回调函数
-            isControl = false;
-          });
+    if (result.type === 'forwardMsg') {
+      if (isAuth !== 'none') {
+        if (result.data.code === 4000 || result.data.code === 3000) {
+          if (isAuth === 'huo') {
+            $.confirm(
+              '授权方已收回控制权,您进入观看屏幕模式',
+              function () {
+                //点击确认后的回调函数
+                isControl = false;
+              },
+              function () {
+                isControl = false;
+                //点击取消后的回调函数
+                quit();
+              },
+            );
+          } else {
+            $.confirm(
+              '当前云手机正在授控,是否请求获取云手机控制权?',
+              function () {
+                //点击确认后的回调函数
+                var ping = {
+                  type: 'forwardMsg',
+                  data: {
+                    code: '5000',
+                    desc: '控制权限收回', // 可选
+                  },
+                };
+                wsss.send(JSON.stringify(ping));
+                isControl = true;
+              },
+              function () {
+                //点击取消后的回调函数
+                isControl = false;
+              },
+            );
+          }
+          return;
         }
+        if (result.data.code === 'phoneSizeChange') {
+          console.log(result.data);
+          window.currentPhoneSize = {
+            width: result.data.width,
+            height: result.data.height,
+          };
+          return;
+        }
+        return;
       }
-      return
+      return;
     }
     if (result.type === 'payInitiateEvent') {
       var url = window.location.href;
@@ -121,93 +142,114 @@ function doConnectDirectives() {
         dataType: 'json',
         contentType: 'application/json;charset=UTF-8',
         success: function (res) {
-          if(result.data.payType === 1) { // 微信
-            if (window.__wxjs_environment === 'miniprogram') { // 小程序
+          if (result.data.payType === 1) {
+            // 微信
+            if (window.__wxjs_environment === 'miniprogram') {
+              // 小程序
               // copyUrl(result.data.payUrl);
             } else {
-              window.location.href = result.data.payUrl
+              window.location.href = result.data.payUrl;
             }
           } else {
-            window.location.href = result.data.payUrl
+            window.location.href = result.data.payUrl;
           }
         },
       });
-      return
+      return;
     }
-  }
+  };
 }
-$('body').on("click", function () {
+$('body').on('click', function () {
   draw_graph('pencil');
-})
+});
 //剪切板
-$(".upload").on("click", function () {
-  var texts = $(this).attr("data-text")
-  if (texts == "uploads") {
-    $(".mainbox").css({
-      "display": "block"
-    })
-    $(".sbox").css({
-      "display": "none"
-    })
+$('.upload').on('click', function () {
+  var texts = $(this).attr('data-text');
+  if (texts == 'uploads') {
+    $('.mainbox').css({
+      display: 'block',
+    });
+    $('.sbox').css({
+      display: 'none',
+    });
   }
-})
+});
 
 //home 控制home
-$(".botmat1img").on("click", function () {
-  var codes = $(this).attr("data-text")
-  if (codes == "home" && isControl) {
+$('.botmat1img').on('click', function () {
+  var codes = $(this).attr('data-text');
+  if (codes == 'home' && isControl) {
     wsss.send(ExexuteKeyBoard(3));
-  } else if (codes == "return" && isControl) {
+  } else if (codes == 'return' && isControl) {
     wsss.send(ExexuteKeyBoard(4));
-  } else if (codes == "gengduo" && isControl) {
+  } else if (codes == 'gengduo' && isControl) {
     wsss.send(ExexuteKeyBoard(187));
   }
-
-})
+});
 // 高清控制
-$(".PictureQuality").on("click", function () {
+$('.PictureQuality').on('click', function () {
   if (!isControl) {
-    return
+    return;
   }
-  $(this).addClass("avit").siblings().removeClass('avit')
-  var id = $(this).attr("data-id")
+  $(this).addClass('avit').siblings().removeClass('avit');
+  var id = $(this).attr('data-id');
   var buffer = makeSharpness(Number(id));
   ws.send(buffer);
-})
+});
 //画图形
 var draw_graph = function (graphType, obj) {
   //把蒙版放于画板上面
-  $("#container").css("z-index", 30);
-  $("#dedit").css("z-index", 20);
+  $('#container').css('z-index', 30);
+  $('#dedit').css('z-index', 20);
   var canDraw = false;
   //鼠标按下获取 开始xy开始画图
   var ongoingTouches = [];
   var touchstart = function (e) {
     if (!isControl) {
-      return
+      return;
     }
     $('.control-right-img').attr({
-      "data-id": "2"
-    })
-    $(".leftmains").css({
-      "right": "-4rem"
-    })
+      'data-id': '2',
+    });
+    $('.leftmains').css({
+      right: '-4rem',
+    });
     var touchfor = e.originalEvent.changedTouches; //for 的手指数组
     //是否横屏
     for (var i = 0; i < touchfor.length; i++) {
       var acrossWidthX = touchfor[i].pageY * (videoHeight / voheight);
-      var acrossHeightY = videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
+      var acrossHeightY =
+        videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
       var verticalWidthX = touchfor[i].pageX * (videoWidth / vowidth);
       var verticalHeightY = touchfor[i].pageY * (videoHeight / voheight);
       var idx = ongoingTouches.findIndex(function (ele) {
-        return ele.identifier === touchfor[i].identifier
-      })
+        return ele.identifier === touchfor[i].identifier;
+      });
       if (idx < 0) {
         ongoingTouches.push(touchfor[i]);
       }
-      var ping = resolving == 0 ?
-        { "data": { "action": 0, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
-        { "data": { "action": 0, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": verticalWidthX.toFixed(2), "y": verticalHeightY.toFixed(2) }, "type": "event" };
+      var ping =
+        resolving == 0
+          ? {
+              data: {
+                action: 0,
+                count: ongoingTouches.length,
+                pointerId: touchfor[i].identifier,
+                x: acrossWidthX.toFixed(2),
+                y: acrossHeightY.toFixed(2),
+              },
+              type: 'event',
+            }
+          : {
+              data: {
+                action: 0,
+                count: ongoingTouches.length,
+                pointerId: touchfor[i].identifier,
+                x: verticalWidthX.toFixed(2),
+                y: verticalHeightY.toFixed(2),
+              },
+              type: 'event',
+            };
       wsss.send(JSON.stringify(ping));
     }
     canDraw = true;
@@ -216,24 +258,44 @@ var draw_graph = function (graphType, obj) {
   //鼠标离开 把蒙版canvas的图片生成到canvas中
   var touchend = function (e) {
     if (!isControl) {
-      return
+      return;
     }
     var touchfor = e.originalEvent.changedTouches; //for 的手指数组
     //是否横屏
     for (var i = 0; i < touchfor.length; i++) {
       var acrossWidthX = touchfor[i].pageY * (videoHeight / voheight);
-      var acrossHeightY = videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
+      var acrossHeightY =
+        videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
       var verticalWidthX = touchfor[i].pageX * (videoWidth / vowidth);
       var verticalHeightY = touchfor[i].pageY * (videoHeight / voheight);
-      var ping = resolving == 0 ?
-        { "data": { "action": 1, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
-        { "data": { "action": 1, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": verticalWidthX.toFixed(2), "y": verticalHeightY.toFixed(2) }, "type": "event" };
+      var ping =
+        resolving == 0
+          ? {
+              data: {
+                action: 1,
+                count: ongoingTouches.length,
+                pointerId: touchfor[i].identifier,
+                x: acrossWidthX.toFixed(2),
+                y: acrossHeightY.toFixed(2),
+              },
+              type: 'event',
+            }
+          : {
+              data: {
+                action: 1,
+                count: ongoingTouches.length,
+                pointerId: touchfor[i].identifier,
+                x: verticalWidthX.toFixed(2),
+                y: verticalHeightY.toFixed(2),
+              },
+              type: 'event',
+            };
       wsss.send(JSON.stringify(ping));
       ongoingTouches.forEach(function (item, index) {
         if (item.identifier === touchfor[i].identifier) {
-          ongoingTouches.splice(index, 1)
+          ongoingTouches.splice(index, 1);
         }
-      })
+      });
     }
     canDraw = false;
   };
@@ -241,22 +303,42 @@ var draw_graph = function (graphType, obj) {
   //清空层 云手机超出屏幕的开关
   var clearContext = function () {
     canDraw = false;
-  }
+  };
 
   // 鼠标移动
   var touchmove = function (e) {
     if (!isControl) {
-      return
+      return;
     }
     var touchfor = e.originalEvent.targetTouches; //for 的手指数组
     for (var i = 0; i < touchfor.length; i++) {
       var acrossWidthX = touchfor[i].pageY * (videoHeight / voheight);
-      var acrossHeightY = videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
+      var acrossHeightY =
+        videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
       var verticalWidthX = touchfor[i].pageX * (videoWidth / vowidth);
       var verticalHeightY = touchfor[i].pageY * (videoHeight / voheight);
-      var ping = resolving == 0 ?
-        { "data": { "action": 2, "count": touchfor.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
-        { "data": { "action": 2, "count": touchfor.length, "pointerId": touchfor[i].identifier, "x": verticalWidthX.toFixed(2), "y": verticalHeightY.toFixed(2) }, "type": "event" };
+      var ping =
+        resolving == 0
+          ? {
+              data: {
+                action: 2,
+                count: touchfor.length,
+                pointerId: touchfor[i].identifier,
+                x: acrossWidthX.toFixed(2),
+                y: acrossHeightY.toFixed(2),
+              },
+              type: 'event',
+            }
+          : {
+              data: {
+                action: 2,
+                count: touchfor.length,
+                pointerId: touchfor[i].identifier,
+                x: verticalWidthX.toFixed(2),
+                y: verticalHeightY.toFixed(2),
+              },
+              type: 'event',
+            };
       wsss.send(JSON.stringify(ping));
     }
   };
@@ -266,24 +348,24 @@ var draw_graph = function (graphType, obj) {
     if (graphType != 'handwriting') {
       clearContext();
     }
-  }
+  };
 
   $(canvas_bak).unbind();
   $(canvas_bak).bind('touchstart', touchstart);
   $(canvas_bak).bind('touchmove', touchmove);
   $(canvas_bak).bind('touchend', touchend);
   $(canvas_bak).bind('mouseout', mouseout);
-}
+};
 
 // 获取url中"?"符后的字串
 function GetRequest() {
   var url = location.search;
   var obj = new Object();
-  if (url.indexOf("?") != -1) {
+  if (url.indexOf('?') != -1) {
     var str = url.substr(1);
-    strs = str.split("&");
+    strs = str.split('&');
     for (var i = 0; i < strs.length; i++) {
-      obj[strs[i].split("=")[0]] = (strs[i].split("=")[1]);
+      obj[strs[i].split('=')[0]] = strs[i].split('=')[1];
     }
   }
   return obj;

+ 190 - 14
static/screenAndroid/WXtrialInterface.html

@@ -42,9 +42,21 @@
       rel="stylesheet"
       href="https://cdn.bootcss.com/jquery-weui/1.2.1/css/jquery-weui.min.css"
     />
+    <script src="../static/lib/doT-1.1.3/doT.min.js"></script>
   </head>
 
   <body class="scroll h-player" style="overscroll-behavior: contain">
+    <template id="template-phone-size-item">
+      {{~ it.list :value:index }}
+      <div
+        class="phone-size-item {{? value.width === it.active.width && value.height === it.active.height }}active{{?}}"
+        data-width="{{= value.width }}"
+        data-height="{{= value.height }}"
+      >
+        <span>{{= value.width }}x{{= value.height }}</span>
+      </div>
+      {{~}}
+    </template>
     <div class="container" id="player">
       <div class="muted" id="btnMuted">
         <div class="control-right-img" data-id="1">
@@ -80,9 +92,14 @@
       </div>
       <div class="leftmains">
         <div class="PictureQualityMain">
-          <div class="PictureQuality" data-id="4">高清</div>
-          <div class="PictureQuality avit" data-id="3">标清</div>
-          <div class="PictureQuality" data-id="2">极速</div>
+          <div class="menu-btn PictureQuality" data-id="4">高清</div>
+          <div class="menu-btn PictureQuality avit" data-id="3">标清</div>
+          <div class="menu-btn PictureQuality" data-id="2">极速</div>
+        </div>
+        <div class="">
+          <div class="menu-btn" id="open-set-phone-size-dialog-btn">
+            <span>分辨率</span>
+          </div>
         </div>
         <div class="operation">
           <div class="upload" id="showsuss" data-text="uploads">
@@ -172,7 +189,26 @@
       </div>
     </div>
 
-    <body oncontextmenu="Back()"></body>
+    <!-- <body oncontextmenu="Back()"></body> -->
+    <div id="set-phone-size-dialog" class="dialog">
+      <div class="dialog-mask"></div>
+      <!-- 设置分辨率的弹窗 -->
+      <div class="dialog-content-border">
+        <div class="dialog-content">
+          <div class="dialog-header">
+            <div class="dialog-btn cancel">
+              <span>取消</span>
+            </div>
+            <div class="dialog-btn confirm">
+              <span>确定</span>
+            </div>
+          </div>
+          <div class="dialog-main">
+            <div id="phone-size-list"></div>
+          </div>
+        </div>
+      </div>
+    </div>
     <script
       type="text/javascript"
       src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"
@@ -217,10 +253,10 @@
         /^192\.168\./.test(location.host) ||
         /^127\.0\.0\.1/.test(location.host) ||
         /^localhost/.test(location.host);
-      if (isDev) {
-        baseUrl = 'http://gntest.phone.androidscloud.com:1280';
-        sourceType = 2;
-      }
+      // if (isDev) {
+      //   baseUrl = 'http://gntest.phone.androidscloud.com:1280';
+      //   sourceType = 2;
+      // }
       if (parameters['mealType'] === 'VIP') {
         $('.loading_sceen_pic').attr('src', '../static/img/home_bg_VIP.png');
       } else if (parameters['mealType'] === 'SVIP') {
@@ -592,7 +628,7 @@
               ws.close();
               wsss.close();
               uni.webView.navigateBack({
-                delta: 1
+                delta: 1,
               });
             }
           }
@@ -1397,9 +1433,12 @@
       // 观看广告次数上报
       function reportFrequency() {
         $.ajax({
-          url: baseUrl + '/api/resoures/v1/trial/reportFrequency/' + form.userCardId,
+          url:
+            baseUrl +
+            '/api/resoures/v1/trial/reportFrequency/' +
+            form.userCardId,
           headers: {
-            Authorization: form.token
+            Authorization: form.token,
           },
           type: 'post',
           contentType: 'application/json',
@@ -1409,8 +1448,8 @@
       }
       //关闭广告
       $('.time-close-wrap')[0].addEventListener('click', () => {
-        if(videoTime == 0) {
-          reportFrequency()
+        if (videoTime == 0) {
+          reportFrequency();
         }
         $('.buy-phone-wrap').eq(0).show();
       });
@@ -1518,7 +1557,7 @@
           });
         } else {
           uni.webView.navigateBack({
-	          delta: 1
+            delta: 1,
           });
         }
       }
@@ -1526,6 +1565,143 @@
         ws.close();
         wsss.close();
       };
+      function updatePhoneSizeListHtml() {
+        const templatePhoneSizeItem = doT.template(
+          $('#template-phone-size-item').html().replace(/&amp;/g, '&'),
+        );
+        const phoneSizeListItemsHtml = templatePhoneSizeItem({
+          list: window.phoneSizeList,
+          active: window.activePhoneSize,
+        });
+        $('#phone-size-list').html(phoneSizeListItemsHtml);
+      }
+      $('#open-set-phone-size-dialog-btn').on('click', function (e) {
+        window.activePhoneSize = window.currentPhoneSize;
+        updatePhoneSizeListHtml();
+        $('#set-phone-size-dialog').addClass('show');
+      });
+      // $('#set-phone-size-dialog').addClass('show');
+      $('.dialog .dialog-mask')
+        .add('.dialog .dialog-btn.cancel')
+        .on('click', function (e) {
+          $(e.currentTarget).parents('.dialog').removeClass('show');
+        });
+
+      function getPhoneSizeList() {
+        $.ajax({
+          url: baseUrl + '/api/public/v5/shear/content',
+          headers: {
+            Authorization: token,
+          },
+          type: 'get',
+          dataType: 'json',
+        });
+      }
+      // 分辨率列表
+      window.phoneSizeList = [];
+      // 当前生效的分辨率
+      window.currentPhoneSize = {
+        width: 720,
+        height: 1280,
+      };
+      // 选中的分辨率
+      window.activePhoneSize = window.currentPhoneSize;
+
+      function getPhoneSizeList() {
+        return $.ajax({
+          url: baseUrl + '/api/public/config/switch/getValue/toJSONObject',
+          headers: {
+            Authorization: token,
+          },
+          type: 'get',
+          dataType: 'json',
+          data: {
+            configKey: 'cloud_phone_resolving_power',
+          },
+        }).then(function (response) {
+          return response.data.map(function (v) {
+            return {
+              width: v.width || v.abscissa,
+              height: v.height || v.ordinate,
+            };
+          });
+          // [
+          //   // { width: 320, height: 240 },
+          //   // { width: 640, height: 480 },
+          //   { width: 375, height: 812 },
+          //   { width: 720, height: 1280 },
+
+          //   // { width: 1280, height: 720 },
+          //   // { width: 1080, height: 1920 },
+          // ];
+        });
+      }
+
+      getPhoneSizeList().then(function (phoneSizeList) {
+        window.phoneSizeList = phoneSizeList;
+        return updatePhoneSizeListHtml();
+      });
+
+      // const phoneSizeListSwiper = new Swiper('#phone-size-list-swiper', {
+      //   direction: 'vertical',
+      //   slidesPerView: 'auto',
+      //   loop: false,
+      //   centeredSlides: true,
+      // });
+      function setPhoneSize(config) {
+        $.ajax({
+          url:
+            baseUrl +
+            '/api/resources/v5/machine/resolution/operationResolvingPower',
+          headers: {
+            Authorization: token,
+          },
+          type: 'post',
+          dataType: 'json',
+          data: {
+            userCardId: window.userCardId,
+            width: config.width,
+            height: config.height,
+          },
+        });
+        wsss.send(
+          JSON.stringify({
+            type: 'setPhoneSize',
+            data: {
+              width: config.width,
+              height: config.height,
+            },
+          }),
+        );
+        wsss.send(
+          JSON.stringify({
+            type: 'forwardMsg',
+            data: {
+              code: 'phoneSizeChange',
+              width: config.width,
+              height: config.height,
+              desc: '分辨率修改', // 可选
+            },
+          }),
+        );
+        window.currentPhoneSize = config;
+      }
+      // wsss.addEventListener('message', function (event) {
+      //   console.log(
+      //     '🚀 ~ file: WXtrialInterface.html ~ line 1476 ~ event',
+      //     event,
+      //   );
+      // });
+      $('#phone-size-list').on('click', '.phone-size-item', function (e) {
+        const data = $(e.currentTarget).data();
+        window.activePhoneSize = data;
+        updatePhoneSizeListHtml();
+        // setPhoneSize(data.width, data.height);
+      });
+      $('#set-phone-size-dialog .dialog-btn.confirm').on('click', function (e) {
+        setPhoneSize(window.activePhoneSize);
+        $('#set-phone-size-dialog').removeClass('show');
+      });
     </script>
     <script type="text/javascript" src="WXdraw.js"></script>
     <script type="text/javascript" src="aac.js"></script>

File diff suppressed because it is too large
+ 590 - 439
static/screenAndroid/css/WXtrialInterface.css


+ 173 - 113
static/screenIos/WXdraw.js

@@ -1,15 +1,15 @@
 // 蒙版
-var canvas_bak = document.getElementById("box");;
+var canvas_bak = document.getElementById('box');
 
 var winHeight = window.screen.height - window.innerHeight;
 var vowidth = window.screen.width;
 var topwinHeightDraw = window.screen.height - window.innerHeight + 30; //计算title top 头部
-var numse = window.screen.height // -winHeight
+var numse = window.screen.height; // -winHeight
 //计算title top 头部
 if (numse <= 70) {
-  var voheight = window.screen.height - winHeight - 34 - 20
+  var voheight = window.screen.height - winHeight - 34 - 20;
 } else {
-  var voheight = window.screen.height - topwinHeightDraw - 20
+  var voheight = window.screen.height - topwinHeightDraw - 20;
 }
 
 //画笔大小
@@ -40,30 +40,30 @@ function throttle(fn, delay) {
 }
 
 function doConnectDirectives() {
-  videoWidth = Number(resolvingPower) ? Number(resolvingPower) : 720
-  videoHeight = videoWidth === 720 ? 1280 : 1920
+  videoWidth = Number(resolvingPower) ? Number(resolvingPower) : 720;
+  videoHeight = videoWidth === 720 ? 1280 : 1920;
   wsss = new WebSocket(cUrl);
   wsss.binaryType = 'arraybuffer';
 
   wsss.onopen = function () {
     // 获取虚拟场景状态
-    var pings = { "type": "getVsStatus" }
+    var pings = { type: 'getVsStatus' };
     wsss.send(JSON.stringify(pings));
     var bitRate = {
-      "data": {
-        "bitRate": 1243000
+      data: {
+        bitRate: 1243000,
       },
-      "type": "bitRate"
-    }
+      type: 'bitRate',
+    };
     wsss.send(JSON.stringify(bitRate));
     // 进入发起询问
     var pings2 = {
-      "type": "forwardMsg",
-      "data": {
-        "code": "3000",
-        "desc": "询问是否有在控制" // 可选
-      }
-    }
+      type: 'forwardMsg',
+      data: {
+        code: '3000',
+        desc: '询问是否有在控制', // 可选
+      },
+    };
     wsss.send(JSON.stringify(pings2));
   };
   wsss.onerror = function () {
@@ -74,45 +74,70 @@ function doConnectDirectives() {
     }
   };
   wsss.onmessage = function (res) {
-    var result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
+    var result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
+    console.log(
+      '🚀 ~ file: WXdraw.js ~ line 78 ~ doConnectDirectives ~ result',
+      result,
+    );
+
     if (result.type === 'cutting') {
       if (result.data.status === 0) {
-        $.toast('复制成功', "text");
+        $.toast('复制成功', 'text');
       } else {
-        $.toast(result.msg, "text");
+        $.toast(result.msg, 'text');
       }
-      return
+      return;
     }
-    if (result.type === 'forwardMsg' && isAuth !== 'none') {
-      if (result.data.code === 4000 || result.data.code === 3000) {
-        if (isAuth === 'huo') {
-          $.confirm("授权方已收回控制权,您进入观看屏幕模式", function () {
-            //点击确认后的回调函数
-            isControl = false;
-          }, function () {
-            isControl = false;
-            //点击取消后的回调函数
-            quit();
-          });
-        } else {
-          $.confirm("当前云手机正在授控,是否请求获取云手机控制权?", function () {
-            //点击确认后的回调函数
-            var ping = {
-              "type": "forwardMsg",
-              "data": {
-                "code": "5000",
-                "desc": "控制权限收回" // 可选
-              }
-            }
-            wsss.send(JSON.stringify(ping));
-            isControl = true;
-          }, function () {
-            //点击取消后的回调函数
-            isControl = false;
-          });
+    if (result.type === 'forwardMsg') {
+      if (isAuth !== 'none') {
+        if (result.data.code === 4000 || result.data.code === 3000) {
+          if (isAuth === 'huo') {
+            $.confirm(
+              '授权方已收回控制权,您进入观看屏幕模式',
+              function () {
+                //点击确认后的回调函数
+                isControl = false;
+              },
+              function () {
+                isControl = false;
+                //点击取消后的回调函数
+                quit();
+              },
+            );
+          } else {
+            $.confirm(
+              '当前云手机正在授控,是否请求获取云手机控制权?',
+              function () {
+                //点击确认后的回调函数
+                var ping = {
+                  type: 'forwardMsg',
+                  data: {
+                    code: '5000',
+                    desc: '控制权限收回', // 可选
+                  },
+                };
+                wsss.send(JSON.stringify(ping));
+                isControl = true;
+              },
+              function () {
+                //点击取消后的回调函数
+                isControl = false;
+              },
+            );
+          }
+          return;
         }
+        return;
+      }
+      if (result.data.code === 'phoneSizeChange') {
+        console.log(result.data);
+        window.currentPhoneSize = {
+          width: result.data.width,
+          height: result.data.height,
+        };
+        return;
       }
-      return
+      return;
     }
     if (result.type === 'payInitiateEvent') {
       var url = window.location.href;
@@ -129,98 +154,111 @@ function doConnectDirectives() {
         dataType: 'json',
         contentType: 'application/json;charset=UTF-8',
         success: function (res) {
-          if(result.data.payType === 1) { // 微信
-            if (window.__wxjs_environment === 'miniprogram') { // 小程序
+          if (result.data.payType === 1) {
+            // 微信
+            if (window.__wxjs_environment === 'miniprogram') {
+              // 小程序
               // copyUrl(result.data.payUrl);
             } else {
-              window.location.href = result.data.payUrl
+              window.location.href = result.data.payUrl;
             }
           } else {
-            window.location.href = result.data.payUrl
+            window.location.href = result.data.payUrl;
           }
         },
       });
-      return
+      return;
     }
-  }
+  };
 }
-$('body').on("click", function () {
-  draw_graph('pencil', this)
-})
+$('body').on('click', function () {
+  draw_graph('pencil', this);
+});
 //剪切板
-$(".upload").on("click", function () {
-  var texts = $(this).attr("data-text")
-  if (texts == "uploads") {
-    $(".mainbox").css({
-      "display": "block"
-    })
-    $(".sbox").css({
-      "display": "none"
-    })
+$('.upload').on('click', function () {
+  var texts = $(this).attr('data-text');
+  if (texts == 'uploads') {
+    $('.mainbox').css({
+      display: 'block',
+    });
+    $('.sbox').css({
+      display: 'none',
+    });
   }
-})
+});
 
 //home 控制home
-$(".botmat1img").on("click", function () {
-  var codes = $(this).attr("data-text")
-  if (codes == "home" && isControl) {
+$('.botmat1img').on('click', function () {
+  var codes = $(this).attr('data-text');
+  if (codes == 'home' && isControl) {
     wsss.send(ExexuteKeyBoard(3));
-  } else if (codes == "return" && isControl) {
+  } else if (codes == 'return' && isControl) {
     wsss.send(ExexuteKeyBoard(4));
-  } else if (codes == "gengduo" && isControl) {
+  } else if (codes == 'gengduo' && isControl) {
     wsss.send(ExexuteKeyBoard(187));
   }
-})
+});
 // 高清控制
-$(".PictureQuality").on("click", function () {
+$('.PictureQuality').on('click', function () {
   if (!isControl) {
-    return
+    return;
   }
-  $(this).addClass("avit").siblings().removeClass('avit')
-  var id = $(this).attr("data-id")
+  $(this).addClass('avit').siblings().removeClass('avit');
+  var id = $(this).attr('data-id');
   var cmd = {
-    type: "switchSharpness",
+    type: 'switchSharpness',
   };
 
-  decodeWoker.postMessage(cmd);//通知解码器worker切换分辨率		
+  decodeWoker.postMessage(cmd); //通知解码器worker切换分辨率
   var buffer = makeSharpness(Number(id));
   webSocketWorker.postMessage(buffer);
-})
+});
 var canDraw = false;
 //画图形
 var draw_graph = function (graphType) {
   //把蒙版放于画板上面
-  $("#container").css("z-index", 30);
-  $("#dedit").css("z-index", 20);
+  $('#container').css('z-index', 30);
+  $('#dedit').css('z-index', 20);
   // 先画在蒙版上 再复制到画布上
   //鼠标按下获取 开始xy开始画图
   var ongoingTouches = [];
   var touchstart = function (e) {
     if (!isControl) {
-      return
+      return;
     }
     $('.control-right-img').attr({
-      "data-id": "2"
-    })
-    $(".leftmains").css({
-      "right": "-4rem"
-    })
+      'data-id': '2',
+    });
+    $('.leftmains').css({
+      right: '-4rem',
+    });
     var touchfor = e.originalEvent.changedTouches; //for 的手指数组
     //是否横屏
     for (var i = 0; i < touchfor.length; i++) {
       var acrossWidthX = touchfor[i].pageY * (videoHeight / voheight);
-      var acrossHeightY = videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
+      var acrossHeightY =
+        videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
       var verticalWidthX = touchfor[i].pageX * (videoWidth / vowidth);
       var verticalHeightY = touchfor[i].pageY * (videoHeight / voheight);
       var idx = ongoingTouches.findIndex(function (ele) {
-        return ele.identifier === touchfor[i].identifier
-      })
+        return ele.identifier === touchfor[i].identifier;
+      });
       if (idx < 0) {
         ongoingTouches.push(touchfor[i]);
       }
-      var ping = resolving == 0 ?
-        { "data": { "action": 0, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
-        { "data": { "action": 0, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": verticalWidthX.toFixed(2), "y": verticalHeightY.toFixed(2) }, "type": "event" };
+      var ping =
+        //  resolving == 0 ?
+        //   { "data": { "action": 0, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
+        {
+          data: {
+            action: 0,
+            count: ongoingTouches.length,
+            pointerId: touchfor[i].identifier,
+            x: verticalWidthX.toFixed(2),
+            y: verticalHeightY.toFixed(2),
+          },
+          type: 'event',
+        };
       wsss.send(JSON.stringify(ping));
     }
     canDraw = true;
@@ -229,24 +267,35 @@ var draw_graph = function (graphType) {
   //鼠标离开 把蒙版canvas的图片生成到canvas中
   var touchend = function (e) {
     if (!isControl) {
-      return
+      return;
     }
     var touchfor = e.originalEvent.changedTouches; //for 的手指数组
     //是否横屏
     for (var i = 0; i < touchfor.length; i++) {
       var acrossWidthX = touchfor[i].pageY * (videoHeight / voheight);
-      var acrossHeightY = videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
+      var acrossHeightY =
+        videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
       var verticalWidthX = touchfor[i].pageX * (videoWidth / vowidth);
       var verticalHeightY = touchfor[i].pageY * (videoHeight / voheight);
-      var ping = resolving == 0 ?
-        { "data": { "action": 1, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
-        { "data": { "action": 1, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": verticalWidthX.toFixed(2), "y": verticalHeightY.toFixed(2) }, "type": "event" };
+      var ping =
+        // resolving == 0 ?
+        //   { "data": { "action": 1, "count": ongoingTouches.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
+        {
+          data: {
+            action: 1,
+            count: ongoingTouches.length,
+            pointerId: touchfor[i].identifier,
+            x: verticalWidthX.toFixed(2),
+            y: verticalHeightY.toFixed(2),
+          },
+          type: 'event',
+        };
       wsss.send(JSON.stringify(ping));
       ongoingTouches.forEach(function (item, index) {
         if (item.identifier === touchfor[i].identifier) {
-          ongoingTouches.splice(index, 1)
+          ongoingTouches.splice(index, 1);
         }
-      })
+      });
     }
     canDraw = false;
   };
@@ -254,22 +303,33 @@ var draw_graph = function (graphType) {
   //清空层 云手机超出屏幕的开关
   var clearContext = function () {
     canDraw = false;
-  }
+  };
 
   // 鼠标移动
   var touchmove = function (e) {
     if (!isControl) {
-      return
+      return;
     }
     var touchfor = e.originalEvent.targetTouches; //for 的手指数组
     for (var i = 0; i < touchfor.length; i++) {
       var acrossWidthX = touchfor[i].pageY * (videoHeight / voheight);
-      var acrossHeightY = videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
+      var acrossHeightY =
+        videoWidth - touchfor[i].pageX * (videoWidth / vowidth);
       var verticalWidthX = touchfor[i].pageX * (videoWidth / vowidth);
       var verticalHeightY = touchfor[i].pageY * (videoHeight / voheight);
-      var ping = resolving == 0 ?
-        { "data": { "action": 2, "count": touchfor.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
-        { "data": { "action": 2, "count": touchfor.length, "pointerId": touchfor[i].identifier, "x": verticalWidthX.toFixed(2), "y": verticalHeightY.toFixed(2) }, "type": "event" };
+      var ping =
+        // resolving == 0 ?
+        //   { "data": { "action": 2, "count": touchfor.length, "pointerId": touchfor[i].identifier, "x": acrossWidthX.toFixed(2), "y": acrossHeightY.toFixed(2) }, "type": "event" } :
+        {
+          data: {
+            action: 2,
+            count: touchfor.length,
+            pointerId: touchfor[i].identifier,
+            x: verticalWidthX.toFixed(2),
+            y: verticalHeightY.toFixed(2),
+          },
+          type: 'event',
+        };
       wsss.send(JSON.stringify(ping));
     }
   };
@@ -279,22 +339,22 @@ var draw_graph = function (graphType) {
     if (graphType != 'handwriting') {
       clearContext();
     }
-  }
+  };
   $(canvas_bak).unbind();
   $(canvas_bak).bind('touchstart', touchstart);
   $(canvas_bak).bind('touchmove', touchmove);
   $(canvas_bak).bind('touchend', touchend);
   $(canvas_bak).bind('mouseout', mouseout);
-}
+};
 
 function GetRequest() {
   var url = location.search; // 获取url中"?"符后的字串
   var obj = new Object();
-  if (url.indexOf("?") != -1) {
+  if (url.indexOf('?') != -1) {
     var str = url.substr(1);
-    strs = str.split("&");
+    strs = str.split('&');
     for (var i = 0; i < strs.length; i++) {
-      obj[strs[i].split("=")[0]] = (strs[i].split("=")[1]);
+      obj[strs[i].split('=')[0]] = strs[i].split('=')[1];
     }
   }
   return obj;

+ 204 - 13
static/screenIos/WXtrialInterface.html

@@ -43,9 +43,23 @@
       rel="stylesheet"
       href="https://cdn.bootcss.com/jquery-weui/1.2.1/css/jquery-weui.min.css"
     />
+    <!-- <link rel="stylesheet" href="../static/lib/swiper/swiper-bundle.min.css" />
+    <script src="../static/lib/swiper/swiper-bundle.js"></script> -->
+    <script src="../static/lib/doT-1.1.3/doT.min.js"></script>
   </head>
 
   <body class="scroll h-player" style="overscroll-behavior: contain">
+    <template id="template-phone-size-item">
+      {{~ it.list :value:index }}
+      <div
+        class="phone-size-item {{? value.width === it.active.width && value.height === it.active.height }}active{{?}}"
+        data-width="{{= value.width }}"
+        data-height="{{= value.height }}"
+      >
+        <span>{{= value.width }}x{{= value.height }}</span>
+      </div>
+      {{~}}
+    </template>
     <div class="container" id="player">
       <div class="muted" id="btnMuted">
         <div class="control-right-img" data-id="1">
@@ -59,15 +73,24 @@
       </div>
       <div class="leftmains">
         <div class="PictureQualityMain">
-          <div class="PictureQuality" data-id="4">高清</div>
-          <div class="PictureQuality avit" data-id="3">标清</div>
-          <div class="PictureQuality" data-id="2">极速</div>
+          <div class="menu-btn PictureQuality" data-id="4">高清</div>
+          <div class="menu-btn PictureQuality avit" data-id="3">标清</div>
+          <div class="menu-btn PictureQuality" data-id="2">极速</div>
+        </div>
+        <div class="">
+          <div class="menu-btn" id="open-set-phone-size-dialog-btn">
+            <span>分辨率</span>
+          </div>
         </div>
         <div class="operation">
           <div class="upload" id="showsuss" data-text="uploads">
             <img src="../static/img/wx/shangchuan_icon.png" />
             <div>上传</div>
           </div>
+          <!-- <div class="upload" id="open-set-phone-size-dialog-btn">
+            <img src="../static/img/wx/jianqieban_icon.png" />
+            <div>分辨率</div>
+          </div> -->
           <div class="upload" onclick="showShearPlate()" data-text="Shearplate">
             <img src="../static/img/wx/jianqieban_icon.png" />
             <div>剪贴板</div>
@@ -149,6 +172,26 @@
         </div>
       </div>
     </div>
+
+    <div id="set-phone-size-dialog" class="dialog">
+      <div class="dialog-mask"></div>
+      <!-- 设置分辨率的弹窗 -->
+      <div class="dialog-content-border">
+        <div class="dialog-content">
+          <div class="dialog-header">
+            <div class="dialog-btn cancel">
+              <span>取消</span>
+            </div>
+            <div class="dialog-btn confirm">
+              <span>确定</span>
+            </div>
+          </div>
+          <div class="dialog-main">
+            <div id="phone-size-list"></div>
+          </div>
+        </div>
+      </div>
+    </div>
     <script
       type="text/javascript"
       src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"
@@ -254,10 +297,10 @@
       // 开发环境
       var isDev =
         /^192\.168\./.test(location.host) || /^localhost/.test(location.host);
-      if (isDev) {
-        baseUrl = 'http://gntest.phone.androidscloud.com:1280';
-        sourceType = 2;
-      }
+      // if (isDev) {
+      //   baseUrl = 'http://gntest.phone.androidscloud.com:1280';
+      //   sourceType = 2;
+      // }
 
       var topwinHeight = window.screen.height - window.innerHeight + 30; //计算title top 头部
       var url = window.location.href;
@@ -269,7 +312,7 @@
       var token = parameters['token'];
       var mealType = parameters['mealType'];
       var userCardId = parameters['userCardId'];
-      
+
       var videoTimer = null,
         videoTime = 0,
         adType = 0,
@@ -883,10 +926,13 @@
           case 0:
             break;
           case 1:
+            // console.log(objData);
             if (logicWidth != objData.width || logicHeight != objData.height) {
               logicWidth = objData.width;
               logicHeight = objData.height;
             }
+            // logicWidth = 375
+            // logicHeight = 812
             webglPlayer.renderFrame(
               objData.data,
               logicWidth,
@@ -928,6 +974,7 @@
             '&cardToken=' +
             encodeURIComponent(cardToken),
         );
+        window.webSocketWorker = webSocketWorker;
         webSocketWorker.onmessage = function (event) {
           var input = event.data;
           if (input[0] == 0xff && isAudioPlay) {
@@ -963,10 +1010,12 @@
                 console.log('安卓卡此时竖屏');
                 //竖屏处理
                 resolving = 1;
+                $('#playCanvas').removeClass('horizontal').addClass('vertical');
               } else {
                 console.log('安卓卡此时横屏');
                 //横屏处理
                 resolving = 0;
+                $('#playCanvas').removeClass('vertical').addClass('horizontal');
               }
             }
             if (input[23] == 0x0b) {
@@ -1175,9 +1224,12 @@
       // 观看广告次数上报1
       function reportFrequency() {
         $.ajax({
-          url: baseUrl + '/api/resoures/v1/trial/reportFrequency/' + form.userCardId,
+          url:
+            baseUrl +
+            '/api/resoures/v1/trial/reportFrequency/' +
+            form.userCardId,
           headers: {
-            Authorization: form.token
+            Authorization: form.token,
           },
           type: 'post',
           contentType: 'application/json',
@@ -1204,8 +1256,8 @@
       }
       //关闭广告
       $('.time-close-wrap')[0].addEventListener('click', () => {
-        if(videoTime == 0) {
-          reportFrequency()
+        if (videoTime == 0) {
+          reportFrequency();
         }
         $('.buy-phone-wrap').eq(0).show();
       });
@@ -1295,10 +1347,149 @@
           });
         } else {
           uni.webView.navigateBack({
-	          delta: 1
+            delta: 1,
           });
         }
       }
+
+      function updatePhoneSizeListHtml() {
+        const templatePhoneSizeItem = doT.template(
+          $('#template-phone-size-item').html().replace(/&amp;/g, '&'),
+        );
+        const phoneSizeListItemsHtml = templatePhoneSizeItem({
+          list: window.phoneSizeList,
+          active: window.activePhoneSize,
+        });
+        $('#phone-size-list').html(phoneSizeListItemsHtml);
+      }
+
+      $('#open-set-phone-size-dialog-btn').on('click', function (e) {
+        window.activePhoneSize = window.currentPhoneSize;
+        updatePhoneSizeListHtml();
+        $('#set-phone-size-dialog').addClass('show');
+      });
+      // $('#set-phone-size-dialog').addClass('show');
+      $('.dialog .dialog-mask')
+        .add('.dialog .dialog-btn.cancel')
+        .on('click', function (e) {
+          $(e.currentTarget).parents('.dialog').removeClass('show');
+        });
+
+      function getPhoneSizeList() {
+        $.ajax({
+          url: baseUrl + '/api/public/v5/shear/content',
+          headers: {
+            Authorization: token,
+          },
+          type: 'get',
+          dataType: 'json',
+        });
+      }
+      // 分辨率列表
+      window.phoneSizeList = [];
+      // 当前生效的分辨率
+      window.currentPhoneSize = {
+        width: 720,
+        height: 1280,
+      };
+      // 选中的分辨率
+      window.activePhoneSize = window.currentPhoneSize;
+
+      function getPhoneSizeList() {
+        return $.ajax({
+          url: baseUrl + '/api/public/config/switch/getValue/toJSONObject',
+          headers: {
+            Authorization: token,
+          },
+          type: 'get',
+          dataType: 'json',
+          data: {
+            configKey: 'cloud_phone_resolving_power',
+          },
+        }).then(function (response) {
+          return response.data.map(function (v) {
+            return {
+              width: v.width || v.abscissa,
+              height: v.height || v.ordinate,
+            };
+          });
+          // [
+          //   // { width: 320, height: 240 },
+          //   // { width: 640, height: 480 },
+          //   { width: 375, height: 812 },
+          //   { width: 720, height: 1280 },
+
+          //   // { width: 1280, height: 720 },
+          //   // { width: 1080, height: 1920 },
+          // ];
+        });
+      }
+
+      getPhoneSizeList().then(function (phoneSizeList) {
+        window.phoneSizeList = phoneSizeList;
+        return updatePhoneSizeListHtml();
+      });
+
+      // const phoneSizeListSwiper = new Swiper('#phone-size-list-swiper', {
+      //   direction: 'vertical',
+      //   slidesPerView: 'auto',
+      //   loop: false,
+      //   centeredSlides: true,
+      // });
+      function setPhoneSize(config) {
+        $.ajax({
+          url:
+            baseUrl +
+            '/api/resources/v5/machine/resolution/operationResolvingPower',
+          headers: {
+            Authorization: token,
+          },
+          type: 'post',
+          dataType: 'json',
+          data: {
+            userCardId: window.userCardId,
+            width: config.width,
+            height: config.height,
+          },
+        });
+        wsss.send(
+          JSON.stringify({
+            type: 'setPhoneSize',
+            data: {
+              width: config.width,
+              height: config.height,
+            },
+          }),
+        );
+        wsss.send(
+          JSON.stringify({
+            type: 'forwardMsg',
+            data: {
+              code: 'phoneSizeChange',
+              width: config.width,
+              height: config.height,
+              desc: '分辨率修改', // 可选
+            },
+          }),
+        );
+        window.currentPhoneSize = config;
+      }
+      // wsss.addEventListener('message', function (event) {
+      //   console.log(
+      //     '🚀 ~ file: WXtrialInterface.html ~ line 1476 ~ event',
+      //     event,
+      //   );
+      // });
+      $('#phone-size-list').on('click', '.phone-size-item', function (e) {
+        const data = $(e.currentTarget).data();
+        window.activePhoneSize = data;
+        updatePhoneSizeListHtml();
+        // setPhoneSize(data.width, data.height);
+      });
+      $('#set-phone-size-dialog .dialog-btn.confirm').on('click', function (e) {
+        setPhoneSize(window.activePhoneSize);
+        $('#set-phone-size-dialog').removeClass('show');
+      });
     </script>
     <script type="text/javascript" src="WXdraw.js"></script>
     <script type="text/javascript" src="aac.js"></script>

File diff suppressed because it is too large
+ 519 - 370
static/screenIos/css/WXtrialInterface.css


+ 67 - 50
static/screenIos/decoder.js

@@ -6,18 +6,17 @@ var ret;
 var maxWidth = 1080;
 var maxHeight = 1920;
 var globalYuvPtr = undefined;
-var golbalYuvData;//全局,只分配一次
+var golbalYuvData; //全局,只分配一次
 var renderCount = 0;
 var curFrameWidth = undefined;
 var curFrameHeight = undefined;
 
-
 function doSomeInit() {
   var allocSize = maxWidth * maxHeight * 3;
   golbalYuvData = new Uint8Array(allocSize);
 }
-self.importScripts("ffmpeghelper.js");
-self.importScripts("spsParser.js");
+self.importScripts('ffmpeghelper.js');
+self.importScripts('spsParser.js');
 
 self.Module.onRuntimeInitialized = function () {
   isFinish = true;
@@ -25,43 +24,49 @@ self.Module.onRuntimeInitialized = function () {
   ret = Module._openDecoder();
 
   if (!ret) {
-    console.log("打开编码器成功");
+    console.log('打开编码器成功');
   }
-}
-
-self.addEventListener('message', function (e) {
-  var msg = e.data;
-  if (msg.type == "rawData") {
-    var buffer = e.data.data;
-
-    if (buffer[0] !== 0xff) { // 音频解码
-      var type = buffer[4] & 0x1f;
-      if (type == 7) {
-        let info = spsParser(buffer);
-
-        if (curFrameWidth != undefined && curFrameHeight != undefined) {
-          if (info.width != curFrameWidth || info.height != curFrameHeight) { // 分辨率发生改变,切换		
-            switchNewStream();
+};
+
+self.addEventListener(
+  'message',
+  function (e) {
+    var msg = e.data;
+    if (msg.type == 'rawData') {
+      var buffer = e.data.data;
+
+      if (buffer[0] !== 0xff) {
+        // 音频解码
+        var type = buffer[4] & 0x1f;
+        if (type == 7) {
+          let info = spsParser(buffer);
+
+          if (curFrameWidth != undefined && curFrameHeight != undefined) {
+            if (info.width != curFrameWidth || info.height != curFrameHeight) {
+              // 分辨率发生改变,切换
+              console.log('🚀 ~ file: decoder.js ~ line 44 ~ 分辨率发生改变');
+              switchNewStream();
+            }
           }
-        }
 
-        curFrameWidth = info.width;
-        curFrameHeight = info.height;
-        h264Queue.push(buffer);
-      } else {
-        h264Queue.push(buffer);
+          curFrameWidth = info.width;
+          curFrameHeight = info.height;
+          h264Queue.push(buffer);
+        } else {
+          h264Queue.push(buffer);
+        }
       }
-
     }
-  }
-}, false);
+  },
+  false,
+);
 
 function PrintfLog(str) {
   var curTime = new Date().getTime();
   var objData = {
     cmd: 0,
     data: str,
-    time: curTime
+    time: curTime,
   };
   self.postMessage(objData);
 }
@@ -73,23 +78,27 @@ function doRequestIFrame() {
   self.postMessage(objData);
 }
 
-
 function decodeVideo() {
   if (h264Queue.length > 0 && isFinish) {
     decodeH264(h264Queue.shift());
   }
 }
 
-
 var timeFlag = setInterval(decodeVideo, 1);
 
 //实现C 端到js yuv数据赋值, 并分配给opengl 渲染
 /*yuvData, 存放yuv数据的数组
-* inputYuvPtr C++ 
-*/
-function dispatchYuvData(yuvData, inputYuvPtr, videoWidth, videoHeight, copyLen) {
+ * inputYuvPtr C++
+ */
+function dispatchYuvData(
+  yuvData,
+  inputYuvPtr,
+  videoWidth,
+  videoHeight,
+  copyLen,
+) {
   for (i = 0; i < copyLen; i++) {
-    yuvData[i] = Module.HEAPU8[(inputYuvPtr) + i];
+    yuvData[i] = Module.HEAPU8[inputYuvPtr + i];
   }
 
   var curTime = new Date().getTime();
@@ -98,7 +107,7 @@ function dispatchYuvData(yuvData, inputYuvPtr, videoWidth, videoHeight, copyLen)
     data: yuvData,
     time: curTime,
     width: videoWidth,
-    height: videoHeight
+    height: videoHeight,
   };
   self.postMessage(objData);
 }
@@ -109,23 +118,32 @@ function decodeH264(data) {
   var inputPtr = Module._malloc(data.length); //输入数据
 
   for (var i = 0; i < data.length; i++) {
-    Module.HEAPU8[(inputPtr) + i] = data[i]; //转换为堆数据
+    Module.HEAPU8[inputPtr + i] = data[i]; //转换为堆数据
   }
 
-  var allocSize = maxWidth * maxHeight * 3 / 2;
+  var allocSize = (maxWidth * maxHeight * 3) / 2;
   if (globalYuvPtr == undefined) {
     globalYuvPtr = Module._malloc(allocSize);
   }
 
   var ret = Module._feedData(inputPtr, data.length, globalYuvPtr);
 
-  if (ret >= 0) { //解码成功才考虑渲染
-    frameWidth = Module._getVideoWidth();//拿到解码器宽、高
+  if (ret >= 0) {
+    //解码成功才考虑渲染
+    frameWidth = Module._getVideoWidth(); //拿到解码器宽、高
     frameHeight = Module._getVideoHeight();
-    var copyLen = frameWidth * frameHeight * 3 / 2;//只拷贝必须的长度
-
-    if (renderCount > 1) { //第一帧因为画面时全绿色的不渲染
-      dispatchYuvData(golbalYuvData, globalYuvPtr, frameWidth, frameHeight, copyLen);
+    // console.log("🚀 ~ file: decoder.js ~ line 134 ~ decodeH264 ~ frameWidth", frameWidth,frameHeight)
+    var copyLen = (frameWidth * frameHeight * 3) / 2; //只拷贝必须的长度
+
+    if (renderCount > 1) {
+      //第一帧因为画面时全绿色的不渲染
+      dispatchYuvData(
+        golbalYuvData,
+        globalYuvPtr,
+        frameWidth,
+        frameHeight,
+        copyLen,
+      );
     } else {
       renderCount++;
     }
@@ -135,15 +153,14 @@ function decodeH264(data) {
 }
 
 function switchNewStream() {
-
   closeDecoder();
-  var ret = Module._openDecoder();//再次开启解码器	
+  var ret = Module._openDecoder(); //再次开启解码器
   var timeFlag = setInterval(decodeVideo, 1);
-  console.log("切换解码器成功");
+  console.log('切换解码器成功');
 }
 
 function closeDecoder() {
-  clearInterval(timeFlag);//关闭原有定时器
+  clearInterval(timeFlag); //关闭原有定时器
   Module._closeDecoder();
   renderCount = 0;
 
@@ -151,7 +168,7 @@ function closeDecoder() {
     Module._free(globalYuvPtr);
     globalYuvPtr = undefined;
   }
-  console.log("此时buffer长度: %d", h264Queue.length);
+  console.log('此时buffer长度: %d', h264Queue.length);
   while (h264Queue.lengh > 0) {
     h264Queue.shift();
   }

File diff suppressed because it is too large
+ 62 - 39
static/screenIos/helper.js


BIN
static/static/img/phone-size-active.png


+ 24 - 0
static/static/lib/doT-1.1.3/.eslintrc.yml

@@ -0,0 +1,24 @@
+env:
+  node: true
+extends: 'eslint:recommended'
+globals:
+  define: false
+parserOptions:
+  ecmaVersion: 5
+rules:
+  no-trailing-spaces: 2
+  linebreak-style: [ 2, unix ]
+  semi: [ 2, always ]
+  valid-jsdoc: [ 2, { requireReturn: false } ]
+  no-unused-vars: [ 2, { args: none } ]
+  no-console: 0
+  block-scoped-var: 2
+  dot-location: [ 2, property ]
+  dot-notation: 2
+  no-else-return: 2
+  no-eq-null: 2
+  no-fallthrough: 2
+  no-return-assign: 2
+  no-use-before-define: [ 2, nofunc ]
+  no-path-concat: 2
+  no-useless-escape: 0

+ 33 - 0
static/static/lib/doT-1.1.3/.gitignore

@@ -0,0 +1,33 @@
+# Logs
+logs
+*.log
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
+node_modules
+
+# MacOS directory info files
+.DS_Store
+
+package-lock.json

+ 8 - 0
static/static/lib/doT-1.1.3/.travis.yml

@@ -0,0 +1,8 @@
+language: node_js
+node_js:
+  - "8"
+  - "10"
+  - "12"
+  - "13"
+after_script:
+  - coveralls < coverage/lcov.info

+ 24 - 0
static/static/lib/doT-1.1.3/LICENSE-DOT.txt

@@ -0,0 +1,24 @@
+
+Copyright (c) 2011 Laura Doktorova
+
+Software includes portions from jQote2 Copyright (c) 2010 aefxx,
+http://aefxx.com/ licensed under the MIT license.
+
+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.

+ 106 - 0
static/static/lib/doT-1.1.3/README.md

@@ -0,0 +1,106 @@
+# doT
+
+Created in search of the fastest and concise JavaScript templating function with emphasis on performance under V8 and nodejs. It shows great performance for both nodejs and browsers.
+
+doT.js is fast, small and has no dependencies.
+
+[![Build Status](https://travis-ci.org/olado/doT.svg?branch=master)](https://travis-ci.org/olado/doT)
+[![npm version](https://badge.fury.io/js/dot.svg)](https://www.npmjs.com/package/dot)
+[![Coverage Status](http://coveralls.io/repos/github/olado/doT/badge.svg?branch=master)](https://coveralls.io/github/olado/doT?branch=master)
+
+
+## Features
+    custom delimiters
+    runtime evaluation
+    runtime interpolation
+    compile-time evaluation
+    partials support
+    conditionals support
+    array iterators
+    encoding
+    control whitespace - strip or preserve
+    streaming friendly
+    use it as logic-less or with logic, it is up to you
+
+## Docs, live playground and samples
+
+http://olado.github.com/doT (todo: update docs with new features added in version 1.0.0)
+
+## New in version 1.0.0
+
+#### Added parameters support in partials
+
+```html
+{{##def.macro:param:
+	<div>{{=param.foo}}</div>
+#}}
+
+{{#def.macro:myvariable}}
+```
+
+#### Node module now supports auto-compilation of dot templates from specified path
+
+```js
+var dots = require("dot").process({ path: "./views"});
+```
+
+This will compile .def, .dot, .jst files found under the specified path.
+Details
+   * It ignores sub-directories.
+   * Template files can have multiple extensions at the same time.
+   * Files with .def extension can be included in other files via {{#def.name}}
+   * Files with .dot extension are compiled into functions with the same name and
+   can be accessed as renderer.filename
+   * Files with .jst extension are compiled into .js files. Produced .js file can be
+   loaded as a commonJS, AMD module, or just installed into a global variable (default is set to window.render)
+   * All inline defines defined in the .jst file are
+   compiled into separate functions and are available via _render.filename.definename
+ 
+   Basic usage:
+ ```js
+        var dots = require("dot").process({path: "./views"});
+        dots.mytemplate({foo:"hello world"});
+ ```
+   The above snippet will:
+	* Compile all templates in views folder (.dot, .def, .jst)
+  	* Place .js files compiled from .jst templates into the same folder
+     	   These files can be used with require, i.e. require("./views/mytemplate")
+  	* Return an object with functions compiled from .dot templates as its properties
+  	* Render mytemplate template
+ 
+#### CLI tool to compile dot templates into js files
+
+	./bin/dot-packer -s examples/views -d out/views
+
+## Example for express
+	Many people are using doT with express. I added an example of the best way of doing it examples/express:
+
+[doT with express](examples/express)
+
+## Notes
+    doU.js is here only so that legacy external tests do not break. Use doT.js.
+    doT.js with doT.templateSettings.append=false provides the same performance as doU.js.
+
+## Security considerations
+
+doT allows arbitrary JavaScript code in templates, making it one of the most flexible and powerful templating engines. It means that doT security model assumes that you only use trusted templates and you don't use any  user input as any part of the template, as otherwise it can lead to code injection.
+
+It is strongly recommended to compile all templates to JS code as early as possible. Possible options:
+
+- using doT as dev-dependency only and compiling templates to JS files, for example, as described above or using a custom script, during the build. This is the most performant and secure approach and it is strongly recommended.
+- if the above approach is not possible for some reason (e.g. templates are dynamically generated using some run-time data), it is recommended to compile templates to in-memory functions during application start phase, before any external input is processed.
+- compiling templates lazily, on demand, is less safe. Even though the possibility of the code injection via prototype pollution was patched (#291), there may be some other unknown vulnerabilities that could lead to code injection.
+
+Please report any found vulnerabilities to npm, not via issue tracker.
+
+## Author
+Laura Doktorova [@olado](http://twitter.com/olado)
+
+## License
+doT is licensed under the MIT License. (See LICENSE-DOT)
+
+<p align="center">
+  <img src="http://olado.github.io/doT/doT-js-100@2x.png" alt="logo by Kevin Kirchner"/>
+</p>
+
+Thank you [@KevinKirchner](https://twitter.com/kevinkirchner) for the logo.

+ 110 - 0
static/static/lib/doT-1.1.3/benchmarks/compileBench.js

@@ -0,0 +1,110 @@
+(function() {
+	var jslitmus, _, doU, doT,
+		data = { f1: 1, f2: 2, f3: 3, f4: "http://bebedo.com/laura"},
+		snippet = "<h1>Just static text</h1>\
+		<p>Here is a simple {{=it.f1}} </p>\
+		<div>test {{=it.f2}}\
+		<div>{{=it.f3}}</div>\
+		<div>{{!it.f4}}</div>\
+		</div>";
+
+	if (typeof module !== 'undefined' && module.exports) {
+		runTests();
+	} else {
+		window.onload = runTestsInBrowser;
+	}
+
+	function testsetup(snippet) {
+
+		jslitmus.test('doU.js', function() {
+			doU.template(snippet);
+		});
+
+		jslitmus.test('doU.js - looping', function(count) {
+			while (count--) {
+				doU.template(snippet);
+			}
+		});
+
+		jslitmus.test('doT.js - using this', function() {
+			doT.template(snippet);
+		});
+
+		jslitmus.test('doT.js - using this - looping', function(count) {
+			while (count--) {
+				doT.template(snippet);
+			}
+		});
+	}
+
+	function runTests() {
+		//var util = require('util');
+		jslitmus = require('./jslitmus.js');
+		doU = require('./templating/doU.js');
+		doT = require('./templating/doT.js');
+		var passOne = 0;
+		console.log("*** Compilation speed test");
+		console.log("*** Small template length: " + snippet.length);
+		testsetup(snippet);
+		// Log the test results
+		jslitmus.on('complete', function(test) {
+			//console.log(util.inspect(process.memoryUsage()));
+			console.log(test.toString());
+		});
+		// 'all_complete' fires when all tests have finished.
+		jslitmus.on('all_complete', function() {
+			switch (passOne) {
+			case 0:
+				passOne++;
+				for(var i=0; i<5; i++) { snippet += snippet; }
+				console.log("*** Medium template length: " + snippet.length);
+				break;
+			case 1:
+				passOne++;
+				for(var i=0; i<3; i++) { snippet += snippet; }
+				console.log("*** Large template length: " + snippet.length);
+				break;
+			default:
+				return;
+			}
+
+			jslitmus.clearAll();
+			testsetup(snippet);
+			jslitmus.runAll();
+		});
+		// Run it!
+		jslitmus.runAll();
+	}
+
+	function runTestsInBrowser() {
+		jslitmus = window.jslitmus;doU = window.doU;doT = window.doT;
+
+		var resultTmpl = doT.template("<h3>Template length : {{=it.size}} </h3>	<img src='{{=it.url}}'/>");
+		var currentSet = document.getElementById('small');
+		testsetup(snippet);
+		// 'complete' fires for each test when it finishes.
+		jslitmus.on('complete', function(test) {
+		// Output test results
+			currentSet.innerHTML += test + '<br/>';
+		});
+		// 'all_complete' fires when all tests have finished.
+		jslitmus.on('all_complete', function() {
+			// Get the results image URL
+			var url = jslitmus.getGoogleChart();
+			if (currentSet.id === 'small') {
+				currentSet.innerHTML += resultTmpl({size: snippet.length, url: url});
+				setTimeout(function() {
+					jslitmus.clearAll();
+					currentSet = document.getElementById('large');
+					for(var i=0; i<8; i++) { snippet += snippet; }
+					testsetup(snippet);
+					jslitmus.runAll();
+				}, 10);
+			} else {
+				currentSet.innerHTML += resultTmpl({size: snippet.length, url: url});
+			}
+		});
+		// Run it!
+		jslitmus.runAll();
+	}
+})();

+ 22 - 0
static/static/lib/doT-1.1.3/benchmarks/genspeed.html

@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+
+<title>Templating Test Suite</title>
+
+<script type="text/javascript" src="jslitmus.js"></script>
+<script type="text/javascript" src="templating/doU.js"></script>
+<script type="text/javascript" src="templating/doT.js"></script>
+<script type="text/javascript" src="compileBench.js"></script>
+
+</head>
+
+<body>
+  <h1>Comparing doU.js and doT.js compilation speed</h1>
+  <div id='small' style="float:left;min-width:400px;"><h3>Small template</h3></div>
+  <div id='large' style="float:left;"><h3>Large template</h3></div>
+</body>
+
+</html>

+ 22 - 0
static/static/lib/doT-1.1.3/benchmarks/index.html

@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+
+<title>Templating Test Suite</title>
+
+<script type="text/javascript" src="jslitmus.js"></script>
+<script type="text/javascript" src="templating/doU.js"></script>
+<script type="text/javascript" src="templating/doT.js"></script>
+<script type="text/javascript" src="templatesBench.js"></script>
+
+</head>
+
+<body>
+  <h1>Comparing doU.js and doT.js</h1>
+  <div id='small' style="float:left;min-width:400px;"><h3>Small template</h3></div>
+  <div id='large' style="float:left;"><h3>Large template</h3></div>
+</body>
+
+</html>

+ 628 - 0
static/static/lib/doT-1.1.3/benchmarks/jslitmus.js

@@ -0,0 +1,628 @@
+// jslitmus.js
+//
+// Copyright (c) 2010, Robert Kieffer, http://broofa.com
+// Available under MIT license (http://en.wikipedia.org/wiki/MIT_License)
+
+(function() {
+  var root = this;
+
+  //
+  // Platform detect
+  //
+
+  var platform = (function() {
+    // Platform info object
+    var p = {
+      name: null,
+      version: null,
+      os: null,
+      description: 'unknown platform',
+      toString: function() {return this.description;}
+    };
+
+    if (root.navigator) {
+      var ua = navigator.userAgent;
+
+      // Detect OS
+      var oses = 'Windows|iPhone OS|(?:Intel |PPC )?Mac OS X|Linux';
+      p.os = new RegExp('((' + oses + ') +[^ \);]*)').test(ua) ? RegExp.$1.replace(/_/g, '.') : null;
+
+      // Detect expected names
+      p.name = /(Chrome|MSIE|Safari|Opera|Firefox|Minefield)/.test(ua) ? RegExp.$1 : null;
+
+      // Detect version
+      if (p.name == 'Opera') {
+        p.version = opera.name;
+      } else if (p.name) {
+        var vre = new RegExp('(Version|' + p.name + ')[ \/]([^ ;]*)');
+        p.version = vre.test(ua) ? RegExp.$2 : null;
+      }
+    } else if (root.process && process.platform) {
+      // Support node.js (see http://nodejs.org)
+      p.name = 'node';
+      p.version = process.version;
+      p.os = process.platform;
+    }
+
+    // Set the description
+    var d = [];
+    if (p.name) d.push(p.name);
+    if (p.version) d.push(' ' + p.version);
+    if (p.os) d.push(' on ' + p.os);
+    if (d.length) p.description = d.join('');
+
+    return p;
+  })();
+
+  //
+  // Context-specific initialization
+  //
+
+  var sys = null, querystring = null;
+  if (platform.name == 'node') {
+    util = require('util');
+    querystring = require('querystring');
+  }
+
+  //
+  // Misc convenience methods
+  //
+
+  function log(msg) {
+    if (typeof(console) != 'undefined') {
+      console.log(msg);
+    } else if (sys) {
+      util.log(msg);
+    }
+  }
+
+  // nil function
+  function nilf(x) {
+    return x;
+  }
+
+  // Copy properties
+  function extend(dst, src) {
+    for (var k in src) {
+      dst[k] = src[k];
+    }
+    return dst;
+  }
+
+  // Array: apply f to each item in a
+  function forEach(a, f) {
+    for (var i = 0, il = (a && a.length); i < il; i++) {
+      var o = a[i];
+      f(o, i);
+    }
+  }
+
+  // Array: return array of all results of f(item)
+  function map(a, f) {
+    var o, res = [];
+    for (var i = 0, il = (a && a.length); i < il; i++) {
+      var o = a[i];
+      res.push(f(o, i));
+    }
+    return res;
+  }
+
+  // Array: filter out items for which f(item) is falsy
+  function filter(a, f) {
+    var o, res = [];
+    for (var i = 0, il = (a && a.length); i < il; i++) {
+      var o = a[i];
+      if (f(o, i)) res.push(o);
+    }
+    return res;
+  }
+
+  // Array: IE doesn't have indexOf in some cases
+  function indexOf(a, o) {
+    if (a.indexOf) return a.indexOf(o);
+    for (var i = 0, l = a.length; i < l; i++) if (a[i] === o) return i;
+    return -1;
+  }
+
+  // Enhanced escape()
+  function escape2(s) {
+    s = s.replace(/,/g, '\\,');
+    s = querystring ? querystring.escape(s) : escape(s);
+    s = s.replace(/\+/g, '%2b');
+    s = s.replace(/ /g, '+');
+    return s;
+  }
+
+  // join(), for objects. Creates url query param-style strings by default
+  function join(o, delimit1, delimit2) {
+    var asQuery = !delimit1 && !delimit2;
+    if (asQuery) {
+      delimit1 = '&';
+      delimit2 = '=';
+    }
+
+    var pairs = [];
+    for (var key in o) {
+      var value = o[key];
+      if (asQuery) value = escape2(value);
+      pairs.push(key + delimit2 + o[key]);
+    }
+    return pairs.join(delimit1);
+  }
+
+  // split(), for object strings. Parses url query param strings by default
+  function split(s, delimit1, delimit2) {
+    var asQuery = !delimit1 && !delimit2;
+    if (asQuery) {
+      s = s.replace(/.*[?#]/, '');
+      delimit1 = '&';
+      delimit2 = '=';
+    }
+
+    if (match) {
+      var o = query.split(delimit1);
+      for (var i = 0; i < o.length; i++) {
+        var pair = o[i].split(new RegExp(delimit2 + '+'));
+        var key = pair.shift();
+        var value = (asQuery && pair.length > 1) ? pair.join(delimit2) : pair[0];
+        o[key] = value;
+      }
+    }
+
+    return o;
+  }
+
+  // Round x to d significant digits
+  function sig(x, d) {
+    var exp = Math.ceil(Math.log(Math.abs(x))/Math.log(10)),
+        f = Math.pow(10, exp-d);
+    return Math.round(x/f)*f;
+  }
+
+  // Convert x to a readable string version
+  function humanize(x, sd) {
+    var ax = Math.abs(x), res;
+    sd = sd | 4;  // significant digits
+    if (ax == Infinity) {
+      res = ax > 0 ? 'Infinity' : '-Infinity';
+    } else if (ax > 1e9) {
+      res = sig(x/1e9, sd) + 'G';
+    } else if (ax > 1e6) {
+      res = sig(x/1e6, sd) + 'M';
+    } else if (ax > 1e3) {
+      res = sig(x/1e3, sd) + 'k';
+    } else if (ax > .01) {
+      res = sig(x, sd);
+    } else if (ax > 1e-3) {
+      res = sig(x/1e-3, sd) + 'm';
+    } else if (ax > 1e-6) {
+      res = sig(x/1e-6, sd) + '\u00b5'; // Greek mu
+    } else if (ax > 1e-9) {
+      res = sig(x/1e-9, sd) + 'n';
+    } else {
+      res = x ? sig(x, sd) : 0;
+    }
+    // Turn values like "1.1000000000005" -> "1.1"
+    res = (res + '').replace(/0{5,}\d*/, '');
+
+    return res;
+  }
+
+  // Node.js-inspired event emitter API, with some enhancements.
+  function EventEmitter() {
+    var ee = this;
+    var listeners = {};
+    extend(ee, {
+      on: function(e, f) {
+        if (!listeners[e]) listeners[e] = [];
+        listeners[e].push(f);
+      },
+      removeListener: function(e, f) {
+        listeners[e] = filter(listeners[e], function(l) {
+          return l != f;
+        });
+      },
+      removeAllListeners: function(e) {
+        listeners[e] = [];
+      },
+      emit: function(e) {
+        var args = Array.prototype.slice.call(arguments, 1);
+        forEach([].concat(listeners[e], listeners['*']), function(l) {
+          ee._emitting = e;
+          if (l) l.apply(ee, args);
+        });
+        delete ee._emitting;
+      }
+    });
+  }
+
+  //
+  // Test class
+  //
+
+  /**
+   * Test manages a single test (created with JSLitmus.test())
+   */
+  function Test(name, f) {
+    var test = this;
+
+    // Test instances get EventEmitter API
+    EventEmitter.call(test);
+
+    if (!f) throw new Error('Undefined test function');
+    if (!/function[^\(]*\(([^,\)]*)/.test(f)) {
+      throw new Error('"' + name + '" test: Invalid test function');
+    }
+
+    // If the test function takes an argument, we assume it does the iteration
+    // for us
+    var isLoop = !!RegExp.$1;
+
+    /**
+     * Reset test state
+     */
+    function reset() {
+      delete test.count;
+      delete test.time;
+      delete test.running;
+      test.emit('reset', test);
+      return test;
+    }
+
+    function clone() {
+      var test = extend(new Test(name, f), test);
+      return test.reset();
+    }
+
+    /**
+     * Run the test n times, and use the best results
+     */
+    function bestOf(n) {
+      var best = null;
+      while (n--) {
+        var t = clone();
+        t.run(null, true);
+        if (!best || t.period < best.period) {
+          best = t;
+        }
+      }
+      extend(test, best);
+    }
+
+    /**
+     * Start running a test.  Default is to run the test asynchronously (via
+     * setTimeout).  Can be made synchronous by passing true for 2nd param
+     */
+    function run(count, synchronous) {
+      count = count || test.INIT_COUNT;
+      test.running = true;
+
+      if (synchronous) {
+        _run(count, synchronous);
+      } else {
+        setTimeout(function() {
+          _run(count);
+        }, 1);
+      }
+      return test;
+    }
+
+    /**
+     * Run, for real
+     */
+    function _run(count, noTimeout) {
+
+      try {
+        var start, f = test.f, now, i = count;
+
+        // Start the timer
+        start = new Date();
+
+        // Run the test code
+        test.count = count;
+        test.time = 0;
+        test.period = 0;
+
+        test.emit('start', test);
+
+        if (isLoop) {
+          // Test code does it's own iteration
+          f(count);
+        } else {
+          // Do the iteration ourselves
+          while (i--) f();
+        }
+
+        // Get time test took (in secs)
+        test.time = Math.max(1,new Date() - start)/1000;
+
+        // Store iteration count and per-operation time taken
+        test.count = count;
+        test.period = test.time/count;
+
+        // Do we need to keep running?
+        test.running = test.time < test.MIN_TIME;
+
+        // Publish results
+        test.emit('results', test);
+
+        // Set up for another run, if needed
+        if (test.running) {
+          // Use an iteration count that will (we hope) get us close to the
+          // MAX_COUNT time.
+          var x = test.MIN_TIME/test.time;
+          var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
+          count *= pow;
+          if (count > test.MAX_COUNT) {
+            throw new Error('Max count exceeded.  If this test uses a looping function, make sure the iteration loop is working properly.');
+          }
+
+          if (noTimeout) {
+            _run(count, noTimeout);
+          } else {
+            run(count);
+          }
+        } else {
+          test.emit('complete', test);
+        }
+      } catch (err) {
+        log(err);
+        // Exceptions are caught and displayed in the test UI
+        test.emit('error', err);
+      }
+
+      return test;
+    }
+
+    /**
+    * Get the number of operations per second for this test.
+    *
+    * @param normalize if true, iteration loop overhead taken into account.
+    *                  Note that normalized tests may return Infinity if the
+    *                  test time is of the same order as the calibration time.
+    */
+    function getHz(normalize) {
+      var p = test.period;
+
+      // Adjust period based on the calibration test time
+      if (normalize) {
+        var cal = test.isLoop ? Test.LOOP_CAL : Test.NOLOOP_CAL;
+        if (!cal.period) {
+          // Run calibration if needed
+          cal.MIN_TIME = .3;
+          cal.bestOf(3);
+        }
+
+        // Subtract off calibration time.  In theory this should never be
+        // negative, but in practice the calibration times are affected by a
+        // variety of factors so just clip to zero and let users test for
+        // getHz() == Infinity
+        p = Math.max(0, p - cal.period);
+      }
+
+      return sig(1/p, 4);
+    }
+
+    // Set properties that are specific to this instance
+    extend(test, {
+      // Test name
+      name: name,
+
+      // Test function
+      f: f,
+
+      // True if the test function does it's own looping (i.e. takes an arg)
+      isLoop: isLoop,
+
+      clone: clone,
+      run: run,
+      bestOf: bestOf,
+      getHz: getHz,
+      reset: reset
+    });
+
+    // IE7 doesn't do 'toString' or 'toValue' in object enumerations, so set
+    // it explicitely here.
+    test.toString = function() {
+      if (this.time) {
+        return this.name + ', f = '  +
+        humanize(this.getHz()) + 'hz (' +
+        humanize(this.count) + '/' + humanize(this.time) + 'secs)';
+      } else {
+        return this.name + ', count = '  + humanize(this.count);
+      }
+    };
+  };
+
+  // Set static properties
+  extend(Test, {
+    LOOP_CAL: new Test('loop cal', function(count) {while (count--) {}}),
+    NOLOOP_CAL: new Test('noloop cal', nilf)
+  });
+
+  // Set default property values
+  extend(Test.prototype, {
+    // Initial number of iterations
+    INIT_COUNT: 10,
+
+    // Max iterations allowed (used to detect bad looping functions)
+    MAX_COUNT: 1e9,
+
+    // Minimum time test should take to get valid results (secs)
+    MIN_TIME: 1.0
+  });
+
+  //
+  // jslitmus
+  //
+
+  // Set up jslitmus context
+  var jslitmus;
+  if (platform.name == 'node') {
+    jslitmus = exports;
+  } else {
+    jslitmus = root.jslitmus = {};
+  }
+
+  var tests = [], // test store (all tests added w/ jslitmus.test())
+      queue = [], // test queue (to be run)
+      currentTest; // currently running test
+
+  // jslitmus gets EventEmitter API
+  EventEmitter.call(jslitmus);
+
+  /**
+    * Create a new test
+    */
+  function test(name, f) {
+    // Create the Test object
+    var test = new Test(name, f);
+    tests.push(test);
+
+    // Run the next test if this one finished
+    test.on('*', function() {
+      // Forward test events to jslitmus listeners
+      var args = Array.prototype.slice.call(arguments);
+      args.unshift(test._emitting);
+      jslitmus.emit.apply(jslitmus, args);
+
+      // Auto-run the next test
+      if (test._emitting == 'complete') {
+        currentTest = null;
+        _nextTest();
+      }
+    });
+
+    jslitmus.emit('added', test);
+
+    return test;
+  }
+
+  /**
+    * Add all tests to the run queue
+    */
+  function runAll(e) {
+    forEach(tests, _queueTest);
+  }
+
+  /**
+    * Remove all tests from the run queue.  The current test has to finish on
+    * it's own though
+    */
+  function stop() {
+    while (queue.length) {
+      var test = queue.shift();
+    }
+  }
+
+  /**
+    * Run the next test in the run queue
+    */
+  function _nextTest() {
+    if (!currentTest) {
+      var test = queue.shift();
+      if (test) {
+        currentTest = test;
+        test.run();
+      } else {
+        jslitmus.emit('all_complete');
+      }
+    }
+  }
+
+  /**
+    * Add a test to the run queue
+    */
+  function _queueTest(test) {
+    if (indexOf(queue, test) >= 0) return;
+    queue.push(test);
+    _nextTest();
+  }
+
+  function clearAll() {
+	tests = [];
+  }
+
+  /**
+    * Generate a Google Chart URL that shows the data for all tests
+    */
+  function getGoogleChart(normalize) {
+    var chart_title = [
+      'Operations/second on ' + platform.name,
+      '(' + platform.version + ' / ' + platform.os + ')'
+    ];
+
+    var n = tests.length, markers = [], data = [];
+    var d, min = 0, max = -1e10;
+
+    // Gather test data
+
+    var markers = map(tests, function(test, i) {
+      if (test.count) {
+        var hz = test.getHz();
+        var v = hz != Infinity ? hz : 0;
+        data.push(v);
+        var label = test.name + '(' + humanize(hz)+ ')';
+        var marker = 't' + escape2(label) + ',000000,0,' + i + ',10';
+        max = Math.max(v, max);
+
+        return marker;
+      }
+    });
+
+    if (markers.length <= 0) return null;
+
+    // Build labels
+    var labels = [humanize(min), humanize(max)];
+
+    var w = 250, bw = 15;
+    var bs = 5;
+    var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
+
+    var params = {
+      chtt: escape(chart_title.join('|')),
+      chts: '000000,10',
+      cht: 'bhg',                     // chart type
+      chd: 't:' + data.join(','),     // data set
+      chds: min + ',' + max,          // max/min of data
+      chxt: 'x',                      // label axes
+      chxl: '0:|' + labels.join('|'), // labels
+      chsp: '0,1',
+      chm: markers.join('|'),         // test names
+      chbh: [bw, 0, bs].join(','),    // bar widths
+      // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
+      chs: w + 'x' + h
+    };
+
+    var url = 'http://chart.apis.google.com/chart?' + join(params);
+
+    return url;
+  }
+
+  // Public API
+  extend(jslitmus, {
+    Test: Test,
+    platform: platform,
+    test: test,
+    runAll: runAll,
+    getGoogleChart: getGoogleChart,
+	clearAll: clearAll
+  });
+
+  // Expose code goodness we've got here, since it's useful, but do so in a way
+  // that doesn't commit us to supporting it in future versions.
+  jslitmus.unsupported = {
+    nilf: nilf,
+    log: log,
+    extend: extend,
+    forEach: forEach,
+    filter: filter,
+    map: map,
+    indexOf: indexOf,
+    escape2: escape2,
+    join: join,
+    split: split,
+    sig: sig,
+    humanize: humanize
+  };
+})();

+ 138 - 0
static/static/lib/doT-1.1.3/benchmarks/templatesBench.js

@@ -0,0 +1,138 @@
+(function() {
+	var jslitmus, _, doU, doT,
+		data = { f1: 1, f2: 2, f3: 3, f4: "http://bebedo.com/laura"},
+		snippet = "<h1>Just static text</h1>\
+		<p>Here is a simple {{=it.f1}} </p>\
+		<div>test {{=it.f2}}\
+		<div>{{=it.f3}}</div>\
+		<div>{{!it.f4}}</div>\
+		</div>";
+
+	if (typeof module !== 'undefined' && module.exports) {
+		runTests();
+	} else {
+		window.onload = runTestsInBrowser;
+	}
+
+	function testsetup(snippet) {
+		// doU with 'it'
+		var doUCompiled = doU.template(snippet);
+		// doT with 'it'
+		var doTCompiledParam = doT.template(snippet);
+		// doT with 'this'
+		var doTCompiled = doT.template(snippet.replace(/=it\./g, '=this.').replace(/{{!it\./g, '{{!this.'));
+		// doT with 'it' and append = false
+		doT.templateSettings.append = false;
+		var doTCompiledNoAppend = doT.template(snippet);
+
+		jslitmus.test('doU.js', function() {
+			doUCompiled(data);
+		});
+
+		jslitmus.test('doU.js - looping', function(count) {
+			while (count--) {
+				doUCompiled(data);
+			}
+		});
+
+		jslitmus.test('doT.js - using this', function() {
+			doTCompiled.call(data);
+		});
+
+		jslitmus.test('doT.js - using this - looping', function(count) {
+			while (count--) {
+				doTCompiled.call(data);
+			}
+		});
+
+		jslitmus.test('doT.js - using it', function() {
+			doTCompiledParam(data);
+		});
+
+		jslitmus.test('doT.js - using it - looping', function(count) {
+			while (count--) {
+				doTCompiledParam(data);
+			}
+		});
+
+		jslitmus.test('doT.js - append off', function() {
+			doTCompiledNoAppend(data);
+		});
+
+		jslitmus.test('doT.js - append off - looping', function(count) {
+			while (count--) {
+				doTCompiledNoAppend(data);
+			}
+		});
+}
+
+	function runTests() {
+		//var util = require('util');
+		jslitmus = require('./jslitmus.js');
+		doU = require('./templating/doU.js');
+		doT = require('./templating/doT.js');
+		var passOne = 0;
+		console.log("*** Small template length: " + snippet.length);
+		testsetup(snippet);
+		// Log the test results
+		jslitmus.on('complete', function(test) {
+			//console.log(util.inspect(process.memoryUsage()));
+			console.log(test.toString());
+		});
+		// 'all_complete' fires when all tests have finished.
+		jslitmus.on('all_complete', function() {
+			switch (passOne) {
+			case 0:
+				passOne++;
+				for(var i=0; i<5; i++) { snippet += snippet; }
+				console.log("*** Medium template length: " + snippet.length);
+				break;
+			case 1:
+				passOne++;
+				for(var i=0; i<3; i++) { snippet += snippet; }
+				console.log("*** Large template length: " + snippet.length);
+				break;
+			default:
+				return;
+			}
+
+			jslitmus.clearAll();
+			testsetup(snippet);
+			jslitmus.runAll();
+		});
+		// Run it!
+		jslitmus.runAll();
+	}
+
+	function runTestsInBrowser() {
+		jslitmus = window.jslitmus;doU = window.doU;doT = window.doT;
+
+		var resultTmpl = doT.template("<h3>Template length : {{=it.size}} </h3>	<img src='{{=it.url}}'/>");
+		var currentSet = document.getElementById('small');
+		testsetup(snippet);
+		// 'complete' fires for each test when it finishes.
+		jslitmus.on('complete', function(test) {
+		// Output test results
+			currentSet.innerHTML += test + '<br/>';
+		});
+		// 'all_complete' fires when all tests have finished.
+		jslitmus.on('all_complete', function() {
+			// Get the results image URL
+			var url = jslitmus.getGoogleChart();
+			if (currentSet.id === 'small') {
+				currentSet.innerHTML += resultTmpl({size: snippet.length, url: url});
+				setTimeout(function() {
+					jslitmus.clearAll();
+					currentSet = document.getElementById('large');
+					for(var i=0; i<8; i++) { snippet += snippet; }
+					testsetup(snippet);
+					jslitmus.runAll();
+				}, 10);
+			} else {
+				currentSet.innerHTML += resultTmpl({size: snippet.length, url: url});
+			}
+		});
+		// Run it!
+		jslitmus.runAll();
+	}
+})();

+ 140 - 0
static/static/lib/doT-1.1.3/benchmarks/templating/doT.js

@@ -0,0 +1,140 @@
+// doT.js
+// 2011-2014, Laura Doktorova, https://github.com/olado/doT
+// Licensed under the MIT license.
+
+(function() {
+	"use strict";
+
+	var doT = {
+		version: "1.0.3",
+		templateSettings: {
+			evaluate:    /\{\{([\s\S]+?(\}?)+)\}\}/g,
+			interpolate: /\{\{=([\s\S]+?)\}\}/g,
+			encode:      /\{\{!([\s\S]+?)\}\}/g,
+			use:         /\{\{#([\s\S]+?)\}\}/g,
+			useParams:   /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
+			define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
+			defineParams:/^\s*([\w$]+):([\s\S]+)/,
+			conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
+			iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
+			varname:	"it",
+			strip:		true,
+			append:		true,
+			selfcontained: false,
+			doNotSkipEncoded: false
+		},
+		template: undefined, //fn, compile template
+		compile:  undefined  //fn, for express
+	}, _globals;
+
+	doT.encodeHTMLSource = function(doNotSkipEncoded) {
+		var encodeHTMLRules = { "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': "&#34;", "'": "&#39;", "/": "&#47;" },
+			matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g;
+		return function(code) {
+			return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : "";
+		};
+	};
+
+	_globals = (function(){ return this || (0,eval)("this"); }());
+
+	if (typeof module !== "undefined" && module.exports) {
+		module.exports = doT;
+	} else if (typeof define === "function" && define.amd) {
+		define(function(){return doT;});
+	} else {
+		_globals.doT = doT;
+	}
+
+	var startend = {
+		append: { start: "'+(",      end: ")+'",      startencode: "'+encodeHTML(" },
+		split:  { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" }
+	}, skip = /$^/;
+
+	function resolveDefs(c, block, def) {
+		return ((typeof block === "string") ? block : block.toString())
+		.replace(c.define || skip, function(m, code, assign, value) {
+			if (code.indexOf("def.") === 0) {
+				code = code.substring(4);
+			}
+			if (!(code in def)) {
+				if (assign === ":") {
+					if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
+						def[code] = {arg: param, text: v};
+					});
+					if (!(code in def)) def[code]= value;
+				} else {
+					new Function("def", "def['"+code+"']=" + value)(def);
+				}
+			}
+			return "";
+		})
+		.replace(c.use || skip, function(m, code) {
+			if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
+				if (def[d] && def[d].arg && param) {
+					var rw = (d+":"+param).replace(/'|\\/g, "_");
+					def.__exp = def.__exp || {};
+					def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
+					return s + "def.__exp['"+rw+"']";
+				}
+			});
+			var v = new Function("def", "return " + code)(def);
+			return v ? resolveDefs(c, v, def) : v;
+		});
+	}
+
+	function unescape(code) {
+		return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
+	}
+
+	doT.template = function(tmpl, c, def) {
+		c = c || doT.templateSettings;
+		var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
+			str  = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
+
+		str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ")
+					.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str)
+			.replace(/'|\\/g, "\\$&")
+			.replace(c.interpolate || skip, function(m, code) {
+				return cse.start + unescape(code) + cse.end;
+			})
+			.replace(c.encode || skip, function(m, code) {
+				needhtmlencode = true;
+				return cse.startencode + unescape(code) + cse.end;
+			})
+			.replace(c.conditional || skip, function(m, elsecase, code) {
+				return elsecase ?
+					(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
+					(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
+			})
+			.replace(c.iterate || skip, function(m, iterate, vname, iname) {
+				if (!iterate) return "';} } out+='";
+				sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
+				return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
+					+vname+"=arr"+sid+"["+indv+"+=1];out+='";
+			})
+			.replace(c.evaluate || skip, function(m, code) {
+				return "';" + unescape(code) + "out+='";
+			})
+			+ "';return out;")
+			.replace(/\n/g, "\\n").replace(/\t/g, '\\t').replace(/\r/g, "\\r")
+			.replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, "");
+			//.replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+=');
+
+		if (needhtmlencode) {
+			if (!c.selfcontained && _globals && !_globals._encodeHTML) _globals._encodeHTML = doT.encodeHTMLSource(c.doNotSkipEncoded);
+			str = "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("
+				+ doT.encodeHTMLSource.toString() + "(" + (c.doNotSkipEncoded || '') + "));"
+				+ str;
+		}
+		try {
+			return new Function(c.varname, str);
+		} catch (e) {
+			if (typeof console !== "undefined") console.log("Could not create a template function: " + str);
+			throw e;
+		}
+	};
+
+	doT.compile = function(tmpl, def) {
+		return doT.template(tmpl, null, def);
+	};
+}());

+ 56 - 0
static/static/lib/doT-1.1.3/benchmarks/templating/doU.js

@@ -0,0 +1,56 @@
+// doU.js
+// (c) 2011, Laura Doktorova
+// https://github.com/olado/doT
+//
+// doU is an extraction and slight modification of an excellent
+// templating function from jQote2.js (jQuery plugin) by aefxx
+// (http://aefxx.com/jquery-plugins/jqote2/).
+//
+// Modifications:
+// 1. nodejs support
+// 2. allow for custom template markers
+// 3. only allow direct invocation of the compiled function
+//
+// Licensed under the MIT license.
+
+(function() {
+	var doU = { version : '0.1.2' };
+
+	if (typeof module !== 'undefined' && module.exports) {
+		module.exports = doU;
+	} else {
+		this.doU = doU;
+	}
+
+	doU.templateSettings = {
+		begin : '{{',
+		end : '}}',
+		varname : 'it'
+	};
+
+	doU.template = function(tmpl, conf) {
+		conf = conf || doU.templateSettings;
+		var str = '', tb = conf.begin, te = conf.end, m, l,
+			arr = tmpl.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, '')
+				.split(tb).join(te +'\x1b')
+				.split(te);
+
+		for (m=0,l=arr.length; m < l; m++) {
+			str += arr[m].charAt(0) !== '\x1b' ?
+			"out+='" + arr[m].replace(/(\\|["'])/g, '\\$1') + "'" : (arr[m].charAt(1) === '=' ?
+			';out+=(' + arr[m].substr(2) + ');' : (arr[m].charAt(1) === '!' ?
+			';out+=(' + arr[m].substr(2) + ").toString().replace(/&(?!\\w+;)/g, '&#38;').split('<').join('&#60;').split('>').join('&#62;').split('" + '"' + "').join('&#34;').split(" + '"' + "'" + '"' + ").join('&#39;').split('/').join('&#x2F;');" : ';' + arr[m].substr(1)));
+		}
+
+		str = ('var out="";'+str+';return out;')
+			.split("out+='';").join('')
+			.split('var out="";out+=').join('var out=');
+
+		try {
+			return new Function(conf.varname, str);
+		} catch (e) {
+			if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
+			throw e;
+		}
+	};
+}());

+ 52 - 0
static/static/lib/doT-1.1.3/bin/dot-packer

@@ -0,0 +1,52 @@
+#!/usr/bin/env node
+/* Continuation of https://github.com/Katahdin/dot-packer */
+
+var program = require('commander'),
+	dot = require('../');
+
+program
+	.version('0.0.1')
+	.usage('dottojs')
+	.option('-s, --source [value]', 'source folder/file path')
+	.option('-d, --dest [value]', 'destination folder')
+	.option('-g, --global [value]', 'the global variable to install the templates in',"window.render")
+	.option('-p, --package [value]', 'if specified, package all templates from destination folder into specified file')
+	.parse(process.argv);
+
+if (program.dest) mkdirordie(program.dest);
+if (program.package) {
+	var li = program.package.lastIndexOf('/');
+	if (li>0) mkdirordie(program.package.substring(0, li));
+}
+
+function mkdirordie(path) {
+	require("mkdirp")(path, function (err) {
+    	if (err) {
+    		console.error(err);
+    		process.exit(1);
+    	}
+	});
+}
+
+var render = dot.process({
+		path: program.source,
+		destination: program.dest,
+		global: program.global
+	});
+
+if (program.package) {
+	console.log("Packaging all files into " + program.package);
+	var fs = require("fs");
+	var files = [];
+	var dest = program.dest || './';
+	if (dest[dest.length-1] !== '/') dest += '/';
+	var sources = fs.readdirSync(dest);
+	for(k = 0; k < sources.length; k++) {
+		name = sources[k];
+		if (/\.js$/.test(name)) {
+			files.push(dest + name);
+		}
+	}
+	var result = require("uglify-js").minify(files);
+	fs.writeFileSync(program.package, result.code);
+}

+ 21 - 0
static/static/lib/doT-1.1.3/bower.json

@@ -0,0 +1,21 @@
+{
+  "name": "dot",
+  "description": "Concise and fast javascript templating compatible with nodejs and other javascript environments",
+  "main": "doT.js",
+  "authors": [
+    "Laura Doktorova <ldoktorova@gmail.com>"
+  ],
+  "license": "MIT",
+  "keywords": [
+    "template",
+    "fast",
+    "simple",
+    "templating"
+  ],
+  "homepage": "https://github.com/olado/doT",
+  "ignore": [
+    "node_modules",
+    "bower_components",
+    "test"
+  ]
+}

+ 144 - 0
static/static/lib/doT-1.1.3/doT.js

@@ -0,0 +1,144 @@
+// doT.js
+// 2011-2014, Laura Doktorova, https://github.com/olado/doT
+// Licensed under the MIT license.
+
+(function () {
+	"use strict";
+
+	var doT = {
+		name: "doT",
+		version: "1.1.1",
+		templateSettings: {
+			evaluate:    /\{\{([\s\S]+?(\}?)+)\}\}/g,
+			interpolate: /\{\{=([\s\S]+?)\}\}/g,
+			encode:      /\{\{!([\s\S]+?)\}\}/g,
+			use:         /\{\{#([\s\S]+?)\}\}/g,
+			useParams:   /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
+			define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
+			defineParams:/^\s*([\w$]+):([\s\S]+)/,
+			conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
+			iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
+			varname:	"it",
+			strip:		true,
+			append:		true,
+			selfcontained: false,
+			doNotSkipEncoded: false
+		},
+		template: undefined, //fn, compile template
+		compile:  undefined, //fn, for express
+		log: true
+	}, _globals;
+
+	doT.encodeHTMLSource = function(doNotSkipEncoded) {
+		var encodeHTMLRules = { "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': "&#34;", "'": "&#39;", "/": "&#47;" },
+			matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g;
+		return function(code) {
+			return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : "";
+		};
+	};
+
+	_globals = (function(){ return this || (0,eval)("this"); }());
+
+	/* istanbul ignore else */
+	if (typeof module !== "undefined" && module.exports) {
+		module.exports = doT;
+	} else if (typeof define === "function" && define.amd) {
+		define(function(){return doT;});
+	} else {
+		_globals.doT = doT;
+	}
+
+	var startend = {
+		append: { start: "'+(",      end: ")+'",      startencode: "'+encodeHTML(" },
+		split:  { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" }
+	}, skip = /$^/;
+
+	function resolveDefs(c, block, def) {
+		return ((typeof block === "string") ? block : block.toString())
+		.replace(c.define || skip, function(m, code, assign, value) {
+			if (code.indexOf("def.") === 0) {
+				code = code.substring(4);
+			}
+			if (!(code in def)) {
+				if (assign === ":") {
+					if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
+						def[code] = {arg: param, text: v};
+					});
+					if (!(code in def)) def[code]= value;
+				} else {
+					new Function("def", "def['"+code+"']=" + value)(def);
+				}
+			}
+			return "";
+		})
+		.replace(c.use || skip, function(m, code) {
+			if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
+				if (def[d] && def[d].arg && param) {
+					var rw = (d+":"+param).replace(/'|\\/g, "_");
+					def.__exp = def.__exp || {};
+					def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
+					return s + "def.__exp['"+rw+"']";
+				}
+			});
+			var v = new Function("def", "return " + code)(def);
+			return v ? resolveDefs(c, v, def) : v;
+		});
+	}
+
+	function unescape(code) {
+		return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
+	}
+
+	doT.template = function(tmpl, c, def) {
+		c = c || doT.templateSettings;
+		var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
+			str  = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
+
+		str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ")
+					.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str)
+			.replace(/'|\\/g, "\\$&")
+			.replace(c.interpolate || skip, function(m, code) {
+				return cse.start + unescape(code) + cse.end;
+			})
+			.replace(c.encode || skip, function(m, code) {
+				needhtmlencode = true;
+				return cse.startencode + unescape(code) + cse.end;
+			})
+			.replace(c.conditional || skip, function(m, elsecase, code) {
+				return elsecase ?
+					(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
+					(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
+			})
+			.replace(c.iterate || skip, function(m, iterate, vname, iname) {
+				if (!iterate) return "';} } out+='";
+				sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
+				return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
+					+vname+"=arr"+sid+"["+indv+"+=1];out+='";
+			})
+			.replace(c.evaluate || skip, function(m, code) {
+				return "';" + unescape(code) + "out+='";
+			})
+			+ "';return out;")
+			.replace(/\n/g, "\\n").replace(/\t/g, '\\t').replace(/\r/g, "\\r")
+			.replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, "");
+			//.replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+=');
+
+		if (needhtmlencode) {
+			if (!c.selfcontained && _globals && !_globals._encodeHTML) _globals._encodeHTML = doT.encodeHTMLSource(c.doNotSkipEncoded);
+			str = "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("
+				+ doT.encodeHTMLSource.toString() + "(" + (c.doNotSkipEncoded || '') + "));"
+				+ str;
+		}
+		try {
+			return new Function(c.varname, str);
+		} catch (e) {
+			/* istanbul ignore else */
+			if (typeof console !== "undefined") console.log("Could not create a template function: " + str);
+			throw e;
+		}
+	};
+
+	doT.compile = function(tmpl, def) {
+		return doT.template(tmpl, null, def);
+	};
+}());

File diff suppressed because it is too large
+ 1 - 0
static/static/lib/doT-1.1.3/doT.min.js


+ 56 - 0
static/static/lib/doT-1.1.3/doU.js

@@ -0,0 +1,56 @@
+// doU.js
+// (c) 2011, Laura Doktorova
+// https://github.com/olado/doT
+//
+// doU is an extraction and slight modification of an excellent
+// templating function from jQote2.js (jQuery plugin) by aefxx
+// (http://aefxx.com/jquery-plugins/jqote2/).
+//
+// Modifications:
+// 1. nodejs support
+// 2. allow for custom template markers
+// 3. only allow direct invocation of the compiled function
+//
+// Licensed under the MIT license.
+
+(function() {
+	var doU = { version : '0.1.2' };
+
+	if (typeof module !== 'undefined' && module.exports) {
+		module.exports = doU;
+	} else {
+		this.doU = doU;
+	}
+
+	doU.templateSettings = {
+		begin : '{{',
+		end : '}}',
+		varname : 'it'
+	};
+
+	doU.template = function(tmpl, conf) {
+		conf = conf || doU.templateSettings;
+		var str = '', tb = conf.begin, te = conf.end, m, l,
+			arr = tmpl.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, '')
+				.split(tb).join(te +'\x1b')
+				.split(te);
+
+		for (m=0,l=arr.length; m < l; m++) {
+			str += arr[m].charAt(0) !== '\x1b' ?
+			"out+='" + arr[m].replace(/(\\|["'])/g, '\\$1') + "'" : (arr[m].charAt(1) === '=' ?
+			';out+=(' + arr[m].substr(2) + ');' : (arr[m].charAt(1) === '!' ?
+			';out+=(' + arr[m].substr(2) + ").toString().replace(/&(?!\\w+;)/g, '&#38;').split('<').join('&#60;').split('>').join('&#62;').split('" + '"' + "').join('&#34;').split(" + '"' + "'" + '"' + ").join('&#39;').split('/').join('&#x2F;');" : ';' + arr[m].substr(1)));
+		}
+
+		str = ('var out="";'+str+';return out;')
+			.split("out+='';").join('')
+			.split('var out="";out+=').join('var out=');
+
+		try {
+			return new Function(conf.varname, str);
+		} catch (e) {
+			if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
+			throw e;
+		}
+	};
+}());

+ 135 - 0
static/static/lib/doT-1.1.3/examples/advancedsnippet.txt

@@ -0,0 +1,135 @@
+Advanced templating: illustrates defines and includes.
+
+Include external snippet defined in a variable:
+{{#def.externalsnippet}}
+
+Load external template from a file:
+{{#def.loadfile('/snippet.txt')}}
+
+Load external template from a file and cache in a variable:
+{{#def['snippet.txt'] || (def['snippet.txt'] = def.loadfile('/snippet.txt'))}}
+
+Use cached file again:
+{{#def['snippet.txt']}}
+
+Here is a def block that will be used later. This snippet can be referenced from external templates too:
+{{##def.snippet1:
+	Some snippet that will be included {{#def.a}} later {{=it.f1}}
+#}}
+
+First use of snippet1:
+{{#def.snippet1}}
+
+Second use of snippet1:
+{{#def.snippet1}}
+
+Include snippet1 if true:
+{{# true && def.snippet1 }}
+
+Runtime and Compile time evaluation used together:
+{{= it.f3 + {{#def.a + def.b}} }}
+
+Include xyz or insert 'not found':
+{{#def.xyz || 'not found'}}
+
+Set xyz to 1 and exclude result from output:
+{{##def.xyz=1#}} is identical to {{#(def.xyz=1) && ""}}
+
+Compare xyz to 1, show 'xyz is not 1' if false:
+{{#def.xyz === 1 || 'xyz is not 1'}}
+
+{{ if ({{#!def.abc}}) { }}
+	{{#def.abc}} is falsy
+{{ } }}
+
+{{ if ({{#def.xyz === 1}}) { }}
+	if(true) block
+{{ } }}
+
+{{##def.fntest = function() {
+	return "Function test worked!";
+}
+#}}
+
+{{#def.fntest()}}
+
+Conditionals:
+{{? !it.altEmail }}
+	<p>
+	second email: {{= it.altEmail }}
+	</p>
+{{?? true }}
+	else case worked
+{{?}}
+
+Array iterators
+{{~ it.farray :p }}
+	<h1>{{=p.farray}}<h1>
+	{{~ p.farray :value:i }}
+		<h2>{{=i}}: {{=value}}</h2>
+		{{~ value :w }}
+			<h3>{{=w}}</h3>
+		{{~}}
+	{{~}}
+{{~}}
+
+{{~ ["apple", "banana", "orange"] :k}}
+	{{=k}}
+{{~}}
+
+{{~ (function(){ return [1,2,3]})() :k}}
+	{{=k}}
+{{~}}
+
+{{ function children(it) { }}
+
+{{?it.Nodes.length}}
+<ul>
+    {{~ it.Nodes :p}}
+    <li>
+        {{=p.title}}
+		{{children(p);}}
+    </li>
+    {{~}}
+</ul>
+{{?}}
+
+{{ } }}
+
+{{ children( {Nodes:[ {title:"1.1", Nodes:[ {title:"1.1.1", Nodes:[]}, {title:"1.1.2", Nodes:[]}] }, { title:"1.2", Nodes:[]}, { title:"1.3", Nodes:[]}], title:"1" } ); }}
+
+
+{{##def.block:param:
+	<div>{{=param}}</div>
+#}}
+
+{{##def.block1:param:
+	<div>{{=param.a}}</div>
+#}}
+
+
+{{#(def.block:'text' || '') + def.block:5}}
+
+{{#def.block:it.f3 || ''}}
+
+{{#def.block:"lala tralala" || ''}}
+
+{{#def.block1:{a:1, b:2} || ''}}
+
+{{##def.testFunctionWithParam = function(str) {
+		return "My name is: " + str;
+	}
+#}}
+
+{{##def.mytestparam: {{=it.name}} #}}
+{{#def.testFunctionWithParam(def.mytestparam)}}
+
+{{#def.testFunctionWithParam("\{\{=it.name\}\}")}}
+
+{{##def.testParamDef:myparam:
+My name is: {{=myparam}}
+#}}
+
+{{#def.testParamDef:it.name}}
+
+The end

+ 54 - 0
static/static/lib/doT-1.1.3/examples/browsersample.html

@@ -0,0 +1,54 @@
+<html>
+	<head>
+
+	<script id="headertmpl" type="text/x-dot-template">
+		<h1>{{=it.title}}</h1>
+	</script>
+
+	<script id="pagetmpl" type="text/x-dot-template">
+		<h2>Here is the page using a header template</h2>
+		{{#def.header}}
+		{{=it.name}}
+	</script>
+
+	<script id="customizableheadertmpl" type="text/x-dot-template">
+		 {{#def.header}}
+		 {{#def.mycustominjectionintoheader || ''}}
+	 </script>
+
+	<script id="pagetmplwithcustomizableheader" type="text/x-dot-template">
+		<h2>Here is the page with customized header template</h2>
+		{{##def.mycustominjectionintoheader:
+			<div>{{=it.title}} is not {{=it.name}}</div>
+		#}}
+		{{#def.customheader}}
+		{{=it.name}}
+	</script>
+
+	<script src="../doT.min.js" type="text/javascript"></script>
+	</head>
+
+	<body>
+		<div id="content"></div>
+		<div id="contentcustom"></div>
+	</body>
+
+	<script type="text/javascript">
+		var def = {
+			header: document.getElementById('headertmpl').text,
+			customheader: document.getElementById('customizableheadertmpl').text
+		};
+		var data = {
+			title: "My title",
+			name: "My name"
+		};
+
+		var pagefn = doT.template(document.getElementById('pagetmpl').text, undefined, def);
+		document.getElementById('content').innerHTML = pagefn(data);
+
+		pagefn = doT.template(document.getElementById('pagetmplwithcustomizableheader').text, undefined, def);
+		document.getElementById('contentcustom').innerHTML = pagefn(data);
+
+	</script>
+
+</html>

+ 19 - 0
static/static/lib/doT-1.1.3/examples/customdoT.js

@@ -0,0 +1,19 @@
+(function() {
+	var doT = require('../doT.js'),
+		data = { f1: 1, f2: 2, f3: 3},
+		snippet = '<h1>Just static text</h1> <p>Here is a simple case <?=it.f1+it.f3?> </p> <div class="<?=it.f1?>"> Next we will use a JavaScript block: </div> <? for(var i=0; i < it.f2; i++) { ?>	<div><?=it.f3?></div> <? }; ?>';
+
+	doT.templateSettings = {
+		evaluate : /\<\?([\s\S]+?)\?\>/g,
+		interpolate : /\<\?=([\s\S]+?)\?\>/g,
+		varname     : 'it',
+		strip: true
+	};
+
+
+
+	var doTCompiled = doT.template(snippet);
+
+	console.log("Generated function: \n" + doTCompiled.toString());
+	console.log("Result of calling with " + JSON.stringify(data) + " :\n" + doTCompiled(data));
+}());

+ 1 - 0
static/static/lib/doT-1.1.3/examples/express/index.js

@@ -0,0 +1 @@
+require("./lib/app");

+ 25 - 0
static/static/lib/doT-1.1.3/examples/express/lib/app.js

@@ -0,0 +1,25 @@
+require("dot").process({
+	global: "_page.render"
+	, destination: __dirname + "/render/"
+	, path: (__dirname + "/../templates")
+});
+
+var express = require('express')
+, http = require('http')
+, app = express()
+, render = require('./render')
+;
+
+app.get('/', function(req, res){
+  res.send(render.dashboard({text:"Good morning!"}));
+});
+
+app.use(function(err, req, res, next) {
+	console.error(err.stack);
+	res.status(500).send('Something broke!');
+});
+
+var httpServer = http.createServer(app);
+httpServer.listen(3000, function() {
+	console.log('Listening on port %d', httpServer.address().port);
+});

+ 18 - 0
static/static/lib/doT-1.1.3/examples/express/lib/render/index.js

@@ -0,0 +1,18 @@
+var path = require('path')
+	, fs = require('fs');
+
+function req(name) {
+	var module = require("./" + name);
+	delete exports[name];
+	return exports[name] = module;
+}
+
+fs.readdirSync(__dirname).forEach(function(file) {
+	if ((file === 'index.js') || (file[0] === '_')) { return; }
+	var ext = path.extname(file);
+	var stats = fs.statSync(__dirname + '/' + file);
+	if (stats.isFile() && !(ext in require.extensions)) { return; }
+	var basename = path.basename(file, '.js');
+  	exports.__defineGetter__(basename, function(){ return req(basename); });
+});
+

+ 10 - 0
static/static/lib/doT-1.1.3/examples/express/package.json

@@ -0,0 +1,10 @@
+{
+  "name": "dot-express-example",
+  "description": "doT express example",
+  "version": "0.0.1",
+  "private": true,
+  "dependencies": {
+    "express": "4.x",
+    "dot": "*"
+  }
+}

+ 5 - 0
static/static/lib/doT-1.1.3/examples/express/templates/dashboard.jst

@@ -0,0 +1,5 @@
+{{##def.test:
+	{{=it.text}}
+#}}
+
+{{#def.test}}

+ 34 - 0
static/static/lib/doT-1.1.3/examples/express/templates/login.jst

@@ -0,0 +1,34 @@
+<html>
+  <body>
+	<div>Signin</div>
+    <form action="/login" method="post">
+      <div>
+        <label>Username:</label>
+        <input type="text" name="username" />
+        <br/>
+      </div>
+      <div>
+        <label>Password:</label>
+        <input type="password" name="password" />
+      </div>
+      <div>
+        <input type="submit" value="Sign in" />
+      </div>
+    </form>
+	<div>Signup</div>
+    <form action="/signup" method="post">
+      <div>
+        <label>Username:</label>
+        <input type="text" name="username" />
+        <br/>
+      </div>
+      <div>
+        <label>Password:</label>
+        <input type="password" name="password" />
+      </div>
+      <div>
+        <input type="submit" value="Sign up" />
+      </div>
+    </form>
+   </body>
+</html>

+ 13 - 0
static/static/lib/doT-1.1.3/examples/snippet.txt

@@ -0,0 +1,13 @@
+Core templating
+
+<h1>Just static text</h1>
+<p>Interpolation {{=it.f1	+	it.f3}} </p>
+<div> JavaScript block evaluation
+{{ for(var i=0; i < it.f2; i++) {
+	console.log("Pass\t" + i);
+}}
+<div>{{=it.f3}}</div>
+{{ } }}
+</div>
+<div> Encoding {{!'<a 	href="http://github.com"></a>'}}</div>
+

+ 13 - 0
static/static/lib/doT-1.1.3/examples/views/multidef.def.jst

@@ -0,0 +1,13 @@
+{{##def.template1:
+	<div>{{=it.bar}}</div>
+	/* Including one.def file here */
+	{{#def.one}}
+#}}
+
+{{##def.template2:param:
+	<div>{{=param.bar}}</div>
+	<div class="{{=param.class}}">
+	</div>
+#}}
+
+

+ 2 - 0
static/static/lib/doT-1.1.3/examples/views/one.def

@@ -0,0 +1,2 @@
+/* This file can be inserted into other files */
+<div>{{=it.foo}}</div>

+ 17 - 0
static/static/lib/doT-1.1.3/examples/views/two.dot.jst

@@ -0,0 +1,17 @@
+/* Including multidef file */
+{{#def.multidef}}
+
+<div class="{{=it.class}}">
+	/* Including one.def file */
+	{{#def.one}}
+
+	/* Using sub-define from multidef */
+	{{#def.template2:{bar:"hello", class:"hidden"} }}
+
+	/* Using sub-define from multidef */
+	{{ var data = {bar:"world", class:"visible"}; }}
+	{{#def.template2:data}}
+</div>
+
+
+

+ 21 - 0
static/static/lib/doT-1.1.3/examples/withdoT.js

@@ -0,0 +1,21 @@
+(function() {
+	var doT = require('../doT.js'),
+		fs = require('fs'),
+		data = { name: "Foo", f1: 1, f2: 2, f3: 3, altEmail: "conditional works", farray:[{farray:[1,2,3,[11,22,33]],person:{name:'Ell',age:23}},{farray:{how:'really'}}, {farray:[5,6,7,8]}]},
+		defs = { a: 100, b: 200};
+
+	defs.loadfile = function(path) {
+		return fs.readFileSync(process.argv[1].replace(/\/[^\/]*$/,path));
+	};
+	defs.externalsnippet = defs.loadfile('/snippet.txt');
+
+	fs.readFile(process.argv[1].replace(/\/[^\/]*$/,'/advancedsnippet.txt'), function (err, snippet) {
+		if (err) {
+			console.log("Error reading advancedsnippet.txt " + err);
+		} else {
+			var doTCompiled = doT.template(snippet.toString(), undefined, defs);
+			console.log("Generated function: \n" + doTCompiled.toString());
+			console.log("Result of calling with " + JSON.stringify(data) + " :\n" + doTCompiled(data));
+		}
+	});
+}());

+ 150 - 0
static/static/lib/doT-1.1.3/index.js

@@ -0,0 +1,150 @@
+/* doT + auto-compilation of doT templates
+ *
+ * 2012, Laura Doktorova, https://github.com/olado/doT
+ * Licensed under the MIT license
+ *
+ * Compiles .def, .dot, .jst files found under the specified path.
+ * It ignores sub-directories.
+ * Template files can have multiple extensions at the same time.
+ * Files with .def extension can be included in other files via {{#def.name}}
+ * Files with .dot extension are compiled into functions with the same name and
+ * can be accessed as renderer.filename
+ * Files with .jst extension are compiled into .js files. Produced .js file can be
+ * loaded as a commonJS, AMD module, or just installed into a global variable
+ * (default is set to window.render).
+ * All inline defines defined in the .jst file are
+ * compiled into separate functions and are available via _render.filename.definename
+ *
+ * Basic usage:
+ * var dots = require("dot").process({path: "./views"});
+ * dots.mytemplate({foo:"hello world"});
+ *
+ * The above snippet will:
+ * 1. Compile all templates in views folder (.dot, .def, .jst)
+ * 2. Place .js files compiled from .jst templates into the same folder.
+ *    These files can be used with require, i.e. require("./views/mytemplate").
+ * 3. Return an object with functions compiled from .dot templates as its properties.
+ * 4. Render mytemplate template.
+ */
+
+var fs = require("fs"),
+	doT = module.exports = require("./doT");
+
+doT.process = function(options) {
+	//path, destination, global, rendermodule, templateSettings
+	return new InstallDots(options).compileAll();
+};
+
+function InstallDots(o) {
+	this.__path 		= o.path || "./";
+	if (this.__path[this.__path.length-1] !== '/') this.__path += '/';
+	this.__destination	= o.destination || this.__path;
+	if (this.__destination[this.__destination.length-1] !== '/') this.__destination += '/';
+	this.__global		= o.global || "window.render";
+	this.__rendermodule	= o.rendermodule || {};
+	this.__settings 	= Object.prototype.hasOwnProperty.call(o,"templateSettings") ? copy(o.templateSettings, copy(doT.templateSettings)) : undefined;
+	this.__includes		= {};
+}
+
+InstallDots.prototype.compileToFile = function(path, template, def) {
+	def = def || {};
+	var modulename = path.substring(path.lastIndexOf("/")+1, path.lastIndexOf("."))
+		, defs = copy(this.__includes, copy(def))
+		, settings = this.__settings || doT.templateSettings
+		, compileoptions = copy(settings)
+		, defaultcompiled = doT.template(template, settings, defs)
+		, exports = []
+		, compiled = ""
+		, fn;
+
+	for (var property in defs) {
+		// It looks like the code block inside "if" below can never be executed,
+		// because InstallDots constructor is private, compileToFile is only called from compileAll method
+		// and def parameter is never passed to it, so the condition in if will always fail.
+		// This code will be removed from the next major version.
+		// For now it is only excluded from coverage report
+		/* istanbul ignore if */
+		if (defs[property] !== def[property] && defs[property] !== this.__includes[property]) {
+			fn = undefined;
+			if (typeof defs[property] === 'string') {
+				fn = doT.template(defs[property], settings, defs);
+			} else if (typeof defs[property] === 'function') {
+				fn = defs[property];
+			} else if (defs[property].arg) {
+				compileoptions.varname = defs[property].arg;
+				fn = doT.template(defs[property].text, compileoptions, defs);
+			}
+			if (fn) {
+				compiled += fn.toString().replace('anonymous', property);
+				exports.push(property);
+			}
+		}
+	}
+	compiled += defaultcompiled.toString().replace('anonymous', modulename);
+	fs.writeFileSync(path, "(function(){" + compiled
+		+ "var itself=" + modulename + ", _encodeHTML=(" + doT.encodeHTMLSource.toString() + "(" + (settings.doNotSkipEncoded || '') + "));"
+		+ addexports(exports)
+		+ "if(typeof module!=='undefined' && module.exports) module.exports=itself;else if(typeof define==='function')define(function(){return itself;});else {"
+		+ this.__global + "=" + this.__global + "||{};" + this.__global + "['" + modulename + "']=itself;}}());");
+};
+
+function addexports(exports) {
+	var ret = '';
+	for (var i=0; i< exports.length; i++) {
+		ret += "itself." + exports[i]+ "=" + exports[i]+";";
+	}
+	return ret;
+}
+
+function copy(o, to) {
+	to = to || {};
+	for (var property in o) {
+		to[property] = o[property];
+	}
+	return to;
+}
+
+function readdata(path) {
+	var data = fs.readFileSync(path);
+	if (data) return data.toString();
+	console.log("problems with " + path);
+}
+
+InstallDots.prototype.compilePath = function(path) {
+	var data = readdata(path);
+	if (data) {
+		return doT.template(data,
+					this.__settings || doT.templateSettings,
+					copy(this.__includes));
+	}
+};
+
+InstallDots.prototype.compileAll = function() {
+	if (doT.log) console.log("Compiling all doT templates...");
+
+	var defFolder = this.__path,
+		sources = fs.readdirSync(defFolder),
+		k, l, name;
+
+	for( k = 0, l = sources.length; k < l; k++) {
+		name = sources[k];
+		if (/\.def(\.dot|\.jst)?$/.test(name)) {
+			if (doT.log) console.log("Loaded def " + name);
+			this.__includes[name.substring(0, name.indexOf('.'))] = readdata(defFolder + name);
+		}
+	}
+
+	for( k = 0, l = sources.length; k < l; k++) {
+		name = sources[k];
+		if (/\.dot(\.def|\.jst)?$/.test(name)) {
+			if (doT.log) console.log("Compiling " + name + " to function");
+			this.__rendermodule[name.substring(0, name.indexOf('.'))] = this.compilePath(defFolder + name);
+		}
+		if (/\.jst(\.dot|\.def)?$/.test(name)) {
+			if (doT.log) console.log("Compiling " + name + " to file");
+			this.compileToFile(this.__destination + name.substring(0, name.indexOf('.')) + '.js',
+					readdata(defFolder + name));
+		}
+	}
+	return this.__rendermodule;
+};

+ 54 - 0
static/static/lib/doT-1.1.3/package.json

@@ -0,0 +1,54 @@
+{
+  "name": "dot",
+  "description": "Concise and fast javascript templating compatible with nodejs and other javascript environments",
+  "keywords": [
+    "template",
+    "fast",
+    "simple",
+    "templating"
+  ],
+  "version": "1.1.3",
+  "main": "index.js",
+  "browser": "doT.js",
+  "bin": {
+    "dottojs": "./bin/dot-packer"
+  },
+  "homepage": "http://github.com/olado/doT",
+  "repository": "git://github.com/olado/doT.git",
+  "author": "Laura Doktorova <ldoktorova@gmail.com>",
+  "engines": [
+    "node >=0.2.6"
+  ],
+  "license": "MIT",
+  "scripts": {
+    "eslint": "if-node-version '>=4' eslint *.js --ignore-pattern *.min.js",
+    "test-spec": "mocha test/*.test.js",
+    "test-cov": "nyc npm run test-spec",
+    "test": "npm run eslint && npm run test-cov",
+    "bundle": "uglifyjs doT.js -o doT.min.js -c -m --preamble '/* Laura Doktorova https://github.com/olado/doT */'",
+    "prepublish": "npm run bundle"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "commander": "*",
+    "coveralls": "^3.0.9",
+    "eslint": "^6.7.2",
+    "if-node-version": "^1.1.1",
+    "jshint": "*",
+    "mkdirp": "*",
+    "mocha": "*",
+    "nyc": "^14.1.1",
+    "pre-commit": "^1.1.3",
+    "uglify-js": "*"
+  },
+  "nyc": {
+    "exclude": [
+      "test",
+      "node_modules"
+    ],
+    "reporter": [
+      "lcov",
+      "text-summary"
+    ]
+  }
+}

+ 55 - 0
static/static/lib/doT-1.1.3/test/conditionals.test.js

@@ -0,0 +1,55 @@
+'use strict';
+
+var test = require('./util').test;
+
+describe('conditionals', function() {
+    describe('without else', function() {
+        var templates = [
+            '{{?it.one < 2}}{{=it.one}}{{?}}{{=it.two}}',
+            '{{? it.one < 2 }}{{= it.one }}{{?}}{{= it.two }}'
+        ];
+
+        it('should evaluate condition and include template if valid', function() {
+            test(templates, {one: 1, two: 2}, '12')
+        });
+
+        it('should evaluate condition and do NOT include template if invalid', function() {
+            test(templates, {one: 3, two: 2}, '2')
+        });
+    });
+
+
+    describe('with else', function() {
+        var templates = [
+            '{{?it.one < 2}}{{=it.one}}{{??}}{{=it.two}}{{?}}',
+            '{{? it.one < 2 }}{{= it.one }}{{??}}{{= it.two }}{{?}}'
+        ];
+
+        it('should evaluate condition and include "if" template if valid', function() {
+            test(templates, {one: 1, two: 2}, '1')
+        });
+
+        it('should evaluate condition and include "else" template if invalid', function() {
+            test(templates, {one: 3, two: 2}, '2')
+        });
+    });
+
+    describe('with else if', function() {
+        var templates = [
+            '{{?it.one < 2}}{{=it.one}}{{??it.two < 3}}{{=it.two}}{{??}}{{=it.three}}{{?}}',
+            '{{? it.one < 2 }}{{= it.one }}{{?? it.two < 3 }}{{= it.two }}{{??}}{{= it.three }}{{?}}'
+        ];
+
+        it('should evaluate condition and include "if" template if valid', function() {
+            test(templates, {one: 1, two: 2, three: 3}, '1')
+        });
+
+        it('should evaluate condition and include "else if" template if second condition valid', function() {
+            test(templates, {one: 10, two: 2, three: 3}, '2')
+        });
+
+        it('should evaluate condition and include "else" template if invalid', function() {
+            test(templates, {one: 10, two: 20, three: 3}, '3')
+        });
+    });
+});

+ 29 - 0
static/static/lib/doT-1.1.3/test/defines.test.js

@@ -0,0 +1,29 @@
+'use strict';
+
+var doT = require('..');
+var assert = require('assert');
+
+describe('defines', function() {
+    describe('without parameters', function() {
+        it('should render define', function(){
+            testDef('{{##def.tmp:<div>{{!it.foo}}</div>#}}{{#def.tmp}}');
+        });
+
+        it('should render define if it is passed to doT.compile', function() {
+            testDef('{{#def.tmp}}', {tmp: '<div>{{!it.foo}}</div>'});
+        });
+    });
+
+    describe('with parameters', function() {
+        it('should render define', function(){
+            testDef('{{##def.tmp:foo:<div>{{!foo}}</div>#}}{{ var bar = it.foo; }}{{# def.tmp:bar }}');
+        });
+    });
+
+    function testDef(tmpl, defines) {
+        var fn = doT.compile(tmpl, defines);
+        assert.equal(fn({foo:'http'}), '<div>http</div>');
+        assert.equal(fn({foo:'http://abc.com'}), '<div>http:&#47;&#47;abc.com</div>');
+        assert.equal(fn({}), '<div></div>');
+    }
+});

+ 76 - 0
static/static/lib/doT-1.1.3/test/dot.test.js

@@ -0,0 +1,76 @@
+'use strict';
+
+var test = require('./util').test;
+var assert = require("assert")
+var doT = require("..");
+
+
+describe('doT', function(){
+	var basictemplate = "<div>{{!it.foo}}</div>";
+	var basiccompiled = doT.template(basictemplate);
+
+	describe('.name', function (){
+		it('should have a name', function(){
+			assert.strictEqual(doT.name, 'doT');
+		});
+	});
+	
+	describe('#template()', function(){
+		it('should return a function', function(){
+			assert.equal(typeof basiccompiled, "function");
+		});
+	});
+
+	describe('#()', function(){
+		it('should render the template', function(){
+			assert.equal(basiccompiled({foo:"http"}), "<div>http</div>");
+			assert.equal(basiccompiled({foo:"http://abc.com"}), "<div>http:&#47;&#47;abc.com</div>");
+			assert.equal(basiccompiled({}), "<div></div>");
+		});
+	});
+
+	describe('encoding with doNotSkipEncoded=false', function() {
+		it('should not replace &', function() {
+			global._encodeHTML = undefined;
+			doT.templateSettings.doNotSkipEncoded = false;
+			var fn = doT.template('<div>{{!it.foo}}</div>');
+			assert.equal(fn({foo:"&amp;"}), "<div>&amp;</div>");
+		});
+	});
+
+	describe('interpolate 2 numbers', function() {
+		it('should print numbers next to each other', function() {
+			test([
+				'{{=it.one}}{{=it.two}}',
+				'{{= it.one}}{{= it.two}}',
+				'{{= it.one }}{{= it.two }}'
+			], {one:1, two: 2}, '12');
+		});
+	});
+
+	describe('evaluate JavaScript', function() {
+		it('should print numbers next to each other', function() {
+			test([
+				'{{ it.one = 1; it.two = 2; }}{{= it.one }}{{= it.two }}',
+			], {}, '12');
+		});
+	});
+
+	describe('encoding with doNotSkipEncoded=true', function() {
+		it('should replace &', function() {
+			global._encodeHTML = undefined;
+			doT.templateSettings.doNotSkipEncoded = true;
+			assert.equal(doT.template('<div>{{!it.foo}}</div>')({foo:"&amp;"}), "<div>&#38;amp;</div>");
+			assert.equal(doT.template('{{!it.a}}')({a:"& < > / ' \""}), "&#38; &#60; &#62; &#47; &#39; &#34;");
+			assert.equal(doT.template('{{!"& < > / \' \\""}}')(), "&#38; &#60; &#62; &#47; &#39; &#34;");
+		});
+	});
+
+	describe('invalid JS in templates', function() {
+		it('should throw exception', function() {
+			assert.throws(function() {
+				var fn = doT.template('<div>{{= foo + }}</div>');
+			});
+		});
+	});
+});

+ 39 - 0
static/static/lib/doT-1.1.3/test/iteration.test.js

@@ -0,0 +1,39 @@
+'use strict';
+
+var test = require('./util').test;
+
+describe('iteration', function() {
+    describe('without index', function() {
+        it('should repeat string N times', function() {
+            test([
+                '{{~it.arr:x}}*{{~}}',
+                '{{~ it.arr:x }}*{{~}}',
+                '{{~ it.arr: x }}*{{~}}',
+                '{{~ it.arr :x }}*{{~}}'
+            ], {arr: Array(3)}, '***');
+        });
+
+        it('should concatenate items', function() {
+            test(['{{~it.arr:x}}{{=x}}{{~}}'], {arr: [1,2,3]}, '123');
+        });
+    });
+
+    describe('with index', function() {
+        it('should repeat string N times', function() {
+            test([
+                '{{~it.arr:x:i}}*{{~}}',
+                '{{~ it.arr : x : i }}*{{~}}'
+            ], {arr: Array(3)}, '***');
+        });
+
+        it('should concatenate indices', function() {
+            test(['{{~it.arr:x:i}}{{=i}}{{~}}'], {arr: Array(3)}, '012');
+        });
+
+        it('should concatenate indices and items', function() {
+            test([
+                '{{~it.arr:x:i}}{{?i}}, {{?}}{{=i}}:{{=x}}{{~}}'
+            ], {arr: [10,20,30]}, '0:10, 1:20, 2:30');
+        });
+    });
+});

+ 59 - 0
static/static/lib/doT-1.1.3/test/process.test.js

@@ -0,0 +1,59 @@
+'use strict';
+
+var assert = require('assert');
+var doT = require('..');
+var fs = require('fs');
+
+
+describe('doT.process', function() {
+  beforeEach(function() {
+    removeCompiledTemplateFiles();
+  });
+
+  afterEach(function() {
+    removeCompiledTemplateFiles();
+  });
+
+  function removeCompiledTemplateFiles() {
+    try { fs.unlinkSync('./test/templates/test.js'); } catch(e) {}
+  }
+
+  it('should compile all templates in folder', function() {
+    const templates = doT.process({path: './test/templates'});
+    var str = templates.test({data: 2});
+    assert.equal(str, '21');
+
+    var js = fs.statSync('./test/templates/test.js');
+    assert.ok(js.isFile());
+
+    // code below passes if the test is run without coverage using `npm run test-spec`
+    // because source code of doT.encodeHTMLSource is used inside compiled templates
+
+    // var fn = require('./templates/test.js');
+    // var str = fn({data: 2});
+    // assert.equal(str, '21');
+  });
+
+  
+	it('should ignore varname with polluted object prototype', function() {
+    var currentLog = console.log;
+    console.log = log;
+    var logged;
+    
+    Object.prototype.templateSettings = {varname: 'it=(console.log("executed"),{})'};
+
+    try {
+      const templates = doT.process({path: './test/templates'});
+      assert.notEqual(logged, 'executed');
+      // injected code can only be executed if undefined is passed to template function
+      templates.test();
+      assert.notEqual(logged, 'executed');
+    } finally {
+      console.log = currentLog;
+    }
+    
+    function log(str) {
+      logged = str;
+    }
+  });
+});

+ 1 - 0
static/static/lib/doT-1.1.3/test/templates/test.def

@@ -0,0 +1 @@
+1

+ 2 - 0
static/static/lib/doT-1.1.3/test/templates/test.dot

@@ -0,0 +1,2 @@
+{{=it && it.data}}
+{{#def.test}}

+ 2 - 0
static/static/lib/doT-1.1.3/test/templates/test.jst

@@ -0,0 +1,2 @@
+{{=it && it.data}}
+{{#def.test}}

+ 11 - 0
static/static/lib/doT-1.1.3/test/util.js

@@ -0,0 +1,11 @@
+'use strict';
+
+var assert = require('assert')
+var doT = require('../doT');
+
+exports.test = function (templates, data, result) {
+    templates.forEach(function (tmpl) {
+        var fn = doT.template(tmpl);
+        assert.strictEqual(fn(data), result);
+    });
+};

+ 20 - 0
static/static/lib/swiper/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2019 Vladimir Kharlampidi
+
+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.

+ 11 - 0
static/static/lib/swiper/README.md

@@ -0,0 +1,11 @@
+Swiper
+==========
+
+Swiper - is the free and most modern mobile touch slider with hardware accelerated transitions and amazing native behavior. It is intended to be used in mobile websites, mobile web apps, and mobile native/hybrid apps.
+
+Swiper is not compatible with all platforms, it is a modern touch slider which is focused only on modern apps/platforms to bring the best experience and simplicity.
+
+# Getting Started
+  * [Getting Started Guide](https://swiperjs.com/get-started/)
+  * [API](https://swiperjs.com/swiper-api/)
+  * [Demos](https://swiperjs.com/demos/)

+ 4 - 0
static/static/lib/swiper/angular/angular/src/public-api.d.ts

@@ -0,0 +1,4 @@
+export * from './swiper-events';
+export * from './swiper.module';
+export * from './swiper.component';
+export * from './swiper-slide.directive';

+ 4 - 0
static/static/lib/swiper/angular/angular/src/swiper-events.d.ts

@@ -0,0 +1,4 @@
+import { SwiperEvents } from 'swiper/types';
+export declare type EventsParams<T = SwiperEvents> = {
+    [P in keyof T]: T[P] extends (...args: any[]) => any ? Parameters<T[P]> : never;
+};

+ 27 - 0
static/static/lib/swiper/angular/angular/src/swiper-slide.directive.d.ts

@@ -0,0 +1,27 @@
+import { TemplateRef } from '@angular/core';
+import * as i0 from "@angular/core";
+export declare class SwiperSlideDirective {
+    template: TemplateRef<any>;
+    virtualIndex: number;
+    class: string;
+    set ngClass(val: string);
+    autoplayDelay: string | null;
+    set zoom(val: boolean);
+    get zoom(): boolean;
+    private _zoom;
+    slideIndex: number;
+    get classNames(): string;
+    set classNames(val: string);
+    private _hasClass;
+    slideData: {
+        isActive: boolean;
+        isPrev: boolean;
+        isNext: boolean;
+        isVisible: boolean;
+        isDuplicate: boolean;
+    };
+    private _classNames;
+    constructor(template: TemplateRef<any>);
+    static ɵfac: i0.ɵɵFactoryDeclaration<SwiperSlideDirective, never>;
+    static ɵdir: i0.ɵɵDirectiveDeclaration<SwiperSlideDirective, "ng-template[swiperSlide]", never, { "virtualIndex": "virtualIndex"; "class": "class"; "ngClass": "ngClass"; "autoplayDelay": "data-swiper-autoplay"; "zoom": "zoom"; }, {}, never>;
+}

File diff suppressed because it is too large
+ 255 - 0
static/static/lib/swiper/angular/angular/src/swiper.component.d.ts


+ 9 - 0
static/static/lib/swiper/angular/angular/src/swiper.module.d.ts

@@ -0,0 +1,9 @@
+import * as i0 from "@angular/core";
+import * as i1 from "./swiper.component";
+import * as i2 from "./swiper-slide.directive";
+import * as i3 from "@angular/common";
+export declare class SwiperModule {
+    static ɵfac: i0.ɵɵFactoryDeclaration<SwiperModule, never>;
+    static ɵmod: i0.ɵɵNgModuleDeclaration<SwiperModule, [typeof i1.SwiperComponent, typeof i2.SwiperSlideDirective], [typeof i3.CommonModule], [typeof i1.SwiperComponent, typeof i2.SwiperSlideDirective]>;
+    static ɵinj: i0.ɵɵInjectorDeclaration<SwiperModule>;
+}

+ 10 - 0
static/static/lib/swiper/angular/angular/src/utils/get-params.d.ts

@@ -0,0 +1,10 @@
+declare type KeyValueType = {
+    [x: string]: any;
+};
+export declare const allowedParams: string[];
+export declare function getParams(obj?: any): {
+    params: any;
+    passedParams: KeyValueType;
+    rest: KeyValueType;
+};
+export {};

+ 1 - 0
static/static/lib/swiper/angular/angular/src/utils/params-list.d.ts

@@ -0,0 +1 @@
+export declare const paramsList: string[];

+ 9 - 0
static/static/lib/swiper/angular/angular/src/utils/utils.d.ts

@@ -0,0 +1,9 @@
+export declare function isObject(o: any): boolean;
+export declare function isEnabled(val: boolean | {
+    enabled?: boolean;
+}): boolean;
+export declare function isShowEl(val: any, obj: any, el: any): boolean;
+export declare function extend(target: any, src: any): void;
+export declare function coerceBooleanProperty(value: any): boolean;
+export declare const ignoreNgOnChanges: string[];
+export declare function setProperty(val: any, obj?: {}): {} | false;

File diff suppressed because it is too large
+ 8 - 0
static/static/lib/swiper/angular/esm2020/angular/src/public-api.mjs


File diff suppressed because it is too large
+ 2 - 0
static/static/lib/swiper/angular/esm2020/angular/src/swiper-events.mjs


File diff suppressed because it is too large
+ 65 - 0
static/static/lib/swiper/angular/esm2020/angular/src/swiper-slide.directive.mjs


File diff suppressed because it is too large
+ 1023 - 0
static/static/lib/swiper/angular/esm2020/angular/src/swiper.component.mjs


File diff suppressed because it is too large
+ 19 - 0
static/static/lib/swiper/angular/esm2020/angular/src/swiper.module.mjs


File diff suppressed because it is too large
+ 47 - 0
static/static/lib/swiper/angular/esm2020/angular/src/utils/get-params.mjs


File diff suppressed because it is too large
+ 118 - 0
static/static/lib/swiper/angular/esm2020/angular/src/utils/params-list.mjs


File diff suppressed because it is too large
+ 52 - 0
static/static/lib/swiper/angular/esm2020/angular/src/utils/utils.mjs


+ 2 - 0
static/static/lib/swiper/angular/esm2020/swiper-angular.mjs

@@ -0,0 +1,2 @@
+export * from './angular/src/public-api';
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dpcGVyLWFuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3dpcGVyLWFuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYywwQkFBMEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vYW5ndWxhci9zcmMvcHVibGljLWFwaSc7XG4iXX0=

+ 5 - 0
static/static/lib/swiper/angular/esm2020/swiper_angular.mjs

@@ -0,0 +1,5 @@
+/**
+ * Generated bundle index. Do not edit.
+ */
+export * from './swiper-angular';
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dpcGVyX2FuZ3VsYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3dpcGVyX2FuZ3VsYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGtCQUFrQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3N3aXBlci1hbmd1bGFyJztcbiJdfQ==

File diff suppressed because it is too large
+ 1327 - 0
static/static/lib/swiper/angular/fesm2015/swiper_angular.mjs


File diff suppressed because it is too large
+ 1 - 0
static/static/lib/swiper/angular/fesm2015/swiper_angular.mjs.map


File diff suppressed because it is too large
+ 1320 - 0
static/static/lib/swiper/angular/fesm2020/swiper_angular.mjs


File diff suppressed because it is too large
+ 1 - 0
static/static/lib/swiper/angular/fesm2020/swiper_angular.mjs.map


+ 32 - 0
static/static/lib/swiper/angular/package.json

@@ -0,0 +1,32 @@
+{
+  "name": "swiper_angular",
+  "version": "0.0.1",
+  "private": "true",
+  "peerDependencies": {
+    "@angular/common": "^12.2.0 || ^13.0.0 || ^14.0.0",
+    "@angular/core": "^12.2.0 || ^13.0.0 || ^14.0.0"
+  },
+  "dependencies": {
+    "tslib": "^2.3.0"
+  },
+  "module": "fesm2015/swiper_angular.mjs",
+  "es2020": "fesm2020/swiper_angular.mjs",
+  "esm2020": "esm2020/swiper_angular.mjs",
+  "fesm2020": "fesm2020/swiper_angular.mjs",
+  "fesm2015": "fesm2015/swiper_angular.mjs",
+  "typings": "swiper_angular.d.ts",
+  "exports": {
+    "./package.json": {
+      "default": "./package.json"
+    },
+    ".": {
+      "types": "./swiper_angular.d.ts",
+      "esm2020": "./esm2020/swiper_angular.mjs",
+      "es2020": "./fesm2020/swiper_angular.mjs",
+      "es2015": "./fesm2015/swiper_angular.mjs",
+      "node": "./fesm2015/swiper_angular.mjs",
+      "default": "./fesm2020/swiper_angular.mjs"
+    }
+  },
+  "sideEffects": false
+}

+ 1 - 0
static/static/lib/swiper/angular/swiper-angular.d.ts

@@ -0,0 +1 @@
+export * from './angular/src/public-api';

+ 5 - 0
static/static/lib/swiper/angular/swiper_angular.d.ts

@@ -0,0 +1,5 @@
+/**
+ * Generated bundle index. Do not edit.
+ */
+/// <amd-module name="swiper_angular" />
+export * from './swiper-angular';

+ 46 - 0
static/static/lib/swiper/components-shared/get-changed-params.js

@@ -0,0 +1,46 @@
+import { paramsList } from './params-list.js';
+import { isObject } from './utils.js';
+
+function getChangedParams(swiperParams, oldParams, children, oldChildren, getKey) {
+  const keys = [];
+  if (!oldParams) return keys;
+
+  const addKey = key => {
+    if (keys.indexOf(key) < 0) keys.push(key);
+  };
+
+  if (children && oldChildren) {
+    const oldChildrenKeys = oldChildren.map(getKey);
+    const childrenKeys = children.map(getKey);
+    if (oldChildrenKeys.join('') !== childrenKeys.join('')) addKey('children');
+    if (oldChildren.length !== children.length) addKey('children');
+  }
+
+  const watchParams = paramsList.filter(key => key[0] === '_').map(key => key.replace(/_/, ''));
+  watchParams.forEach(key => {
+    if (key in swiperParams && key in oldParams) {
+      if (isObject(swiperParams[key]) && isObject(oldParams[key])) {
+        const newKeys = Object.keys(swiperParams[key]);
+        const oldKeys = Object.keys(oldParams[key]);
+
+        if (newKeys.length !== oldKeys.length) {
+          addKey(key);
+        } else {
+          newKeys.forEach(newKey => {
+            if (swiperParams[key][newKey] !== oldParams[key][newKey]) {
+              addKey(key);
+            }
+          });
+          oldKeys.forEach(oldKey => {
+            if (swiperParams[key][oldKey] !== oldParams[key][oldKey]) addKey(key);
+          });
+        }
+      } else if (swiperParams[key] !== oldParams[key]) {
+        addKey(key);
+      }
+    }
+  });
+  return keys;
+}
+
+export { getChangedParams };

+ 61 - 0
static/static/lib/swiper/components-shared/get-params.js

@@ -0,0 +1,61 @@
+import Swiper from 'swiper';
+import { isObject, extend } from './utils.js';
+import { paramsList } from './params-list.js';
+
+function getParams(obj, splitEvents) {
+  if (obj === void 0) {
+    obj = {};
+  }
+
+  if (splitEvents === void 0) {
+    splitEvents = true;
+  }
+
+  const params = {
+    on: {}
+  };
+  const events = {};
+  const passedParams = {};
+  extend(params, Swiper.defaults);
+  extend(params, Swiper.extendedDefaults);
+  params._emitClasses = true;
+  params.init = false;
+  const rest = {};
+  const allowedParams = paramsList.map(key => key.replace(/_/, ''));
+  const plainObj = Object.assign({}, obj);
+  Object.keys(plainObj).forEach(key => {
+    if (typeof obj[key] === 'undefined') return;
+
+    if (allowedParams.indexOf(key) >= 0) {
+      if (isObject(obj[key])) {
+        params[key] = {};
+        passedParams[key] = {};
+        extend(params[key], obj[key]);
+        extend(passedParams[key], obj[key]);
+      } else {
+        params[key] = obj[key];
+        passedParams[key] = obj[key];
+      }
+    } else if (key.search(/on[A-Z]/) === 0 && typeof obj[key] === 'function') {
+      if (splitEvents) {
+        events[`${key[2].toLowerCase()}${key.substr(3)}`] = obj[key];
+      } else {
+        params.on[`${key[2].toLowerCase()}${key.substr(3)}`] = obj[key];
+      }
+    } else {
+      rest[key] = obj[key];
+    }
+  });
+  ['navigation', 'pagination', 'scrollbar'].forEach(key => {
+    if (params[key] === true) params[key] = {};
+    if (params[key] === false) delete params[key];
+  });
+  return {
+    params,
+    passedParams,
+    rest,
+    events
+  };
+}
+
+export { getParams };

+ 33 - 0
static/static/lib/swiper/components-shared/mount-swiper.js

@@ -0,0 +1,33 @@
+import { needsNavigation, needsPagination, needsScrollbar } from './utils.js';
+
+function mountSwiper(_ref, swiperParams) {
+  let {
+    el,
+    nextEl,
+    prevEl,
+    paginationEl,
+    scrollbarEl,
+    swiper
+  } = _ref;
+
+  if (needsNavigation(swiperParams) && nextEl && prevEl) {
+    swiper.params.navigation.nextEl = nextEl;
+    swiper.originalParams.navigation.nextEl = nextEl;
+    swiper.params.navigation.prevEl = prevEl;
+    swiper.originalParams.navigation.prevEl = prevEl;
+  }
+
+  if (needsPagination(swiperParams) && paginationEl) {
+    swiper.params.pagination.el = paginationEl;
+    swiper.originalParams.pagination.el = paginationEl;
+  }
+
+  if (needsScrollbar(swiperParams) && scrollbarEl) {
+    swiper.params.scrollbar.el = scrollbarEl;
+    swiper.originalParams.scrollbar.el = scrollbarEl;
+  }
+
+  swiper.init(el);
+}
+
+export { mountSwiper };

File diff suppressed because it is too large
+ 4 - 0
static/static/lib/swiper/components-shared/params-list.js


+ 14 - 0
static/static/lib/swiper/components-shared/update-on-virtual-data.js

@@ -0,0 +1,14 @@
+export const updateOnVirtualData = swiper => {
+  if (!swiper || swiper.destroyed || !swiper.params.virtual || swiper.params.virtual && !swiper.params.virtual.enabled) return;
+  swiper.updateSlides();
+  swiper.updateProgress();
+  swiper.updateSlidesClasses();
+
+  if (swiper.lazy && swiper.params.lazy.enabled) {
+    swiper.lazy.load();
+  }
+
+  if (swiper.parallax && swiper.params.parallax && swiper.params.parallax.enabled) {
+    swiper.parallax.setTranslate();
+  }
+};

+ 136 - 0
static/static/lib/swiper/components-shared/update-swiper.js

@@ -0,0 +1,136 @@
+import { isObject, extend } from './utils.js';
+
+function updateSwiper(_ref) {
+  let {
+    swiper,
+    slides,
+    passedParams,
+    changedParams,
+    nextEl,
+    prevEl,
+    scrollbarEl,
+    paginationEl
+  } = _ref;
+  const updateParams = changedParams.filter(key => key !== 'children' && key !== 'direction');
+  const {
+    params: currentParams,
+    pagination,
+    navigation,
+    scrollbar,
+    virtual,
+    thumbs
+  } = swiper;
+  let needThumbsInit;
+  let needControllerInit;
+  let needPaginationInit;
+  let needScrollbarInit;
+  let needNavigationInit;
+
+  if (changedParams.includes('thumbs') && passedParams.thumbs && passedParams.thumbs.swiper && currentParams.thumbs && !currentParams.thumbs.swiper) {
+    needThumbsInit = true;
+  }
+
+  if (changedParams.includes('controller') && passedParams.controller && passedParams.controller.control && currentParams.controller && !currentParams.controller.control) {
+    needControllerInit = true;
+  }
+
+  if (changedParams.includes('pagination') && passedParams.pagination && (passedParams.pagination.el || paginationEl) && (currentParams.pagination || currentParams.pagination === false) && pagination && !pagination.el) {
+    needPaginationInit = true;
+  }
+
+  if (changedParams.includes('scrollbar') && passedParams.scrollbar && (passedParams.scrollbar.el || scrollbarEl) && (currentParams.scrollbar || currentParams.scrollbar === false) && scrollbar && !scrollbar.el) {
+    needScrollbarInit = true;
+  }
+
+  if (changedParams.includes('navigation') && passedParams.navigation && (passedParams.navigation.prevEl || prevEl) && (passedParams.navigation.nextEl || nextEl) && (currentParams.navigation || currentParams.navigation === false) && navigation && !navigation.prevEl && !navigation.nextEl) {
+    needNavigationInit = true;
+  }
+
+  const destroyModule = mod => {
+    if (!swiper[mod]) return;
+    swiper[mod].destroy();
+
+    if (mod === 'navigation') {
+      currentParams[mod].prevEl = undefined;
+      currentParams[mod].nextEl = undefined;
+      swiper[mod].prevEl = undefined;
+      swiper[mod].nextEl = undefined;
+    } else {
+      currentParams[mod].el = undefined;
+      swiper[mod].el = undefined;
+    }
+  };
+
+  updateParams.forEach(key => {
+    if (isObject(currentParams[key]) && isObject(passedParams[key])) {
+      extend(currentParams[key], passedParams[key]);
+    } else {
+      const newValue = passedParams[key];
+
+      if ((newValue === true || newValue === false) && (key === 'navigation' || key === 'pagination' || key === 'scrollbar')) {
+        if (newValue === false) {
+          destroyModule(key);
+        }
+      } else {
+        currentParams[key] = passedParams[key];
+      }
+    }
+  });
+
+  if (updateParams.includes('controller') && !needControllerInit && swiper.controller && swiper.controller.control && currentParams.controller && currentParams.controller.control) {
+    swiper.controller.control = currentParams.controller.control;
+  }
+
+  if (changedParams.includes('children') && slides && virtual && currentParams.virtual.enabled) {
+    virtual.slides = slides;
+    virtual.update(true);
+  } else if (changedParams.includes('children') && swiper.lazy && swiper.params.lazy.enabled) {
+    swiper.lazy.load();
+  }
+
+  if (needThumbsInit) {
+    const initialized = thumbs.init();
+    if (initialized) thumbs.update(true);
+  }
+
+  if (needControllerInit) {
+    swiper.controller.control = currentParams.controller.control;
+  }
+
+  if (needPaginationInit) {
+    if (paginationEl) currentParams.pagination.el = paginationEl;
+    pagination.init();
+    pagination.render();
+    pagination.update();
+  }
+
+  if (needScrollbarInit) {
+    if (scrollbarEl) currentParams.scrollbar.el = scrollbarEl;
+    scrollbar.init();
+    scrollbar.updateSize();
+    scrollbar.setTranslate();
+  }
+
+  if (needNavigationInit) {
+    if (nextEl) currentParams.navigation.nextEl = nextEl;
+    if (prevEl) currentParams.navigation.prevEl = prevEl;
+    navigation.init();
+    navigation.update();
+  }
+
+  if (changedParams.includes('allowSlideNext')) {
+    swiper.allowSlideNext = passedParams.allowSlideNext;
+  }
+
+  if (changedParams.includes('allowSlidePrev')) {
+    swiper.allowSlidePrev = passedParams.allowSlidePrev;
+  }
+
+  if (changedParams.includes('direction')) {
+    swiper.changeDirection(passedParams.direction, false);
+  }
+
+  swiper.update();
+}
+
+export { updateSwiper };

+ 53 - 0
static/static/lib/swiper/components-shared/utils.js

@@ -0,0 +1,53 @@
+function isObject(o) {
+  return typeof o === 'object' && o !== null && o.constructor && Object.prototype.toString.call(o).slice(8, -1) === 'Object';
+}
+
+function extend(target, src) {
+  const noExtend = ['__proto__', 'constructor', 'prototype'];
+  Object.keys(src).filter(key => noExtend.indexOf(key) < 0).forEach(key => {
+    if (typeof target[key] === 'undefined') target[key] = src[key];else if (isObject(src[key]) && isObject(target[key]) && Object.keys(src[key]).length > 0) {
+      if (src[key].__swiper__) target[key] = src[key];else extend(target[key], src[key]);
+    } else {
+      target[key] = src[key];
+    }
+  });
+}
+
+function needsNavigation(params) {
+  if (params === void 0) {
+    params = {};
+  }
+
+  return params.navigation && typeof params.navigation.nextEl === 'undefined' && typeof params.navigation.prevEl === 'undefined';
+}
+
+function needsPagination(params) {
+  if (params === void 0) {
+    params = {};
+  }
+
+  return params.pagination && typeof params.pagination.el === 'undefined';
+}
+
+function needsScrollbar(params) {
+  if (params === void 0) {
+    params = {};
+  }
+
+  return params.scrollbar && typeof params.scrollbar.el === 'undefined';
+}
+
+function uniqueClasses(classNames) {
+  if (classNames === void 0) {
+    classNames = '';
+  }
+
+  const classes = classNames.split(' ').map(c => c.trim()).filter(c => !!c);
+  const unique = [];
+  classes.forEach(c => {
+    if (unique.indexOf(c) < 0) unique.push(c);
+  });
+  return unique.join(' ');
+}
+
+export { isObject, extend, needsNavigation, needsPagination, needsScrollbar, uniqueClasses };

+ 44 - 0
static/static/lib/swiper/core/breakpoints/getBreakpoint.js

@@ -0,0 +1,44 @@
+import { getWindow } from 'ssr-window';
+export default function getBreakpoint(breakpoints, base, containerEl) {
+  if (base === void 0) {
+    base = 'window';
+  }
+
+  if (!breakpoints || base === 'container' && !containerEl) return undefined;
+  let breakpoint = false;
+  const window = getWindow();
+  const currentHeight = base === 'window' ? window.innerHeight : containerEl.clientHeight;
+  const points = Object.keys(breakpoints).map(point => {
+    if (typeof point === 'string' && point.indexOf('@') === 0) {
+      const minRatio = parseFloat(point.substr(1));
+      const value = currentHeight * minRatio;
+      return {
+        value,
+        point
+      };
+    }
+
+    return {
+      value: point,
+      point
+    };
+  });
+  points.sort((a, b) => parseInt(a.value, 10) - parseInt(b.value, 10));
+
+  for (let i = 0; i < points.length; i += 1) {
+    const {
+      point,
+      value
+    } = points[i];
+
+    if (base === 'window') {
+      if (window.matchMedia(`(min-width: ${value}px)`).matches) {
+        breakpoint = point;
+      }
+    } else if (value <= containerEl.clientWidth) {
+      breakpoint = point;
+    }
+  }
+
+  return breakpoint || 'max';
+}

+ 6 - 0
static/static/lib/swiper/core/breakpoints/index.js

@@ -0,0 +1,6 @@
+import setBreakpoint from './setBreakpoint.js';
+import getBreakpoint from './getBreakpoint.js';
+export default {
+  setBreakpoint,
+  getBreakpoint
+};

+ 85 - 0
static/static/lib/swiper/core/breakpoints/setBreakpoint.js

@@ -0,0 +1,85 @@
+import { extend } from '../../shared/utils.js';
+
+const isGridEnabled = (swiper, params) => {
+  return swiper.grid && params.grid && params.grid.rows > 1;
+};
+
+export default function setBreakpoint() {
+  const swiper = this;
+  const {
+    activeIndex,
+    initialized,
+    loopedSlides = 0,
+    params,
+    $el
+  } = swiper;
+  const breakpoints = params.breakpoints;
+  if (!breakpoints || breakpoints && Object.keys(breakpoints).length === 0) return; // Get breakpoint for window width and update parameters
+
+  const breakpoint = swiper.getBreakpoint(breakpoints, swiper.params.breakpointsBase, swiper.el);
+  if (!breakpoint || swiper.currentBreakpoint === breakpoint) return;
+  const breakpointOnlyParams = breakpoint in breakpoints ? breakpoints[breakpoint] : undefined;
+  const breakpointParams = breakpointOnlyParams || swiper.originalParams;
+  const wasMultiRow = isGridEnabled(swiper, params);
+  const isMultiRow = isGridEnabled(swiper, breakpointParams);
+  const wasEnabled = params.enabled;
+
+  if (wasMultiRow && !isMultiRow) {
+    $el.removeClass(`${params.containerModifierClass}grid ${params.containerModifierClass}grid-column`);
+    swiper.emitContainerClasses();
+  } else if (!wasMultiRow && isMultiRow) {
+    $el.addClass(`${params.containerModifierClass}grid`);
+
+    if (breakpointParams.grid.fill && breakpointParams.grid.fill === 'column' || !breakpointParams.grid.fill && params.grid.fill === 'column') {
+      $el.addClass(`${params.containerModifierClass}grid-column`);
+    }
+
+    swiper.emitContainerClasses();
+  } // Toggle navigation, pagination, scrollbar
+
+
+  ['navigation', 'pagination', 'scrollbar'].forEach(prop => {
+    const wasModuleEnabled = params[prop] && params[prop].enabled;
+    const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;
+
+    if (wasModuleEnabled && !isModuleEnabled) {
+      swiper[prop].disable();
+    }
+
+    if (!wasModuleEnabled && isModuleEnabled) {
+      swiper[prop].enable();
+    }
+  });
+  const directionChanged = breakpointParams.direction && breakpointParams.direction !== params.direction;
+  const needsReLoop = params.loop && (breakpointParams.slidesPerView !== params.slidesPerView || directionChanged);
+
+  if (directionChanged && initialized) {
+    swiper.changeDirection();
+  }
+
+  extend(swiper.params, breakpointParams);
+  const isEnabled = swiper.params.enabled;
+  Object.assign(swiper, {
+    allowTouchMove: swiper.params.allowTouchMove,
+    allowSlideNext: swiper.params.allowSlideNext,
+    allowSlidePrev: swiper.params.allowSlidePrev
+  });
+
+  if (wasEnabled && !isEnabled) {
+    swiper.disable();
+  } else if (!wasEnabled && isEnabled) {
+    swiper.enable();
+  }
+
+  swiper.currentBreakpoint = breakpoint;
+  swiper.emit('_beforeBreakpoint', breakpointParams);
+
+  if (needsReLoop && initialized) {
+    swiper.loopDestroy();
+    swiper.loopCreate();
+    swiper.updateSlides();
+    swiper.slideTo(activeIndex - loopedSlides + swiper.loopedSlides, 0, false);
+  }
+
+  swiper.emit('breakpoint', breakpointParams);
+}

+ 38 - 0
static/static/lib/swiper/core/check-overflow/index.js

@@ -0,0 +1,38 @@
+function checkOverflow() {
+  const swiper = this;
+  const {
+    isLocked: wasLocked,
+    params
+  } = swiper;
+  const {
+    slidesOffsetBefore
+  } = params;
+
+  if (slidesOffsetBefore) {
+    const lastSlideIndex = swiper.slides.length - 1;
+    const lastSlideRightEdge = swiper.slidesGrid[lastSlideIndex] + swiper.slidesSizesGrid[lastSlideIndex] + slidesOffsetBefore * 2;
+    swiper.isLocked = swiper.size > lastSlideRightEdge;
+  } else {
+    swiper.isLocked = swiper.snapGrid.length === 1;
+  }
+
+  if (params.allowSlideNext === true) {
+    swiper.allowSlideNext = !swiper.isLocked;
+  }
+
+  if (params.allowSlidePrev === true) {
+    swiper.allowSlidePrev = !swiper.isLocked;
+  }
+
+  if (wasLocked && wasLocked !== swiper.isLocked) {
+    swiper.isEnd = false;
+  }
+
+  if (wasLocked !== swiper.isLocked) {
+    swiper.emit(swiper.isLocked ? 'lock' : 'unlock');
+  }
+}
+
+export default {
+  checkOverflow
+};

+ 54 - 0
static/static/lib/swiper/core/classes/addClasses.js

@@ -0,0 +1,54 @@
+function prepareClasses(entries, prefix) {
+  const resultClasses = [];
+  entries.forEach(item => {
+    if (typeof item === 'object') {
+      Object.keys(item).forEach(classNames => {
+        if (item[classNames]) {
+          resultClasses.push(prefix + classNames);
+        }
+      });
+    } else if (typeof item === 'string') {
+      resultClasses.push(prefix + item);
+    }
+  });
+  return resultClasses;
+}
+
+export default function addClasses() {
+  const swiper = this;
+  const {
+    classNames,
+    params,
+    rtl,
+    $el,
+    device,
+    support
+  } = swiper; // prettier-ignore
+
+  const suffixes = prepareClasses(['initialized', params.direction, {
+    'pointer-events': !support.touch
+  }, {
+    'free-mode': swiper.params.freeMode && params.freeMode.enabled
+  }, {
+    'autoheight': params.autoHeight
+  }, {
+    'rtl': rtl
+  }, {
+    'grid': params.grid && params.grid.rows > 1
+  }, {
+    'grid-column': params.grid && params.grid.rows > 1 && params.grid.fill === 'column'
+  }, {
+    'android': device.android
+  }, {
+    'ios': device.ios
+  }, {
+    'css-mode': params.cssMode
+  }, {
+    'centered': params.cssMode && params.centeredSlides
+  }, {
+    'watch-progress': params.watchSlidesProgress
+  }], params.containerModifierClass);
+  classNames.push(...suffixes);
+  $el.addClass([...classNames].join(' '));
+  swiper.emitContainerClasses();
+}

+ 6 - 0
static/static/lib/swiper/core/classes/index.js

@@ -0,0 +1,6 @@
+import addClasses from './addClasses.js';
+import removeClasses from './removeClasses.js';
+export default {
+  addClasses,
+  removeClasses
+};

+ 9 - 0
static/static/lib/swiper/core/classes/removeClasses.js

@@ -0,0 +1,9 @@
+export default function removeClasses() {
+  const swiper = this;
+  const {
+    $el,
+    classNames
+  } = swiper;
+  $el.removeClass(classNames.join(' '));
+  swiper.emitContainerClasses();
+}

+ 656 - 0
static/static/lib/swiper/core/core.js

@@ -0,0 +1,656 @@
+/* eslint no-param-reassign: "off" */
+import { getDocument } from 'ssr-window';
+import $ from '../shared/dom.js';
+import { extend, now, deleteProps } from '../shared/utils.js';
+import { getSupport } from '../shared/get-support.js';
+import { getDevice } from '../shared/get-device.js';
+import { getBrowser } from '../shared/get-browser.js';
+import Resize from './modules/resize/resize.js';
+import Observer from './modules/observer/observer.js';
+import eventsEmitter from './events-emitter.js';
+import update from './update/index.js';
+import translate from './translate/index.js';
+import transition from './transition/index.js';
+import slide from './slide/index.js';
+import loop from './loop/index.js';
+import grabCursor from './grab-cursor/index.js';
+import events from './events/index.js';
+import breakpoints from './breakpoints/index.js';
+import classes from './classes/index.js';
+import images from './images/index.js';
+import checkOverflow from './check-overflow/index.js';
+import defaults from './defaults.js';
+import moduleExtendParams from './moduleExtendParams.js';
+const prototypes = {
+  eventsEmitter,
+  update,
+  translate,
+  transition,
+  slide,
+  loop,
+  grabCursor,
+  events,
+  breakpoints,
+  checkOverflow,
+  classes,
+  images
+};
+const extendedDefaults = {};
+
+class Swiper {
+  constructor() {
+    let el;
+    let params;
+
+    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
+    }
+
+    if (args.length === 1 && args[0].constructor && Object.prototype.toString.call(args[0]).slice(8, -1) === 'Object') {
+      params = args[0];
+    } else {
+      [el, params] = args;
+    }
+
+    if (!params) params = {};
+    params = extend({}, params);
+    if (el && !params.el) params.el = el;
+
+    if (params.el && $(params.el).length > 1) {
+      const swipers = [];
+      $(params.el).each(containerEl => {
+        const newParams = extend({}, params, {
+          el: containerEl
+        });
+        swipers.push(new Swiper(newParams));
+      });
+      return swipers;
+    } // Swiper Instance
+
+
+    const swiper = this;
+    swiper.__swiper__ = true;
+    swiper.support = getSupport();
+    swiper.device = getDevice({
+      userAgent: params.userAgent
+    });
+    swiper.browser = getBrowser();
+    swiper.eventsListeners = {};
+    swiper.eventsAnyListeners = [];
+    swiper.modules = [...swiper.__modules__];
+
+    if (params.modules && Array.isArray(params.modules)) {
+      swiper.modules.push(...params.modules);
+    }
+
+    const allModulesParams = {};
+    swiper.modules.forEach(mod => {
+      mod({
+        swiper,
+        extendParams: moduleExtendParams(params, allModulesParams),
+        on: swiper.on.bind(swiper),
+        once: swiper.once.bind(swiper),
+        off: swiper.off.bind(swiper),
+        emit: swiper.emit.bind(swiper)
+      });
+    }); // Extend defaults with modules params
+
+    const swiperParams = extend({}, defaults, allModulesParams); // Extend defaults with passed params
+
+    swiper.params = extend({}, swiperParams, extendedDefaults, params);
+    swiper.originalParams = extend({}, swiper.params);
+    swiper.passedParams = extend({}, params); // add event listeners
+
+    if (swiper.params && swiper.params.on) {
+      Object.keys(swiper.params.on).forEach(eventName => {
+        swiper.on(eventName, swiper.params.on[eventName]);
+      });
+    }
+
+    if (swiper.params && swiper.params.onAny) {
+      swiper.onAny(swiper.params.onAny);
+    } // Save Dom lib
+
+
+    swiper.$ = $; // Extend Swiper
+
+    Object.assign(swiper, {
+      enabled: swiper.params.enabled,
+      el,
+      // Classes
+      classNames: [],
+      // Slides
+      slides: $(),
+      slidesGrid: [],
+      snapGrid: [],
+      slidesSizesGrid: [],
+
+      // isDirection
+      isHorizontal() {
+        return swiper.params.direction === 'horizontal';
+      },
+
+      isVertical() {
+        return swiper.params.direction === 'vertical';
+      },
+
+      // Indexes
+      activeIndex: 0,
+      realIndex: 0,
+      //
+      isBeginning: true,
+      isEnd: false,
+      // Props
+      translate: 0,
+      previousTranslate: 0,
+      progress: 0,
+      velocity: 0,
+      animating: false,
+      // Locks
+      allowSlideNext: swiper.params.allowSlideNext,
+      allowSlidePrev: swiper.params.allowSlidePrev,
+      // Touch Events
+      touchEvents: function touchEvents() {
+        const touch = ['touchstart', 'touchmove', 'touchend', 'touchcancel'];
+        const desktop = ['pointerdown', 'pointermove', 'pointerup'];
+        swiper.touchEventsTouch = {
+          start: touch[0],
+          move: touch[1],
+          end: touch[2],
+          cancel: touch[3]
+        };
+        swiper.touchEventsDesktop = {
+          start: desktop[0],
+          move: desktop[1],
+          end: desktop[2]
+        };
+        return swiper.support.touch || !swiper.params.simulateTouch ? swiper.touchEventsTouch : swiper.touchEventsDesktop;
+      }(),
+      touchEventsData: {
+        isTouched: undefined,
+        isMoved: undefined,
+        allowTouchCallbacks: undefined,
+        touchStartTime: undefined,
+        isScrolling: undefined,
+        currentTranslate: undefined,
+        startTranslate: undefined,
+        allowThresholdMove: undefined,
+        // Form elements to match
+        focusableElements: swiper.params.focusableElements,
+        // Last click time
+        lastClickTime: now(),
+        clickTimeout: undefined,
+        // Velocities
+        velocities: [],
+        allowMomentumBounce: undefined,
+        isTouchEvent: undefined,
+        startMoving: undefined
+      },
+      // Clicks
+      allowClick: true,
+      // Touches
+      allowTouchMove: swiper.params.allowTouchMove,
+      touches: {
+        startX: 0,
+        startY: 0,
+        currentX: 0,
+        currentY: 0,
+        diff: 0
+      },
+      // Images
+      imagesToLoad: [],
+      imagesLoaded: 0
+    });
+    swiper.emit('_swiper'); // Init
+
+    if (swiper.params.init) {
+      swiper.init();
+    } // Return app instance
+
+
+    return swiper;
+  }
+
+  enable() {
+    const swiper = this;
+    if (swiper.enabled) return;
+    swiper.enabled = true;
+
+    if (swiper.params.grabCursor) {
+      swiper.setGrabCursor();
+    }
+
+    swiper.emit('enable');
+  }
+
+  disable() {
+    const swiper = this;
+    if (!swiper.enabled) return;
+    swiper.enabled = false;
+
+    if (swiper.params.grabCursor) {
+      swiper.unsetGrabCursor();
+    }
+
+    swiper.emit('disable');
+  }
+
+  setProgress(progress, speed) {
+    const swiper = this;
+    progress = Math.min(Math.max(progress, 0), 1);
+    const min = swiper.minTranslate();
+    const max = swiper.maxTranslate();
+    const current = (max - min) * progress + min;
+    swiper.translateTo(current, typeof speed === 'undefined' ? 0 : speed);
+    swiper.updateActiveIndex();
+    swiper.updateSlidesClasses();
+  }
+
+  emitContainerClasses() {
+    const swiper = this;
+    if (!swiper.params._emitClasses || !swiper.el) return;
+    const cls = swiper.el.className.split(' ').filter(className => {
+      return className.indexOf('swiper') === 0 || className.indexOf(swiper.params.containerModifierClass) === 0;
+    });
+    swiper.emit('_containerClasses', cls.join(' '));
+  }
+
+  getSlideClasses(slideEl) {
+    const swiper = this;
+    if (swiper.destroyed) return '';
+    return slideEl.className.split(' ').filter(className => {
+      return className.indexOf('swiper-slide') === 0 || className.indexOf(swiper.params.slideClass) === 0;
+    }).join(' ');
+  }
+
+  emitSlidesClasses() {
+    const swiper = this;
+    if (!swiper.params._emitClasses || !swiper.el) return;
+    const updates = [];
+    swiper.slides.each(slideEl => {
+      const classNames = swiper.getSlideClasses(slideEl);
+      updates.push({
+        slideEl,
+        classNames
+      });
+      swiper.emit('_slideClass', slideEl, classNames);
+    });
+    swiper.emit('_slideClasses', updates);
+  }
+
+  slidesPerViewDynamic(view, exact) {
+    if (view === void 0) {
+      view = 'current';
+    }
+
+    if (exact === void 0) {
+      exact = false;
+    }
+
+    const swiper = this;
+    const {
+      params,
+      slides,
+      slidesGrid,
+      slidesSizesGrid,
+      size: swiperSize,
+      activeIndex
+    } = swiper;
+    let spv = 1;
+
+    if (params.centeredSlides) {
+      let slideSize = slides[activeIndex].swiperSlideSize;
+      let breakLoop;
+
+      for (let i = activeIndex + 1; i < slides.length; i += 1) {
+        if (slides[i] && !breakLoop) {
+          slideSize += slides[i].swiperSlideSize;
+          spv += 1;
+          if (slideSize > swiperSize) breakLoop = true;
+        }
+      }
+
+      for (let i = activeIndex - 1; i >= 0; i -= 1) {
+        if (slides[i] && !breakLoop) {
+          slideSize += slides[i].swiperSlideSize;
+          spv += 1;
+          if (slideSize > swiperSize) breakLoop = true;
+        }
+      }
+    } else {
+      // eslint-disable-next-line
+      if (view === 'current') {
+        for (let i = activeIndex + 1; i < slides.length; i += 1) {
+          const slideInView = exact ? slidesGrid[i] + slidesSizesGrid[i] - slidesGrid[activeIndex] < swiperSize : slidesGrid[i] - slidesGrid[activeIndex] < swiperSize;
+
+          if (slideInView) {
+            spv += 1;
+          }
+        }
+      } else {
+        // previous
+        for (let i = activeIndex - 1; i >= 0; i -= 1) {
+          const slideInView = slidesGrid[activeIndex] - slidesGrid[i] < swiperSize;
+
+          if (slideInView) {
+            spv += 1;
+          }
+        }
+      }
+    }
+
+    return spv;
+  }
+
+  update() {
+    const swiper = this;
+    if (!swiper || swiper.destroyed) return;
+    const {
+      snapGrid,
+      params
+    } = swiper; // Breakpoints
+
+    if (params.breakpoints) {
+      swiper.setBreakpoint();
+    }
+
+    swiper.updateSize();
+    swiper.updateSlides();
+    swiper.updateProgress();
+    swiper.updateSlidesClasses();
+
+    function setTranslate() {
+      const translateValue = swiper.rtlTranslate ? swiper.translate * -1 : swiper.translate;
+      const newTranslate = Math.min(Math.max(translateValue, swiper.maxTranslate()), swiper.minTranslate());
+      swiper.setTranslate(newTranslate);
+      swiper.updateActiveIndex();
+      swiper.updateSlidesClasses();
+    }
+
+    let translated;
+
+    if (swiper.params.freeMode && swiper.params.freeMode.enabled) {
+      setTranslate();
+
+      if (swiper.params.autoHeight) {
+        swiper.updateAutoHeight();
+      }
+    } else {
+      if ((swiper.params.slidesPerView === 'auto' || swiper.params.slidesPerView > 1) && swiper.isEnd && !swiper.params.centeredSlides) {
+        translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
+      } else {
+        translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
+      }
+
+      if (!translated) {
+        setTranslate();
+      }
+    }
+
+    if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
+      swiper.checkOverflow();
+    }
+
+    swiper.emit('update');
+  }
+
+  changeDirection(newDirection, needUpdate) {
+    if (needUpdate === void 0) {
+      needUpdate = true;
+    }
+
+    const swiper = this;
+    const currentDirection = swiper.params.direction;
+
+    if (!newDirection) {
+      // eslint-disable-next-line
+      newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
+    }
+
+    if (newDirection === currentDirection || newDirection !== 'horizontal' && newDirection !== 'vertical') {
+      return swiper;
+    }
+
+    swiper.$el.removeClass(`${swiper.params.containerModifierClass}${currentDirection}`).addClass(`${swiper.params.containerModifierClass}${newDirection}`);
+    swiper.emitContainerClasses();
+    swiper.params.direction = newDirection;
+    swiper.slides.each(slideEl => {
+      if (newDirection === 'vertical') {
+        slideEl.style.width = '';
+      } else {
+        slideEl.style.height = '';
+      }
+    });
+    swiper.emit('changeDirection');
+    if (needUpdate) swiper.update();
+    return swiper;
+  }
+
+  changeLanguageDirection(direction) {
+    const swiper = this;
+    if (swiper.rtl && direction === 'rtl' || !swiper.rtl && direction === 'ltr') return;
+    swiper.rtl = direction === 'rtl';
+    swiper.rtlTranslate = swiper.params.direction === 'horizontal' && swiper.rtl;
+
+    if (swiper.rtl) {
+      swiper.$el.addClass(`${swiper.params.containerModifierClass}rtl`);
+      swiper.el.dir = 'rtl';
+    } else {
+      swiper.$el.removeClass(`${swiper.params.containerModifierClass}rtl`);
+      swiper.el.dir = 'ltr';
+    }
+
+    swiper.update();
+  }
+
+  mount(el) {
+    const swiper = this;
+    if (swiper.mounted) return true; // Find el
+
+    const $el = $(el || swiper.params.el);
+    el = $el[0];
+
+    if (!el) {
+      return false;
+    }
+
+    el.swiper = swiper;
+
+    const getWrapperSelector = () => {
+      return `.${(swiper.params.wrapperClass || '').trim().split(' ').join('.')}`;
+    };
+
+    const getWrapper = () => {
+      if (el && el.shadowRoot && el.shadowRoot.querySelector) {
+        const res = $(el.shadowRoot.querySelector(getWrapperSelector())); // Children needs to return slot items
+
+        res.children = options => $el.children(options);
+
+        return res;
+      }
+
+      if (!$el.children) {
+        return $($el).children(getWrapperSelector());
+      }
+
+      return $el.children(getWrapperSelector());
+    }; // Find Wrapper
+
+
+    let $wrapperEl = getWrapper();
+
+    if ($wrapperEl.length === 0 && swiper.params.createElements) {
+      const document = getDocument();
+      const wrapper = document.createElement('div');
+      $wrapperEl = $(wrapper);
+      wrapper.className = swiper.params.wrapperClass;
+      $el.append(wrapper);
+      $el.children(`.${swiper.params.slideClass}`).each(slideEl => {
+        $wrapperEl.append(slideEl);
+      });
+    }
+
+    Object.assign(swiper, {
+      $el,
+      el,
+      $wrapperEl,
+      wrapperEl: $wrapperEl[0],
+      mounted: true,
+      // RTL
+      rtl: el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl',
+      rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || $el.css('direction') === 'rtl'),
+      wrongRTL: $wrapperEl.css('display') === '-webkit-box'
+    });
+    return true;
+  }
+
+  init(el) {
+    const swiper = this;
+    if (swiper.initialized) return swiper;
+    const mounted = swiper.mount(el);
+    if (mounted === false) return swiper;
+    swiper.emit('beforeInit'); // Set breakpoint
+
+    if (swiper.params.breakpoints) {
+      swiper.setBreakpoint();
+    } // Add Classes
+
+
+    swiper.addClasses(); // Create loop
+
+    if (swiper.params.loop) {
+      swiper.loopCreate();
+    } // Update size
+
+
+    swiper.updateSize(); // Update slides
+
+    swiper.updateSlides();
+
+    if (swiper.params.watchOverflow) {
+      swiper.checkOverflow();
+    } // Set Grab Cursor
+
+
+    if (swiper.params.grabCursor && swiper.enabled) {
+      swiper.setGrabCursor();
+    }
+
+    if (swiper.params.preloadImages) {
+      swiper.preloadImages();
+    } // Slide To Initial Slide
+
+
+    if (swiper.params.loop) {
+      swiper.slideTo(swiper.params.initialSlide + swiper.loopedSlides, 0, swiper.params.runCallbacksOnInit, false, true);
+    } else {
+      swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
+    } // Attach events
+
+
+    swiper.attachEvents(); // Init Flag
+
+    swiper.initialized = true; // Emit
+
+    swiper.emit('init');
+    swiper.emit('afterInit');
+    return swiper;
+  }
+
+  destroy(deleteInstance, cleanStyles) {
+    if (deleteInstance === void 0) {
+      deleteInstance = true;
+    }
+
+    if (cleanStyles === void 0) {
+      cleanStyles = true;
+    }
+
+    const swiper = this;
+    const {
+      params,
+      $el,
+      $wrapperEl,
+      slides
+    } = swiper;
+
+    if (typeof swiper.params === 'undefined' || swiper.destroyed) {
+      return null;
+    }
+
+    swiper.emit('beforeDestroy'); // Init Flag
+
+    swiper.initialized = false; // Detach events
+
+    swiper.detachEvents(); // Destroy loop
+
+    if (params.loop) {
+      swiper.loopDestroy();
+    } // Cleanup styles
+
+
+    if (cleanStyles) {
+      swiper.removeClasses();
+      $el.removeAttr('style');
+      $wrapperEl.removeAttr('style');
+
+      if (slides && slides.length) {
+        slides.removeClass([params.slideVisibleClass, params.slideActiveClass, params.slideNextClass, params.slidePrevClass].join(' ')).removeAttr('style').removeAttr('data-swiper-slide-index');
+      }
+    }
+
+    swiper.emit('destroy'); // Detach emitter events
+
+    Object.keys(swiper.eventsListeners).forEach(eventName => {
+      swiper.off(eventName);
+    });
+
+    if (deleteInstance !== false) {
+      swiper.$el[0].swiper = null;
+      deleteProps(swiper);
+    }
+
+    swiper.destroyed = true;
+    return null;
+  }
+
+  static extendDefaults(newDefaults) {
+    extend(extendedDefaults, newDefaults);
+  }
+
+  static get extendedDefaults() {
+    return extendedDefaults;
+  }
+
+  static get defaults() {
+    return defaults;
+  }
+
+  static installModule(mod) {
+    if (!Swiper.prototype.__modules__) Swiper.prototype.__modules__ = [];
+    const modules = Swiper.prototype.__modules__;
+
+    if (typeof mod === 'function' && modules.indexOf(mod) < 0) {
+      modules.push(mod);
+    }
+  }
+
+  static use(module) {
+    if (Array.isArray(module)) {
+      module.forEach(m => Swiper.installModule(m));
+      return Swiper;
+    }
+
+    Swiper.installModule(module);
+    return Swiper;
+  }
+
+}
+
+Object.keys(prototypes).forEach(prototypeGroup => {
+  Object.keys(prototypes[prototypeGroup]).forEach(protoMethod => {
+    Swiper.prototype[protoMethod] = prototypes[prototypeGroup][protoMethod];
+  });
+});
+Swiper.use([Resize, Observer]);
+export default Swiper;

+ 123 - 0
static/static/lib/swiper/core/defaults.js

@@ -0,0 +1,123 @@
+export default {
+  init: true,
+  direction: 'horizontal',
+  touchEventsTarget: 'wrapper',
+  initialSlide: 0,
+  speed: 300,
+  cssMode: false,
+  updateOnWindowResize: true,
+  resizeObserver: true,
+  nested: false,
+  createElements: false,
+  enabled: true,
+  focusableElements: 'input, select, option, textarea, button, video, label',
+  // Overrides
+  width: null,
+  height: null,
+  //
+  preventInteractionOnTransition: false,
+  // ssr
+  userAgent: null,
+  url: null,
+  // To support iOS's swipe-to-go-back gesture (when being used in-app).
+  edgeSwipeDetection: false,
+  edgeSwipeThreshold: 20,
+  // Autoheight
+  autoHeight: false,
+  // Set wrapper width
+  setWrapperSize: false,
+  // Virtual Translate
+  virtualTranslate: false,
+  // Effects
+  effect: 'slide',
+  // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
+  // Breakpoints
+  breakpoints: undefined,
+  breakpointsBase: 'window',
+  // Slides grid
+  spaceBetween: 0,
+  slidesPerView: 1,
+  slidesPerGroup: 1,
+  slidesPerGroupSkip: 0,
+  slidesPerGroupAuto: false,
+  centeredSlides: false,
+  centeredSlidesBounds: false,
+  slidesOffsetBefore: 0,
+  // in px
+  slidesOffsetAfter: 0,
+  // in px
+  normalizeSlideIndex: true,
+  centerInsufficientSlides: false,
+  // Disable swiper and hide navigation when container not overflow
+  watchOverflow: true,
+  // Round length
+  roundLengths: false,
+  // Touches
+  touchRatio: 1,
+  touchAngle: 45,
+  simulateTouch: true,
+  shortSwipes: true,
+  longSwipes: true,
+  longSwipesRatio: 0.5,
+  longSwipesMs: 300,
+  followFinger: true,
+  allowTouchMove: true,
+  threshold: 0,
+  touchMoveStopPropagation: false,
+  touchStartPreventDefault: true,
+  touchStartForcePreventDefault: false,
+  touchReleaseOnEdges: false,
+  // Unique Navigation Elements
+  uniqueNavElements: true,
+  // Resistance
+  resistance: true,
+  resistanceRatio: 0.85,
+  // Progress
+  watchSlidesProgress: false,
+  // Cursor
+  grabCursor: false,
+  // Clicks
+  preventClicks: true,
+  preventClicksPropagation: true,
+  slideToClickedSlide: false,
+  // Images
+  preloadImages: true,
+  updateOnImagesReady: true,
+  // loop
+  loop: false,
+  loopAdditionalSlides: 0,
+  loopedSlides: null,
+  loopFillGroupWithBlank: false,
+  loopPreventsSlide: true,
+  // rewind
+  rewind: false,
+  // Swiping/no swiping
+  allowSlidePrev: true,
+  allowSlideNext: true,
+  swipeHandler: null,
+  // '.swipe-handler',
+  noSwiping: true,
+  noSwipingClass: 'swiper-no-swiping',
+  noSwipingSelector: null,
+  // Passive Listeners
+  passiveListeners: true,
+  maxBackfaceHiddenSlides: 10,
+  // NS
+  containerModifierClass: 'swiper-',
+  // NEW
+  slideClass: 'swiper-slide',
+  slideBlankClass: 'swiper-slide-invisible-blank',
+  slideActiveClass: 'swiper-slide-active',
+  slideDuplicateActiveClass: 'swiper-slide-duplicate-active',
+  slideVisibleClass: 'swiper-slide-visible',
+  slideDuplicateClass: 'swiper-slide-duplicate',
+  slideNextClass: 'swiper-slide-next',
+  slideDuplicateNextClass: 'swiper-slide-duplicate-next',
+  slidePrevClass: 'swiper-slide-prev',
+  slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',
+  wrapperClass: 'swiper-wrapper',
+  // Callbacks
+  runCallbacksOnInit: true,
+  // Internals
+  _emitClasses: false
+};

+ 122 - 0
static/static/lib/swiper/core/events-emitter.js

@@ -0,0 +1,122 @@
+/* eslint-disable no-underscore-dangle */
+export default {
+  on(events, handler, priority) {
+    const self = this;
+    if (!self.eventsListeners || self.destroyed) return self;
+    if (typeof handler !== 'function') return self;
+    const method = priority ? 'unshift' : 'push';
+    events.split(' ').forEach(event => {
+      if (!self.eventsListeners[event]) self.eventsListeners[event] = [];
+      self.eventsListeners[event][method](handler);
+    });
+    return self;
+  },
+
+  once(events, handler, priority) {
+    const self = this;
+    if (!self.eventsListeners || self.destroyed) return self;
+    if (typeof handler !== 'function') return self;
+
+    function onceHandler() {
+      self.off(events, onceHandler);
+
+      if (onceHandler.__emitterProxy) {
+        delete onceHandler.__emitterProxy;
+      }
+
+      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+        args[_key] = arguments[_key];
+      }
+
+      handler.apply(self, args);
+    }
+
+    onceHandler.__emitterProxy = handler;
+    return self.on(events, onceHandler, priority);
+  },
+
+  onAny(handler, priority) {
+    const self = this;
+    if (!self.eventsListeners || self.destroyed) return self;
+    if (typeof handler !== 'function') return self;
+    const method = priority ? 'unshift' : 'push';
+
+    if (self.eventsAnyListeners.indexOf(handler) < 0) {
+      self.eventsAnyListeners[method](handler);
+    }
+
+    return self;
+  },
+
+  offAny(handler) {
+    const self = this;
+    if (!self.eventsListeners || self.destroyed) return self;
+    if (!self.eventsAnyListeners) return self;
+    const index = self.eventsAnyListeners.indexOf(handler);
+
+    if (index >= 0) {
+      self.eventsAnyListeners.splice(index, 1);
+    }
+
+    return self;
+  },
+
+  off(events, handler) {
+    const self = this;
+    if (!self.eventsListeners || self.destroyed) return self;
+    if (!self.eventsListeners) return self;
+    events.split(' ').forEach(event => {
+      if (typeof handler === 'undefined') {
+        self.eventsListeners[event] = [];
+      } else if (self.eventsListeners[event]) {
+        self.eventsListeners[event].forEach((eventHandler, index) => {
+          if (eventHandler === handler || eventHandler.__emitterProxy && eventHandler.__emitterProxy === handler) {
+            self.eventsListeners[event].splice(index, 1);
+          }
+        });
+      }
+    });
+    return self;
+  },
+
+  emit() {
+    const self = this;
+    if (!self.eventsListeners || self.destroyed) return self;
+    if (!self.eventsListeners) return self;
+    let events;
+    let data;
+    let context;
+
+    for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+      args[_key2] = arguments[_key2];
+    }
+
+    if (typeof args[0] === 'string' || Array.isArray(args[0])) {
+      events = args[0];
+      data = args.slice(1, args.length);
+      context = self;
+    } else {
+      events = args[0].events;
+      data = args[0].data;
+      context = args[0].context || self;
+    }
+
+    data.unshift(context);
+    const eventsArray = Array.isArray(events) ? events : events.split(' ');
+    eventsArray.forEach(event => {
+      if (self.eventsAnyListeners && self.eventsAnyListeners.length) {
+        self.eventsAnyListeners.forEach(eventHandler => {
+          eventHandler.apply(context, [event, ...data]);
+        });
+      }
+
+      if (self.eventsListeners && self.eventsListeners[event]) {
+        self.eventsListeners[event].forEach(eventHandler => {
+          eventHandler.apply(context, data);
+        });
+      }
+    });
+    return self;
+  }
+
+};

+ 97 - 0
static/static/lib/swiper/core/events/index.js

@@ -0,0 +1,97 @@
+import { getDocument } from 'ssr-window';
+import onTouchStart from './onTouchStart.js';
+import onTouchMove from './onTouchMove.js';
+import onTouchEnd from './onTouchEnd.js';
+import onResize from './onResize.js';
+import onClick from './onClick.js';
+import onScroll from './onScroll.js';
+let dummyEventAttached = false;
+
+function dummyEventListener() {}
+
+const events = (swiper, method) => {
+  const document = getDocument();
+  const {
+    params,
+    touchEvents,
+    el,
+    wrapperEl,
+    device,
+    support
+  } = swiper;
+  const capture = !!params.nested;
+  const domMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';
+  const swiperMethod = method; // Touch Events
+
+  if (!support.touch) {
+    el[domMethod](touchEvents.start, swiper.onTouchStart, false);
+    document[domMethod](touchEvents.move, swiper.onTouchMove, capture);
+    document[domMethod](touchEvents.end, swiper.onTouchEnd, false);
+  } else {
+    const passiveListener = touchEvents.start === 'touchstart' && support.passiveListener && params.passiveListeners ? {
+      passive: true,
+      capture: false
+    } : false;
+    el[domMethod](touchEvents.start, swiper.onTouchStart, passiveListener);
+    el[domMethod](touchEvents.move, swiper.onTouchMove, support.passiveListener ? {
+      passive: false,
+      capture
+    } : capture);
+    el[domMethod](touchEvents.end, swiper.onTouchEnd, passiveListener);
+
+    if (touchEvents.cancel) {
+      el[domMethod](touchEvents.cancel, swiper.onTouchEnd, passiveListener);
+    }
+  } // Prevent Links Clicks
+
+
+  if (params.preventClicks || params.preventClicksPropagation) {
+    el[domMethod]('click', swiper.onClick, true);
+  }
+
+  if (params.cssMode) {
+    wrapperEl[domMethod]('scroll', swiper.onScroll);
+  } // Resize handler
+
+
+  if (params.updateOnWindowResize) {
+    swiper[swiperMethod](device.ios || device.android ? 'resize orientationchange observerUpdate' : 'resize observerUpdate', onResize, true);
+  } else {
+    swiper[swiperMethod]('observerUpdate', onResize, true);
+  }
+};
+
+function attachEvents() {
+  const swiper = this;
+  const document = getDocument();
+  const {
+    params,
+    support
+  } = swiper;
+  swiper.onTouchStart = onTouchStart.bind(swiper);
+  swiper.onTouchMove = onTouchMove.bind(swiper);
+  swiper.onTouchEnd = onTouchEnd.bind(swiper);
+
+  if (params.cssMode) {
+    swiper.onScroll = onScroll.bind(swiper);
+  }
+
+  swiper.onClick = onClick.bind(swiper);
+
+  if (support.touch && !dummyEventAttached) {
+    document.addEventListener('touchstart', dummyEventListener);
+    dummyEventAttached = true;
+  }
+
+  events(swiper, 'on');
+}
+
+function detachEvents() {
+  const swiper = this;
+  events(swiper, 'off');
+}
+
+export default {
+  attachEvents,
+  detachEvents
+};

+ 13 - 0
static/static/lib/swiper/core/events/onClick.js

@@ -0,0 +1,13 @@
+export default function onClick(e) {
+  const swiper = this;
+  if (!swiper.enabled) return;
+
+  if (!swiper.allowClick) {
+    if (swiper.params.preventClicks) e.preventDefault();
+
+    if (swiper.params.preventClicksPropagation && swiper.animating) {
+      e.stopPropagation();
+      e.stopImmediatePropagation();
+    }
+  }
+}

+ 43 - 0
static/static/lib/swiper/core/events/onResize.js

@@ -0,0 +1,43 @@
+export default function onResize() {
+  const swiper = this;
+  const {
+    params,
+    el
+  } = swiper;
+  if (el && el.offsetWidth === 0) return; // Breakpoints
+
+  if (params.breakpoints) {
+    swiper.setBreakpoint();
+  } // Save locks
+
+
+  const {
+    allowSlideNext,
+    allowSlidePrev,
+    snapGrid
+  } = swiper; // Disable locks on resize
+
+  swiper.allowSlideNext = true;
+  swiper.allowSlidePrev = true;
+  swiper.updateSize();
+  swiper.updateSlides();
+  swiper.updateSlidesClasses();
+
+  if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides) {
+    swiper.slideTo(swiper.slides.length - 1, 0, false, true);
+  } else {
+    swiper.slideTo(swiper.activeIndex, 0, false, true);
+  }
+
+  if (swiper.autoplay && swiper.autoplay.running && swiper.autoplay.paused) {
+    swiper.autoplay.run();
+  } // Return locks after resize
+
+
+  swiper.allowSlidePrev = allowSlidePrev;
+  swiper.allowSlideNext = allowSlideNext;
+
+  if (swiper.params.watchOverflow && snapGrid !== swiper.snapGrid) {
+    swiper.checkOverflow();
+  }
+}

+ 35 - 0
static/static/lib/swiper/core/events/onScroll.js

@@ -0,0 +1,35 @@
+export default function onScroll() {
+  const swiper = this;
+  const {
+    wrapperEl,
+    rtlTranslate,
+    enabled
+  } = swiper;
+  if (!enabled) return;
+  swiper.previousTranslate = swiper.translate;
+
+  if (swiper.isHorizontal()) {
+    swiper.translate = -wrapperEl.scrollLeft;
+  } else {
+    swiper.translate = -wrapperEl.scrollTop;
+  } // eslint-disable-next-line
+
+
+  if (swiper.translate === 0) swiper.translate = 0;
+  swiper.updateActiveIndex();
+  swiper.updateSlidesClasses();
+  let newProgress;
+  const translatesDiff = swiper.maxTranslate() - swiper.minTranslate();
+
+  if (translatesDiff === 0) {
+    newProgress = 0;
+  } else {
+    newProgress = (swiper.translate - swiper.minTranslate()) / translatesDiff;
+  }
+
+  if (newProgress !== swiper.progress) {
+    swiper.updateProgress(rtlTranslate ? -swiper.translate : swiper.translate);
+  }
+
+  swiper.emit('setTranslate', swiper.translate, false);
+}

+ 0 - 0
static/static/lib/swiper/core/events/onTouchEnd.js


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