From ecb6cadc3f016cf9968f48e0cc77479a1e56365b Mon Sep 17 00:00:00 2001
From: hanbaoshan <hanbaoshan@aiotlink.com>
Date: 星期日, 20 十二月 2020 17:32:06 +0800
Subject: [PATCH] 标定添加关联摄像机tab,绘制区域组件参数更新

---
 src/pages/cameraAccess/components/SeparateRules.vue |  579 +++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 370 insertions(+), 209 deletions(-)

diff --git a/src/pages/cameraAccess/components/SeparateRules.vue b/src/pages/cameraAccess/components/SeparateRules.vue
index b4e507c..2260c2d 100644
--- a/src/pages/cameraAccess/components/SeparateRules.vue
+++ b/src/pages/cameraAccess/components/SeparateRules.vue
@@ -2,173 +2,95 @@
   <div class="s-separate-rules">
     <div class="ai">
       <div class="check-area">
-        <el-row class="mt5">
-          <el-col :span="24">
-            <div class="ai-select">
-              <div style="float:left;" v-show="cameraType === 'camera'">
-                <span>
-                  <span class="label">瑙嗛鍒嗘瀽澶勭悊</span>
-                  <el-switch
-                    style="margin-left: 10px;"
-                    v-model="Camera.analytics"
-                    @change="pollEnable"
-                    :disabled="!Camera.cameraId"
-                  ></el-switch>
-                </span>
-              </div>
+        <div class="ai-select">
+          <div v-show="cameraType === 'camera'">
+            <span>
+              <span class="label">瑙嗛鍒嗘瀽澶勭悊</span>
+              <el-switch
+                style="margin-left: 10px;"
+                v-model="Camera.analytics"
+                @change="pollEnable"
+                :disabled="!Camera.cameraId"
+              ></el-switch>
+            </span>
+          </div>
 
-              <div
-                v-if="Camera.analytics"
-                style="float:left;margin-left: 5%;"
-                class="flex-box"
-                v-show="cameraType === 'camera'"
+          <div v-if="Camera.analytics" class="flex-box" v-show="cameraType === 'camera'">
+            <span class="label">澶勭悊鏂瑰紡</span>
+            <toggle-button
+              :value="Camera.dealWay"
+              :width="60"
+              :labels="{checked: '瀹炴椂', unchecked: '杞'}"
+              :color="{checked: '#3D68E1', unchecked: '#FF7733', disabled: '#CCCCCC'}"
+              :sync="true"
+              @change="changePoll"
+            />
+          </div>
+
+          <div v-if="Camera.analytics" class="flex-box" v-show="cameraType === 'camera'">
+            <span
+              class="label"
+            >鍒嗚鲸鐜�: {{(Camera.camearInfo.resolution_width == 0 || Camera.camearInfo.resolution_height == 0) ? '鏈満鍒嗚鲸鐜�': `${Camera.camearInfo.resolution_width} * ${Camera.camearInfo.resolution_height}` }}</span>
+          </div>
+
+          <div v-if="Camera.analytics" class="flex-box">
+            <span class="label">SmartAI鑺傜偣: {{ Camera.runServerName}}</span>
+          </div>
+
+          <div v-if="Camera.analytics" class="flex-box">
+            <span class="label">绠楁硶蹇�熼�氶亾</span>
+            <div class="channel flex-box">
+              <el-tooltip
+                effect="dark"
+                content="澶嶅埗姝ゆ憚鍍忔満绠楁硶瑙勫垯"
+                placement="bottom"
+                popper-class="atooltip"
               >
-                <span class="label" style="margin-right:10px;line-height: 22px;">澶勭悊鏂瑰紡</span>
-                <toggle-button
-                  :value="Camera.dealWay"
-                  :width="60"
-                  :labels="{checked: '瀹炴椂', unchecked: '杞'}"
-                  :color="{checked: '#3D68E1', unchecked: '#FF7733', disabled: '#CCCCCC'}"
-                  :sync="true"
-                  @change="changePoll"
-                />
-              </div>
-
-              <div
-                v-if="Camera.analytics"
-                style="float:left;margin-left:5%;"
-                class="flex-box"
-                v-show="cameraType === 'camera'"
+                <span
+                  style="color:#3D68E1;cursor: pointer;font-size:23px;"
+                  @click="ctrlC"
+                  class="iconfont iconfuzhiguize"
+                ></span>
+              </el-tooltip>
+              <el-tooltip
+                effect="dark"
+                :content="!TreeDataPool.ctrlCameraId?'绮樿创绠楁硶瑙勫垯':`绮樿创绠楁硶瑙勫垯锛屾潵婧愶細${TreeDataPool.ctrlCameraName}`"
+                placement="bottom"
+                popper-class="atooltip"
               >
