From 656503685a93be51b12e5cb9c6a880eae6dcf7b4 Mon Sep 17 00:00:00 2001 From: luxiaotao1123 <t1341870251@63.com> Date: 星期三, 22 十二月 2021 11:11:37 +0800 Subject: [PATCH] # --- /dev/null | 519 ----------------------------------------------- static/js/app.js | 16 + static/js/object/CrnTask.js | 4 static/js/common.js | 98 ++++---- views/index.html | 1 static/js/data/BuildingData.js | 19 + 6 files changed, 86 insertions(+), 571 deletions(-) diff --git a/static/js/ThreeBSP.js b/static/js/ThreeBSP.js deleted file mode 100644 index c9e5b33..0000000 --- a/static/js/ThreeBSP.js +++ /dev/null @@ -1,519 +0,0 @@ -// Generated by CoffeeScript 1.6.3 -(function() { - var BACK, COPLANAR, EPSILON, FRONT, SPANNING, returning, - __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __slice = [].slice, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - - EPSILON = 1e-5; - - COPLANAR = 0; - - FRONT = 1; - - BACK = 2; - - SPANNING = 3; - - returning = function(value, fn) { - fn(); - return value; - }; - - window.ThreeBSP = (function() { - function ThreeBSP(treeIsh, matrix) { - this.matrix = matrix; - this.intersect = __bind(this.intersect, this); - this.union = __bind(this.union, this); - this.subtract = __bind(this.subtract, this); - this.toGeometry = __bind(this.toGeometry, this); - this.toMesh = __bind(this.toMesh, this); - this.toTree = __bind(this.toTree, this); - if (this.matrix == null) { - this.matrix = new THREE.Matrix4(); - } - this.tree = this.toTree(treeIsh); - } - - ThreeBSP.prototype.toTree = function(treeIsh) { - var face, geometry, i, polygons, _fn, _i, _len, _ref, - _this = this; - if (treeIsh instanceof ThreeBSP.Node) { - return treeIsh; - } - polygons = []; - geometry = treeIsh instanceof THREE.Geometry ? treeIsh : treeIsh instanceof THREE.Mesh ? (treeIsh.updateMatrix(), this.matrix = treeIsh.matrix.clone(), treeIsh.geometry) : void 0; - _ref = geometry.faces; - _fn = function(face, i) { - var faceVertexUvs, idx, polygon, vIndex, vName, vertex, _j, _len1, _ref1, _ref2; - faceVertexUvs = (_ref1 = geometry.faceVertexUvs) != null ? _ref1[0][i] : void 0; - if (faceVertexUvs == null) { - faceVertexUvs = [new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2()]; - } - polygon = new ThreeBSP.Polygon(); - _ref2 = ['a', 'b', 'c', 'd']; - for (vIndex = _j = 0, _len1 = _ref2.length; _j < _len1; vIndex = ++_j) { - vName = _ref2[vIndex]; - if ((idx = face[vName]) != null) { - vertex = geometry.vertices[idx]; - vertex = new ThreeBSP.Vertex(vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2(faceVertexUvs[vIndex].x, faceVertexUvs[vIndex].y)); - vertex.applyMatrix4(_this.matrix); - polygon.vertices.push(vertex); - } - } - return polygons.push(polygon.calculateProperties()); - }; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - face = _ref[i]; - _fn(face, i); - } - return new ThreeBSP.Node(polygons); - }; - - ThreeBSP.prototype.toMesh = function(material) { - var geometry, mesh, - _this = this; - if (material == null) { - material = new THREE.MeshNormalMaterial(); - } - geometry = this.toGeometry(); - return returning((mesh = new THREE.Mesh(geometry, material)), function() { - mesh.position.setFromMatrixPosition(_this.matrix); - return mesh.rotation.setFromRotationMatrix(_this.matrix); - }); - }; - - ThreeBSP.prototype.toGeometry = function() { - var geometry, matrix, - _this = this; - matrix = new THREE.Matrix4().getInverse(this.matrix); - return returning((geometry = new THREE.Geometry()), function() { - var face, idx, polyVerts, polygon, v, vertUvs, verts, _i, _len, _ref, _results; - _ref = _this.tree.allPolygons(); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - polygon = _ref[_i]; - polyVerts = (function() { - var _j, _len1, _ref1, _results1; - _ref1 = polygon.vertices; - _results1 = []; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - v = _ref1[_j]; - _results1.push(v.clone().applyMatrix4(matrix)); - } - return _results1; - })(); - _results.push((function() { - var _j, _ref1, _results1; - _results1 = []; - for (idx = _j = 2, _ref1 = polyVerts.length; 2 <= _ref1 ? _j < _ref1 : _j > _ref1; idx = 2 <= _ref1 ? ++_j : --_j) { - verts = [polyVerts[0], polyVerts[idx - 1], polyVerts[idx]]; - vertUvs = (function() { - var _k, _len1, _ref2, _ref3, _results2; - _results2 = []; - for (_k = 0, _len1 = verts.length; _k < _len1; _k++) { - v = verts[_k]; - _results2.push(new THREE.Vector2((_ref2 = v.uv) != null ? _ref2.x : void 0, (_ref3 = v.uv) != null ? _ref3.y : void 0)); - } - return _results2; - })(); - face = (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args); - return Object(result) === result ? result : child; - })(THREE.Face3, __slice.call((function() { - var _k, _len1, _results2; - _results2 = []; - for (_k = 0, _len1 = verts.length; _k < _len1; _k++) { - v = verts[_k]; - _results2.push(geometry.vertices.push(v) - 1); - } - return _results2; - })()).concat([polygon.normal.clone()]), function(){}); - geometry.faces.push(face); - _results1.push(geometry.faceVertexUvs[0].push(vertUvs)); - } - return _results1; - })()); - } - return _results; - }); - }; - - ThreeBSP.prototype.subtract = function(other) { - var them, us, _ref; - _ref = [this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1]; - us.invert().clipTo(them); - them.clipTo(us).invert().clipTo(us).invert(); - return new ThreeBSP(us.build(them.allPolygons()).invert(), this.matrix); - }; - - ThreeBSP.prototype.union = function(other) { - var them, us, _ref; - _ref = [this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1]; - us.clipTo(them); - them.clipTo(us).invert().clipTo(us).invert(); - return new ThreeBSP(us.build(them.allPolygons()), this.matrix); - }; - - ThreeBSP.prototype.intersect = function(other) { - var them, us, _ref; - _ref = [this.tree.clone(), other.tree.clone()], us = _ref[0], them = _ref[1]; - them.clipTo(us.invert()).invert().clipTo(us.clipTo(them)); - return new ThreeBSP(us.build(them.allPolygons()).invert(), this.matrix); - }; - - return ThreeBSP; - - })(); - - ThreeBSP.Vertex = (function(_super) { - __extends(Vertex, _super); - - function Vertex(x, y, z, normal, uv) { - this.normal = normal != null ? normal : new THREE.Vector3(); - this.uv = uv != null ? uv : new THREE.Vector2(); - this.interpolate = __bind(this.interpolate, this); - this.lerp = __bind(this.lerp, this); - Vertex.__super__.constructor.call(this, x, y, z); - } - - Vertex.prototype.clone = function() { - return new ThreeBSP.Vertex(this.x, this.y, this.z, this.normal.clone(), this.uv.clone()); - }; - - Vertex.prototype.lerp = function(v, alpha) { - var _this = this; - return returning(Vertex.__super__.lerp.apply(this, arguments), function() { - _this.uv.add(v.uv.clone().sub(_this.uv).multiplyScalar(alpha)); - return _this.normal.lerp(v, alpha); - }); - }; - - Vertex.prototype.interpolate = function() { - var args, _ref; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return (_ref = this.clone()).lerp.apply(_ref, args); - }; - - return Vertex; - - })(THREE.Vector3); - - ThreeBSP.Polygon = (function() { - function Polygon(vertices, normal, w) { - this.vertices = vertices != null ? vertices : []; - this.normal = normal; - this.w = w; - this.subdivide = __bind(this.subdivide, this); - this.tessellate = __bind(this.tessellate, this); - this.classifySide = __bind(this.classifySide, this); - this.classifyVertex = __bind(this.classifyVertex, this); - this.invert = __bind(this.invert, this); - this.clone = __bind(this.clone, this); - this.calculateProperties = __bind(this.calculateProperties, this); - if (this.vertices.length) { - this.calculateProperties(); - } - } - - Polygon.prototype.calculateProperties = function() { - var _this = this; - return returning(this, function() { - var a, b, c, _ref; - _ref = _this.vertices, a = _ref[0], b = _ref[1], c = _ref[2]; - _this.normal = b.clone().sub(a).cross(c.clone().sub(a)).normalize(); - return _this.w = _this.normal.clone().dot(a); - }); - }; - - Polygon.prototype.clone = function() { - var v; - return new ThreeBSP.Polygon((function() { - var _i, _len, _ref, _results; - _ref = this.vertices; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - v = _ref[_i]; - _results.push(v.clone()); - } - return _results; - }).call(this), this.normal.clone(), this.w); - }; - - Polygon.prototype.invert = function() { - var _this = this; - return returning(this, function() { - _this.normal.multiplyScalar(-1); - _this.w *= -1; - return _this.vertices.reverse(); - }); - }; - - Polygon.prototype.classifyVertex = function(vertex) { - var side; - side = this.normal.dot(vertex) - this.w; - switch (false) { - case !(side < -EPSILON): - return BACK; - case !(side > EPSILON): - return FRONT; - default: - return COPLANAR; - } - }; - - Polygon.prototype.classifySide = function(polygon) { - var back, front, tally, v, _i, _len, _ref, _ref1, - _this = this; - _ref = [0, 0], front = _ref[0], back = _ref[1]; - tally = function(v) { - switch (_this.classifyVertex(v)) { - case FRONT: - return front += 1; - case BACK: - return back += 1; - } - }; - _ref1 = polygon.vertices; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - v = _ref1[_i]; - tally(v); - } - if (front > 0 && back === 0) { - return FRONT; - } - if (front === 0 && back > 0) { - return BACK; - } - if ((front === back && back === 0)) { - return COPLANAR; - } - return SPANNING; - }; - - Polygon.prototype.tessellate = function(poly) { - var b, count, f, i, j, polys, t, ti, tj, v, vi, vj, _i, _len, _ref, _ref1, _ref2, - _this = this; - _ref = { - f: [], - b: [], - count: poly.vertices.length - }, f = _ref.f, b = _ref.b, count = _ref.count; - if (this.classifySide(poly) !== SPANNING) { - return [poly]; - } - _ref1 = poly.vertices; - for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) { - vi = _ref1[i]; - vj = poly.vertices[(j = (i + 1) % count)]; - _ref2 = (function() { - var _j, _len1, _ref2, _results; - _ref2 = [vi, vj]; - _results = []; - for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { - v = _ref2[_j]; - _results.push(this.classifyVertex(v)); - } - return _results; - }).call(this), ti = _ref2[0], tj = _ref2[1]; - if (ti !== BACK) { - f.push(vi); - } - if (ti !== FRONT) { - b.push(vi); - } - if ((ti | tj) === SPANNING) { - t = (this.w - this.normal.dot(vi)) / this.normal.dot(vj.clone().sub(vi)); - v = vi.interpolate(vj, t); - f.push(v); - b.push(v); - } - } - return returning((polys = []), function() { - if (f.length >= 3) { - polys.push(new ThreeBSP.Polygon(f)); - } - if (b.length >= 3) { - return polys.push(new ThreeBSP.Polygon(b)); - } - }); - }; - - Polygon.prototype.subdivide = function(polygon, coplanar_front, coplanar_back, front, back) { - var poly, side, _i, _len, _ref, _results; - _ref = this.tessellate(polygon); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - poly = _ref[_i]; - side = this.classifySide(poly); - switch (side) { - case FRONT: - _results.push(front.push(poly)); - break; - case BACK: - _results.push(back.push(poly)); - break; - case COPLANAR: - if (this.normal.dot(poly.normal) > 0) { - _results.push(coplanar_front.push(poly)); - } else { - _results.push(coplanar_back.push(poly)); - } - break; - default: - throw new Error("BUG: Polygon of classification " + side + " in subdivision"); - } - } - return _results; - }; - - return Polygon; - - })(); - - ThreeBSP.Node = (function() { - Node.prototype.clone = function() { - var node, - _this = this; - return returning((node = new ThreeBSP.Node()), function() { - var p, _ref, _ref1, _ref2; - node.divider = (_ref = _this.divider) != null ? _ref.clone() : void 0; - node.polygons = (function() { - var _i, _len, _ref1, _results; - _ref1 = this.polygons; - _results = []; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - p = _ref1[_i]; - _results.push(p.clone()); - } - return _results; - }).call(_this); - node.front = (_ref1 = _this.front) != null ? _ref1.clone() : void 0; - return node.back = (_ref2 = _this.back) != null ? _ref2.clone() : void 0; - }); - }; - - function Node(polygons) { - this.clipTo = __bind(this.clipTo, this); - this.clipPolygons = __bind(this.clipPolygons, this); - this.invert = __bind(this.invert, this); - this.allPolygons = __bind(this.allPolygons, this); - this.isConvex = __bind(this.isConvex, this); - this.build = __bind(this.build, this); - this.clone = __bind(this.clone, this); - this.polygons = []; - if ((polygons != null) && polygons.length) { - this.build(polygons); - } - } - - Node.prototype.build = function(polygons) { - var _this = this; - return returning(this, function() { - var poly, polys, side, sides, _i, _len, _results; - sides = { - front: [], - back: [] - }; - if (_this.divider == null) { - _this.divider = polygons[0].clone(); - } - for (_i = 0, _len = polygons.length; _i < _len; _i++) { - poly = polygons[_i]; - _this.divider.subdivide(poly, _this.polygons, _this.polygons, sides.front, sides.back); - } - _results = []; - for (side in sides) { - if (!__hasProp.call(sides, side)) continue; - polys = sides[side]; - if (polys.length) { - if (_this[side] == null) { - _this[side] = new ThreeBSP.Node(); - } - _results.push(_this[side].build(polys)); - } else { - _results.push(void 0); - } - } - return _results; - }); - }; - - Node.prototype.isConvex = function(polys) { - var inner, outer, _i, _j, _len, _len1; - for (_i = 0, _len = polys.length; _i < _len; _i++) { - inner = polys[_i]; - for (_j = 0, _len1 = polys.length; _j < _len1; _j++) { - outer = polys[_j]; - if (inner !== outer && outer.classifySide(inner) !== BACK) { - return false; - } - } - } - return true; - }; - - Node.prototype.allPolygons = function() { - var _ref, _ref1; - return this.polygons.slice().concat(((_ref1 = this.front) != null ? _ref1.allPolygons() : void 0) || []).concat(((_ref = this.back) != null ? _ref.allPolygons() : void 0) || []); - }; - - Node.prototype.invert = function() { - var _this = this; - return returning(this, function() { - var flipper, poly, _i, _j, _len, _len1, _ref, _ref1, _ref2; - _ref = _this.polygons; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - poly = _ref[_i]; - poly.invert(); - } - _ref1 = [_this.divider, _this.front, _this.back]; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - flipper = _ref1[_j]; - if (flipper != null) { - flipper.invert(); - } - } - return _ref2 = [_this.back, _this.front], _this.front = _ref2[0], _this.back = _ref2[1], _ref2; - }); - }; - - Node.prototype.clipPolygons = function(polygons) { - var back, front, poly, _i, _len; - if (!this.divider) { - return polygons.slice(); - } - front = []; - back = []; - for (_i = 0, _len = polygons.length; _i < _len; _i++) { - poly = polygons[_i]; - this.divider.subdivide(poly, front, back, front, back); - } - if (this.front) { - front = this.front.clipPolygons(front); - } - if (this.back) { - back = this.back.clipPolygons(back); - } - return front.concat(this.back ? back : []); - }; - - Node.prototype.clipTo = function(node) { - var _this = this; - return returning(this, function() { - var _ref, _ref1; - _this.polygons = node.clipPolygons(_this.polygons); - if ((_ref = _this.front) != null) { - _ref.clipTo(node); - } - return (_ref1 = _this.back) != null ? _ref1.clipTo(node) : void 0; - }); - }; - - return Node; - - })(); - -}).call(this); diff --git a/static/js/app.js b/static/js/app.js index 288ebe8..9e5eebe 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -46,6 +46,8 @@ this.initReSize(this); this.initPointLockControl(this); this.initFloor(); + this.initBuilding(); + this.initTransporter(this); } this.animate = function () { requestAnimationFrame(this.animate.bind(this)); @@ -324,6 +326,20 @@ // this.addObject(new Floor({position: {}})) } + this.initBuilding = function () { + let buildingData = buildingObjects.objects; + for (let i = 0; i < buildingData.length; i++) { + let objectOption = buildingData[i]; + switch (objectOption.objectType) { + case "cube": + let cube = new Cube(objectOption); + this.addObject(cube); + break; + } + } + } + this.initTransporter = function (object) { + } this.initStoreObjects = function (object) { if (this.firstTime === 1) { if (Store3DData !== undefined && Store3DData !== null) { diff --git a/static/js/common.js b/static/js/common.js index 12c1943..36f535e 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -1,68 +1,66 @@ + function CommonFunction() { } + /** * 鍒ゆ柇褰撳墠瀵硅薄鏄惁涓虹┖瀵硅薄 */ CommonFunction.hasObj = function (obj) { - if (obj != null && typeof (obj) != "undefined") { - return true; - } else { - return false; - } -}, - /** - * 鍒涘缓鏉愯川 - * length锛氭潗璐ㄧ殑闀� - * width锛氭潗璐ㄥ搴� - * style:鏉愯川鐗规�� - */ - CommonFunction.createMaterial = function (length, width, style) { - var color = 0xFF0000;//鏉愯川鐨勯鑹� - var image = null;//鎵嶆槸鏄惁鏈夎创鍥� - var texture = null; - var allowRepeat = 0;//璐村浘鏄惁璁剧疆閲嶅鏄剧ず - var transparent = 0;//鏉愯川鏄惁閫忔槑 - var opacity = 0;//鏉愯川閫忔槑搴� - var depthTest = 1;//鏉愯川娣卞害娴嬭瘯 - if (CommonFunction.hasObj(style)) { - color = style.color || 0xFF0000; - image = style.image || null; - allowRepeat = style.allowRepeat || 0; - transparent = style.transparent || 0; - opacity = style.opacity || 0; - depthTest = style.depthTest; - } - let material = new THREE.MeshPhongMaterial({map: texture, color: color}); - if (image != null) { - texture = new THREE.TextureLoader().load(image); - if (allowRepeat == 1) { - texture.repeat.x = length / 128; - texture.repeat.y = width / 128; - texture.repeat.y = 5; - texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + return obj != null && typeof (obj) != "undefined"; +} - } - material = new THREE.MeshPhongMaterial({map: texture}); - } - if (transparent == 1) { - material.transparent = true; - } - if (depthTest == 0) { - material.depthTest = false; - } - material.opacity = opacity; - return material; +/** + * 鍒涘缓鏉愯川 + * length锛氭潗璐ㄧ殑闀� + * width锛氭潗璐ㄥ搴� + * style:鏉愯川鐗规�� + */ +CommonFunction.createMaterial = function (length, width, style) { + var color = 0xFF0000;//鏉愯川鐨勯鑹� + var image = null;//鎵嶆槸鏄惁鏈夎创鍥� + var texture = null; + var allowRepeat = 0;//璐村浘鏄惁璁剧疆閲嶅鏄剧ず + var transparent = 0;//鏉愯川鏄惁閫忔槑 + var opacity = 0;//鏉愯川閫忔槑搴� + var depthTest = 1;//鏉愯川娣卞害娴嬭瘯 + if (CommonFunction.hasObj(style)) { + color = style.color || 0xFF0000; + image = style.image || null; + allowRepeat = style.allowRepeat || 0; + transparent = style.transparent || 0; + opacity = style.opacity || 0; + depthTest = style.depthTest; } + let material = new THREE.MeshPhongMaterial({map: texture, color: color}); + if (image != null) { + texture = new THREE.TextureLoader().load(image); + if (allowRepeat === 1) { + texture.repeat.x = length / 128; + texture.repeat.y = width / 128; + texture.repeat.y = 5; + texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + + } + material = new THREE.MeshPhongMaterial({map: texture}); + } + if (transparent === 1) { + material.transparent = true; + } + if (depthTest === 0) { + material.depthTest = false; + } + material.opacity = opacity; + return material; +} + /** * 杞崲鍧愭爣 * positionOri锛氬師濮嬪潗鏍� * positionTrans:杞崲鍧愭爣 */ - -CommonFunction.transPosition=function(positionOri,positionTrans) -{ +CommonFunction.transPosition=function(positionOri,positionTrans) { positionOri.X = positionOri.X + positionTrans.X; positionOri.Y = positionOri.Y + positionTrans.Y; diff --git a/static/js/data/BuildingData.js b/static/js/data/BuildingData.js new file mode 100644 index 0000000..0286b00 --- /dev/null +++ b/static/js/data/BuildingData.js @@ -0,0 +1,19 @@ +let buildingObjects = { + objects: [ + { + objectName: 'floor', + objectType: 'cube', + length: 1400, + width: 1200, + height: 1, + position: { + x: 700, + y: 600, + z: 0 + }, + style:{ + color: 0x5F7480, + } + } + ] +} diff --git a/static/js/object/CrnTask.js b/static/js/object/CrnTask.js index 6a81258..24cef5d 100644 --- a/static/js/object/CrnTask.js +++ b/static/js/object/CrnTask.js @@ -54,7 +54,7 @@ that.crnLoad = getArrVal(object.objects, "name", that.crnNo + "-load"); that.crnFork = getArrVal(object.objects, "name", that.crnNo + "-fork"); if (that.crnBody===null || that.crnLoad===null || that.crnFork==null) { - console.log(that.crnNo + "鍙峰爢鍨涙満娌℃湁鍒濆鍖�"); + // console.log(that.crnNo + "鍙峰爢鍨涙満娌℃湁鍒濆鍖�"); } }; init(); @@ -163,7 +163,7 @@ } curves.map((value, index) => { - console.log(value.part + " --> " + JSON.stringify(value.route.points)) + // console.log(value.part + " --> " + JSON.stringify(value.route.points)) }); curves[0].start = true; diff --git a/views/index.html b/views/index.html index dcf9b4d..153f898 100644 --- a/views/index.html +++ b/views/index.html @@ -13,6 +13,7 @@ <script type="text/javascript" src="../static/js/utils.js"></script> <script type="text/javascript" src="../static/js/common.js"></script> <script type="text/javascript" src="../static/js/data/Asrs.js"></script> + <script type="text/javascript" src="../static/js/data/BuildingData.js"></script> <script type="text/javascript" src="../static/js/object/Cube.js"></script> <script type="text/javascript" src="../static/js/object/StoreArea.js"></script> <script type="text/javascript" src="../static/js/object/Store.js"></script> -- Gitblit v1.9.1