-                <span class="label" style="line-height:25px">鍒嗚鲸鐜�</span>
-                <el-select
-                  v-model="Camera.selectResolution"
-                  placeholder="璇烽�夋嫨"
-                  size="mini"
-                  style="width: 134px;height: 30px;
-                    margin-left:10px;position: relative;bottom: 3px;"
-                >
-                  <el-option
-                    v-for="item in Camera.resolutionOption"
-                    :key="item.value"
-                    :label="item.label"
-                    :value="item.value"
-                  ></el-option>
-                </el-select>
-              </div>
-
-              <div v-if="Camera.analytics" style="float:left;margin-left:5%;" class="flex-box">
-                <span class="label" style="line-height:22px">鏅鸿兘璁$畻鑺傜偣: {{ Camera.runServerName}}</span>
-              </div>
-
-              <div
-                v-if="Camera.analytics"
-                style="float:left;margin-left: 5%;line-height: 22px;"
-                class="flex-box"
-              >
-                <span style="float:left;">绠楁硶蹇�熼�氶亾</span>
-                <div class="flex-box" style="float: left;
-                  margin-left: 5px;">
-                  <el-tooltip
-                    effect="dark"
-                    content="澶嶅埗姝ゆ憚鍍忔満绠楁硶瑙勫垯"
-                    placement="bottom"
-                    popper-class="atooltip"
-                  >
-                    <span
-                      style="color:#3D68E1;cursor: pointer;font-size:23px;"
-                      @click="ctrlC"
-                      class="iconfont iconfuzhiguize"
-                    ></span>
-                  </el-tooltip>
-                  <el-tooltip
-                    effect="dark"
-                    :content="!TreeDataPool.ctrlCameraId?'绮樿创绠楁硶瑙勫垯':`绮樿创绠楁硶瑙勫垯锛屾潵婧愶細${TreeDataPool.ctrlCameraName}`"
-                    placement="bottom"
-                    popper-class="atooltip"
-                  >
-                    <span
-                      :style="!TreeDataPool.ctrlCameraId?'cursor: not-allowed;font-size:23px;':'color:#3D68E1;font-size:23px;cursor: pointer;'"
-                      @click="ctrlV"
-                      class="iconfont iconniantie ml5"
-                    ></span>
-                  </el-tooltip>
-                </div>
-              </div>
+                <span
+                  :style="!TreeDataPool.ctrlCameraId?'cursor: not-allowed;font-size:23px;':'color:#3D68E1;font-size:23px;cursor: pointer;'"
+                  @click="ctrlV"
+                  class="iconfont iconniantie ml5"
+                ></span>
+              </el-tooltip>
             </div>
-          </el-col>
-        </el-row>
+          </div>
+        </div>
       </div>
     </div>
 
-    <div
-      style="width: calc(100% + 76px);position: absolute;left: -38px;top:38px;height: 10px;background-color: #E9EBF2;"
-    ></div>
+    <div class="devide"></div>
 
-    <div class="top" style="top:60px;">
+    <div class="top">
       <p class="task-css">
         <b style="font-size: 14px; line-height: 18px;">鍦烘櫙</b>
       </p>
-      <div>
+      <div class="clearfix">
         <slide-scene :sceneData="Camera.rules"></slide-scene>
         <div class="top-right">
           <sysinfo
             :showRealPoll="cameraType === 'camera'"
             :ShowLocalVedio="cameraType === 'dataStack'"
             v-if="showSysInfo"
-            style="margin-left: 25px;margin-top:-10px"
+            style="margin-top:-10px"
           />
         </div>
       </div>
-
-      <!-- <swiper :options="swiperOption" class="swiper-box-container">
-       
-        <swiper-slide v-for="(item, index) in 10" :key="index">
-          <div class="item-card">
-            <p style="color: #0066EB;padding-top: 20px;">
-              <b>{{ item }}</b>
-            </p>
-          </div>
-        </swiper-slide>
-      </swiper>
-      <div class="swiper-pre-border" >
-        <div class="icon-btn" slot="button-prev">
-          <i class="iconfont iconzuo"></i>
-        </div>
-      </div>
-      <div class="swiper-next-border" >
-        <div class="icon-btn" slot="button-next">
-          <i class="iconfont iconyou1"></i>
-        </div>
-      </div>-->
-      <!-- <swiper :options="swiperOption" class="swiper-box-container">
-        <span class="task-tip" v-show="Camera.rules.length == 0 ">鏆傛棤鍦烘櫙,璇峰紑濮嬪垱寤�</span>
-        <swiper-slide v-for="(item, index) in Camera.rules" :key="index">
-          <div class="item-card">
-            <p style="color: #0066EB;padding-top: 20px;">
-              <b>{{ item.scene_name }}</b>
-            </p>
-          </div>
-        </swiper-slide>
-      </swiper>
-      <div class="swiper-pre-border" v-show="Camera.rules.length > 4 ">
-        <div class="icon-btn" slot="button-prev">
-          <i class="iconfont iconzuo"></i>
-        </div>
-      </div>
-      <div class="swiper-next-border" v-show="Camera.rules.length > 4 ">
-        <div class="icon-btn" slot="button-next">
-          <i class="iconfont iconyou1"></i>
-        </div>
-      </div>-->
-
-      <!-- 绯荤粺淇℃伅 -->
     </div>
 
-    <div class="bottom" style="top:254px;">
-      <div
-        style="width: calc(100% + 100px);height: 10px;background-color: #E9EBF2;position:relative;left:-40px"
-      ></div>
+    <div class="bottom">
+      <div class="devide"></div>
       <div class="bottom-right">
         <div class="draw-and-time-box">
           <div class="draw-box">
@@ -188,25 +110,86 @@
               >{{ Camera.camearInfo.alias ? Camera.camearInfo.alias: Camera.camearInfo.name }}</b>
             </div>
             <div class="img-box">
-              <polygon-canvas
-                class="cavas"
-                ref="canvas"
-                v-if="showCanvas"
-                v-loading="loading"
-                element-loading-text="鍒锋柊涓紝璇风◢绛�..."
-                element-loading-background="rgba(0, 0, 0, 0.8)"
-                :isShowDrawArrow="false"
-                :disabled="false"
-                :snapshot_url="Camera.baseImg"
-                :canvasDataShow="Camera.canvasData"
-                :currentCameraId="Camera.cameraId"
-                :loading="Camera.loading"
-                :canvasWidth="canvasWidth"
-                :canvasHeight="canvasHeight"
-                @fromCanvas="getCanvasData"
-                @changeLoading="changeLoading"
-                @refresh="refresh"
-              ></polygon-canvas>
+              <template v-if="TreeDataPool.treeActiveName == 'camera'">
+                <polygon-canvas
+                  class="cavas"
+                  ref="canvas"
+                  v-if="showCanvas"
+                  v-loading="loading"
+                  element-loading-text="鍒锋柊涓紝璇风◢绛�..."
+                  element-loading-background="rgba(0, 0, 0, 0.8)"
+                  :isShowDrawArrow="false"
+                  :disabled="false"
+                  :snapshot_url="Camera.baseImg"
+                  :canvasDataShow="Camera.canvasData"
+                  :currentCameraId="Camera.cameraId"
+                  :loading="Camera.loading"
+                  :canvasWidth="canvasWidth"
+                  :canvasHeight="canvasHeight"
+                  @fromCanvas="getCanvasData"
+                  @changeLoading="changeLoading"
+                  @refresh="refresh"
+                ></polygon-canvas>
+              </template>
+              <template v-else>
+                <div style="width:100%" v-loading="getStackFileLoading">
+                  <swiper
+                    ref="swiper"
+                    :auto-update="true"
+                    :options="canvasSwiperOption"
+                    @slideChange="swiperSlideChange"
+                    class="swiper-box-container2"
+                    style="width:100%"
+                  >
+                    <swiper-slide v-for="(data, index) in swipercanvasData" :key="index">
+                      <div>
+                        <b
+                          class="video-title"
+                          style="font-size:14px;margin-top:-10px"
+                        >{{ data.name }}</b>
+                        <polygon-canvas
+                          class="cavas"
+                          ref="canvas"
+                          v-if="showCanvas"
+                          v-loading="loading"
+                          element-loading-text="鍒锋柊涓紝璇风◢绛�..."
+                          element-loading-background="rgba(0, 0, 0, 0.8)"
+                          :isShowDrawArrow="false"
+                          :isShowRefresh="false"
+                          :sourceType="data.type"
+                          :disabled="false"
+                          :snapshot_url="data.baseImg"
+                          :canvasDataShow="Camera.canvasData"
+                          :currentCameraId="data.stackId"
+                          :loading="data.loading"
+                          :canvasWidth="canvasWidth"
+                          :canvasHeight="canvasHeight"
+                          @fromCanvas="getCanvasData"
+                          @changeLoading="changeLoading"
+                        ></polygon-canvas>
+                      </div>
+                    </swiper-slide>
+                  </swiper>
+                  <div
+                    class="swiper-local-prev"
+                    v-show="swipercanvasData.length>1"
+                    @click="prevClick"
+                  >
+                    <div class="icon-btn" slot="button-prev">
+                      <i class="iconfont iconzuo"></i>
+                    </div>
+                  </div>
+                  <div
+                    class="swiper-local-next"
+                    v-show="swipercanvasData.length>1"
+                    @click="nextClick"
+                  >
+                    <div class="icon-btn" slot="button-next">
+                      <i class="iconfont iconyou1"></i>
+                    </div>
+                  </div>
+                </div>
+              </template>
             </div>
           </div>
           <div style="float:left;width:calc(10% - 90px);height:100%;"></div>
@@ -242,20 +225,22 @@
 } from '@/api/task';
 
 import {
-  getAllTemplate,
   saveCameraScene,
   getCameraSceneRule,
 } from '@/api/scene'
 
 import { changeRunType } from "@/api/pollConfig";
-
+import { findAllFileByStackId } from "@/api/localVedio";
 import VideoRuleData from "@/Pool/VideoRuleData";
 
 import TimeSlider from "./TimeSlider";
 import polygonCanvas from "@/components/canvas";
-import Sysinfo from "./SystemInfo";
+//import Sysinfo from "./SystemInfo";
+import Sysinfo from "@/components/subComponents/SystemInfo";
 import SceneRule from "./SceneRule";
 import SlideScene from "./scene/SlideScene";
+import { duration } from 'moment';
+
 
 export default {
   components: {
@@ -283,6 +268,18 @@
       loading: false,
       Camera: new VideoRuleData(),
       runType: -1,
+      getStackFileLoading: false,
+      canvasSwiperOption: {
+        grabCursor: true,
+        pagination: {
+          el: ".swiper-pagination",
+          type: "fraction"
+        },
+        navigation: {
+          nextEl: ".swiper-local-next",
+          prevEl: ".swiper-local-prev"
+        }
+      },
       swiperOption: {
         slidesPerView: 5,
         spaceBetween: 8,
@@ -304,14 +301,108 @@
       showSysInfo: false,
       showCanvas: true,
       canvasWidth: 576,
-      canvasHeight: 324
+      canvasHeight: 324,
+      stackId: '',
+      swiperIndex: 0,
+      swipercanvasData: [],
+      stackFilesPage: 1,
+      stackFilesSize: 5,
     };
   },
   mounted() {
-    this.mockAsync()
-  },
+    this.mockAsync();
+    this.PollData.statistics();
 
+  },
+  watch: {
+    'Camera.cameraId': {
+      handler(n, o) {
+        if (n) {
+          if (this.TreeDataPool.treeActiveName == "dataStack") {
+            this.stackFilesPage = 1;
+            this.stackFilesSize = 5;
+            this.stackId = n;
+            if (this.stackId) {
+              // console.log('getStackFiles')
+              this.swipercanvasData = [];
+              this.getStackFiles()
+            }
+          }
+        }
+      }
+    }
+  },
   methods: {
+    prevClick() {
+      // console.log(this.swiperIndex)
+      // console.log(this.$refs.swiper.swiper.activeIndex)
+      if (this.swiperIndex == 0) {
+        // console.log('鏈鍒嗛〉鐨勭涓�鏉�')
+        //璇锋眰涓婁竴椤�
+        if (this.stackFilesPage > 1) {
+          this.stackFilesPage--;
+          this.getStackFiles(true);
+        } else {
+          this.$message({
+            type: 'info',
+            message: '褰撳墠宸叉槸绗竴椤�'
+          });
+        }
+
+      }
+    },
+    nextClick() {
+      if (this.swiperIndex == this.swipercanvasData.length - 1) {
+        // console.log('鏈�鍚庝竴寮�,鍔犺浇鏇村')
+        //璇锋眰涓嬩竴椤�
+        this.stackFilesPage++;
+        this.getStackFiles(true);
+      }
+    },
+    getStackFiles(onClick = false) {
+      this.getStackFileLoading = true;
+      let _this = this;
+      findAllFileByStackId({ name: '', stackId: this.stackId, page: this.stackFilesPage, size: this.stackFilesSize, type: 0 }).then(res => {
+        if (res && res.success) {
+          if (res.data.dataList.length > 0) {
+            this.swipercanvasData = [];
+            this.swipercanvasData = res.data.dataList.map(item => {
+              return {
+                name: item.name,
+                stackId: item.stack_id,
+                baseImg: item.type == 2 ? `/files/${item.path.substr(item.path.lastIndexOf('/') + 1)}` : item.snapshot_url,
+                type: item.type,
+                id: item.id,
+                loading: false
+              }
+            });
+            this.swiperIndex = 0;
+            this.$refs.swiper.swiper.activeIndex = 0;
+
+          } else {
+            if (onClick) {
+              this.$message({
+                type: 'warning',
+                message: '宸叉棤鏇村鏁版嵁!'
+              });
+            }
+          }
+        } else {
+          // console.log(this.swipercanvasData)
+          this.$message({
+            type: 'error',
+            message: '鏁版嵁璇锋眰澶辫触,璇风◢鍚庨噸璇�!'
+          });
+        }
+        this.getStackFileLoading = false;
+      }).catch(e => {
+        // console.log(e);
+        this.getStackFileLoading = false;
+      });
+    },
+    swiperSlideChange() {
+      this.swiperIndex = this.$refs.swiper.swiper.activeIndex;
+    },
     mockAsync() {
       setTimeout(() => {
         this.mockSceneData = [
@@ -339,14 +430,20 @@
       }, 3000)
     },
     drawBaseImg() {
-      this.$refs.canvas.showModal();
+      if (Array.isArray(this.$refs.canvas)) {
+        if (this.$refs.canvas.length > 0) {
+          this.$refs.canvas[0].showModal();
+        }
+      } else {
+        this.$refs.canvas.showModal();
+      }
     },
     getCanvasData(data) {
       let polyon = { ...data };
       polyon.camera_id = this.Camera.cameraId;
       savePolygon(polyon).then(rsp => {
         this.Camera.getPolygon();
-        this.Camera.getCameraTask();
+        //this.Camera.getCameraTask();
       });
     },
     refresh(url) {
@@ -360,6 +457,7 @@
         this.loading = false;
         this.Camera.cameraId = id;
         await this.Camera.update();
+
       }
 
       this.$refs.timeSlider.activeTab = this.VideoManageData.TimeRules[0].id;
@@ -372,9 +470,11 @@
       })
 
     },
+
     saveSceneRule(groupRule) {
       const payload = { ...groupRule }
       payload.cameraIds = [this.Camera.cameraId];
+      let _this = this;
       saveCameraScene(payload).then(rsp => {
         if (rsp && rsp.success) {
           this.Camera.update();
@@ -382,6 +482,10 @@
             type: "success",
             message: "绛栫暐淇濆瓨鎴愬姛锛�"
           });
+          //鍒锋柊宸︿晶鏍�
+
+          _this.$root.$children[0].$children[0].querySearchAsync('camera')
+
         }
       });
     },
@@ -523,43 +627,107 @@
 };
 </script>
 <style lang="scss">
+.el-message--info .el-message__content {
+  color: #999 !important;
+}
+.swiper-container {
+  margin-left: auto;
+  margin-right: auto;
+  position: relative;
+  overflow: hidden;
+  list-style: none;
+  padding: 0;
+  z-index: 1;
+}
+.swiper-local-prev,
+.swiper-local-next {
+  width: 40px;
+  height: 40px;
+  position: absolute;
+  background: #8888;
+  top: 40%;
+  z-index: 99;
+  border-radius: 4em;
+  outline: none;
+  .icon-btn {
+    color: rgb(255, 255, 255);
+    text-align: center;
+    line-height: 38px;
+    cursor: pointer;
+  }
+}
+.swiper-local-prev {
+  left: 10px;
+}
+.swiper-local-prev:hover {
+  background: #666;
+}
+.swiper-local-next {
+  left: 90%;
+}
+.swiper-local-next:hover {
+  background: #666;
+}
 .s-separate-rules {
   width: 100%;
-  height: 100%;
-  position: relative;
+  padding: 13px 0 20px;
   .ai {
-    width: calc(100% + 76px);
-    height: 38px;
-    position: absolute;
-    left: -38px;
+    //width: calc(100% + 76px);
+    // height: 38px;
+    // position: absolute;
+    // left: -38px;
+    height: 40px;
     .check-area {
       width: 100%;
       height: 100%;
-      float: left;
-      overflow: auto;
-      padding: 0 38px;
+      padding: 0 20px;
       -webkit-box-sizing: border-box;
       box-sizing: border-box;
+      .ai-select {
+        text-align: left;
+        line-height: 30px;
+        height: 30px;
+        .flex-box {
+          .label {
+            & + label,
+            & + div {
+              margin-left: 10px;
+              line-height: 1;
+            }
+          }
+        }
+      }
+      .ai-select > div {
+        display: inline-block;
+        vertical-align: middle;
+        margin-right: 30px;
+
+        .channel {
+          display: inline-block;
+          vertical-align: middle;
+        }
+      }
     }
+  }
+  .devide {
+    height: 10px;
+    background: #e9ebf2;
   }
   .top {
     width: 100%;
-    height: 174px;
-    position: relative;
-    top: 60px;
+    padding: 10px 20px;
+    box-sizing: border-box;
     .swiper-box {
       height: 100%;
       float: left;
-      width: 48%;
+      width: 46%;
       margin-top: -10px;
       position: relative;
     }
     .swiper-container {
       position: initial;
       min-width: 472px;
-      width: 80%;
-
-      // height: 124px;
+      width: 86%;
     }
     .swiper-slide {
       position: relative;
@@ -598,10 +766,6 @@
           backdrop-filter: blur(1px) brightness(100%);
           display: none;
         }
-
-        // @media screen and(max-width: 1280px) {
-        //   max-width: 110px;
-        // }
         @media screen and(max-width: 1440px) {
           max-width: 110px;
         }
@@ -641,10 +805,20 @@
     .swiper-next-border:hover {
       background: #666;
     }
+
     .top-right {
       float: right;
-      width: 52%;
+      width: 54%;
       height: 144px;
+      .card-box {
+        width: 54% !important;
+      }
+      .eCharts-box {
+        width: 45%;
+        canvas {
+          width: 98% !important;
+        }
+      }
     }
     .task-css {
       text-align: left;
@@ -653,9 +827,7 @@
   }
   .bottom {
     width: 100%;
-    height: calc(100% - 234px);
-    position: absolute;
-    top: 234px;
+    margin-bottom: 15px;
     .bottom-side {
       height: 100%;
       width: 250px;
@@ -681,11 +853,7 @@
       }
     }
     .bottom-right {
-      width: calc(100% + 30px);
-      height: 100%;
-      float: left;
-      overflow: auto;
-      padding: 10px 0px;
+      padding: 10px 20px;
       box-sizing: border-box;
       .draw-and-time-box {
         height: 400px;
@@ -820,13 +988,6 @@
     margin-left: 10px;
     font-size: 14px;
   }
-  .task-tip {
-    font-family: PingFangSC-Regular;
-    font-size: 12px;
-    color: #cccccc;
-    margin-top: 10%;
-    margin-left: 38%;
-  }
 
   .marker {
     display: inline-block;
@@ -853,7 +1014,7 @@
   }
 }
 .el-loading-spinner {
-  background: url("../../../assets/gif/loading.gif") no-repeat;
+  background: url("/images/cameraAccess/loading.gif") no-repeat;
   top: 50%;
   margin-top: -21px;
   width: calc(100% - 260px) !important;

--
Gitblit v1.8.0