From d8afdfd08aec7f044357713e2ac4df15c45a6083 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Mon, 20 Jul 2015 11:05:48 +0200 Subject: [PATCH 001/113] init test commit --- .gitignore | 4 + LICENSE | 21 +++ README.md | 32 ++++ bower.json | 21 +++ css/styles.css | 168 +++++++++++++++++++ data/get.xml | 173 ++++++++++++++++++++ data/model.yin | 413 +++++++++++++++++++++++++++++++++++++++++++++++ data/test.xml | 30 ++++ index.html | 33 ++++ js/JSONedit.js | 30 ++++ js/directives.js | 255 +++++++++++++++++++++++++++++ 11 files changed, 1180 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bower.json create mode 100644 css/styles.css create mode 100644 data/get.xml create mode 100644 data/model.yin create mode 100644 data/test.xml create mode 100644 index.html create mode 100644 js/JSONedit.js create mode 100644 js/directives.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ea4793b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.DS_STORE +*.swp +bower_components/* +.idea diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..ec26a86b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mauro Bieg + +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. diff --git a/README.md b/README.md new file mode 100644 index 00000000..d0a52f36 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# JSONedit + +User friendly, visual JSON editor built as an AngularJS directive. Provides a basic GUI to edit JSON. + +**[Give it a try!](http://mb21.github.io/JSONedit)** + +#### Use as Angular module + + $ bower install json-edit + +```javascript +// require module in your app: +var app = angular.module('exampleApp', ['JSONedit']); +``` + +```html + +
+ +
+ + + + + + + + + + + +``` diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..e7bdf385 --- /dev/null +++ b/bower.json @@ -0,0 +1,21 @@ +{ + "name": "JSONedit", + "version": "0.2.1", + "description": "User friendly, visual JSON editor built as an AngularJS directive. Provides a basic GUI to edit JSON.", + "repository": "https://github.com/mb21/JSONedit", + "homepage": "http://mb21.github.io/JSONedit/", + "license": "MIT License", + "main": [ + "css/styles.css", + "js/directives.js" + ], + "ignore": [ + "index.html", + "js/JSONedit.js" + ], + "dependencies": { + "bootstrap": "3.x.x", + "angular": "1.2.x", + "angular-ui-sortable": "0.12.x" + } +} diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 00000000..d3ce2954 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,168 @@ +#mainView { + margin: 30px auto; + width: 700px; +} +#jsonTextarea { + width: 700px; + height: 300px; +} +.red { + color: red; +} + + +/* JSON VIEW */ + +/* striped background */ +.jsonView { + background-color: #f3f6fa; + background-image: linear-gradient(rgba(255, 255, 255, 1) 50%, transparent 50%, transparent); + background-size: 60px 60px; + padding: 30px 0 0 5px; + background-attachment: local; +} +/* inputs */ +.jsonView select.form-control { + margin: 0; + padding: 0; +} +.jsonView select.form-control, .jsonView input.form-control { + width: 100px; + display: inline; + height: 29px; + padding-left: 5px; +} +.jsonView input[type="text"] { + margin: 0; + border: 0; + background: none; +} +.jsonView input[type="checkbox"] { + position: absolute; +} +.jsonView input.keyinput { + font-weight: bold; +} +.jsonView input { + height: 30px; + margin: 0; + padding: 0; +} +.jsonView input[type="text"].addItemKeyInput, .jsonView input[type="text"].addItemValueInput { + border: 1px solid #ccc; + background: white; + margin-left: 0; +} +.jsonView .addItemKeyInput { + font-weight: bold; +} + +/* chevrons */ +.jsonView .glyphicon-chevron-right, .jsonView .glyphicon-chevron-down { + float: left; + cursor: pointer; + position: relative; + top: 7px; + right: 22px; + margin-right: -15px; +} +.jsonView > json > .glyphicon-chevron-down { + display: none; +} +/* add and delete */ +.jsonView .addObjectItemBtn { + background-color: transparent; + border-color: transparent; + padding: 0; + border: 0; + height: 30px; + display: block; +} +.jsonView .addObjectItemBtn i { + display: block; +} +.jsonView .deleteKeyBtn, .jsonView .moveArrayItemBtn { + float: right; + margin-right: 10px; + position: relative; + top: 7px; + z-index: 99999999999999; + cursor: pointer; +} + +/* basic layout */ +.jsonView .jsonObjectKey { + font-weight: bold; +} +.jsonContents { + margin-left: 25px; +} +.jsonView .block { + display: block; +} +.jsonView .jsonItemDesc { + font-family: Georgia, serif; + color: grey; + font-style: italic; + cursor: default; + line-height: 30px +} +.jsonView .objectDesc { + cursor: default; +} +/* first brace */ +.jsonView > json > .jsonItemDesc { + display: block; + float: left; + position: relative; + bottom: 25px; + height: 0; + width: 0; +} + +/* array numbering */ +.jsonView ol.arrayOl { + margin: 0; + padding-left: 25px; +} +.jsonView ol.arrayOl > li > span > span > json > .glyphicon-chevron-down, +.jsonView ol.arrayOl > li > span > span > json > .glyphicon-chevron-right { + left: -40px; +} +.jsonView ol.arrayOl li { + color: grey; + font-style: italic; + font-family: Georgia, serif; + list-style-type: decimal; +} +.jsonView ol.arrayOl li input, .jsonView li select, .jsonView li button { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: normal; +} +.jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc) { + color: black; +} + +.jsonView li li { + list-style-type: lower-roman; +} +.jsonView li li li { + list-style-type: upper-roman; +} +.jsonView li li li li { + list-style-type: lower-latin; +} +.jsonView li li li li li { + list-style-type: upper-latin; +} +.jsonView li li li li li li { + list-style-type: lower-greek; +} +.jsonView li li li li li li li { + list-style-type: decimal; +} +.sortable-placeholder { + height: 20px; + display: block; +} + diff --git a/data/get.xml b/data/get.xml new file mode 100644 index 00000000..4d5c5b85 --- /dev/null +++ b/data/get.xml @@ -0,0 +1,173 @@ + + + + profile_name + true + + nfreader + true + /data/svepes/bin/nfdump_reader + /data/svepes/nfreader_input.dat + + + SERVICE + SERVICE + nfreader_service + + + UNIXSOCKET + OUT + nfreader_out + + + false + 0 + + + flowcounter + true + /data/svepes/bin/flowcounter + + + SERVICE + SERVICE + flowcounter_service + + + UNIXSOCKET + IN + nfreader_out + 7708881 + 0 + 0 + 0 + + + true + 0 + + + + + /data/svepes/bin/ + + + + flowcounter + Example module for counting number of incoming flow records. + 1 + 0 + + -u + -- + Specify UniRec template expected on the input interface. + false + + + + -p + -- + Show progress - print a dot every N flows. + true + int32 + + + -P + -- + When showing progress, print CHAR instead of dot. + true + string + + + -o + -- + Send @VOLUME record filled with current counters every SEC second(s). + true + int32 + + + + amplification_detection + + + nfdump_reader + This module reads a given nfdump file and outputs flow records in UniRec format. If more files are specified, all flows from the first file are read, then all flows from second file and so on. + 0 + 1 + + -F + -- + A file in nfdump format. + true + string + + + -f + -- + A nfdump-like filter expression. Only records matching the filter will be sent to the output. + true + string + + + -c + -- + Read only the first N flow records. + true + uint64 + + + -n + -- + Don't send EOF message at the end. + false + + + + -T + -- + Replace original timestamps by record actual sending time. + false + + + + -D + -- + Fill DIR_BIT_FIELD according to record direction. + false + + + + -l + -- + Use link mask m for LINK_BIT_FIELD. m is 8-bit hexadecimal number e.g. m should be 1, c2, AB,... + true + string + + + -p + -- + Show progress - print a dot every N flows. + true + uint64 + + + -r + -- + Rate limiting. Limiting sending flow rate to N records/sec. + true + uint64 + + + -R + -- + Real time re-sending. Resending records from given files in real time, respecting original timestamps (seconds). Since this mode is timestamp order dependent, real time re-sending is done only at approximate time. + false + + + + + brute_force_detector + + + + \ No newline at end of file diff --git a/data/model.yin b/data/model.yin new file mode 100644 index 00000000..8c51f43c --- /dev/null +++ b/data/model.yin @@ -0,0 +1,413 @@ + + + + + CESNET, z.s.p.o. + + + cejkat@cesnet.cz + + + Module specifying configuration of Nemea supervisor. + + + + Model with state information and notification. + + + + + + + IP/TCP for intermachine connections. + + + + + UNIX socket for local connections. + + + + + Service communication interface for module-supervisor communication. + + + + + + + + + Input interface. + + + + + Output interface. + + + + + Service interface. + + + + + + + + + + + Verbose level of supervisor log. + + + + + + + Global number of automatic restarts of a module that ends. + + + + + + + Path to supervisor logs directory (also with outputs of started modules) + + + + + + + Directories searched by supervisor for Nemea modules + + + + + Individual path with nemea modules. + + + + + + All Nemea modules that were found in search-paths + + + + + Describes one available module. + + + + + + + Name that is presented by the module. + + + + + + + Description of the module. + + + + + + + Number of module output interfaces. + + + + + + + Number of module input interfaces. + + + + + + Contains information about one particular parameter of the module. + + + + + + + Short version of the module parameter. + + + + + + + Long version of the module parameter. + + + + + + + + Description of the module parameter + + + + + + + Information, whether the parameter has mandatory argument. + + + + + + + + int8 is expected for the parameter + + + + + int16 is expected for the parameter + + + + + int32 is expected for the parameter + + + + + int64 is expected for the parameter + + + + + uint8 is expected for the parameter + + + + + uint16 is expected for the parameter + + + + + uint32 is expected for the parameter + + + + + uint64 is expected for the parameter + + + + + Float argument is expected for the parameter. + + + + + String argument is expected for the parameter. + + + + + The data type of the parameters argument. + + + + + + + + + + + + + + Name of group of Nemea modules. + + + + + + Activation of group of Nemea modules. + + + + + + + + Unique name of the module. + + + + + + Additional parameters of the module (program). + + + + + + + Specify whether to start the module or not. + + + + + + + Specify whether the module is running. + + + + + + + The number of repeated starts of the module. + + + + + + + Path to module (executable file). + + + + + + + Global number of automatic restarts of a module that ends. + + + + + + + + + + Type of libtrap communication interface. + + + + + + + Type of libtrap communication interface. + + + + + + + Parameters of libtrap interface: hostname,port for input interface; port for output interface. + + + + + + Optional note for interface + + + + + + + Number of sent messages. + + + + + + + Number of received messages. + + + + + + + Number of sent buffers. + + + + + + + Number of Auto-Flush calls. + + + + + + + Number of dropped buffers. + + + + + + + Number of dropped messages. + + + + + + + + + + Indicates that the status of module has changed. + + + + + Module unique name. + + + + + Indicates the actual module status + + + + + The module was started. + + + + + The module was stopped. + + + + + The module was restarted. + + + + + The module was disabled. + + + + + + + + Reason of changing the status of module. + + + + \ No newline at end of file diff --git a/data/test.xml b/data/test.xml new file mode 100644 index 00000000..7c6496e2 --- /dev/null +++ b/data/test.xml @@ -0,0 +1,30 @@ + + + + + + QWZ5671 + 39.95 + + Red + Burgundy + + + Red + Burgundy + + + + RRX9856 + Dec 25, 1995 + 42.50 + + Black + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..004b63a0 --- /dev/null +++ b/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + +
+

JSONedit

+ + +
+ +
+ +
+
+ + JSON not well-formed! +
+
+ + + + diff --git a/js/JSONedit.js b/js/JSONedit.js new file mode 100644 index 00000000..b8b1af4a --- /dev/null +++ b/js/JSONedit.js @@ -0,0 +1,30 @@ +'use strict'; + +var app = angular.module('exampleApp', ['JSONedit']); + +function MainViewCtrl($scope, $filter, $http, $window) { + + $http.get('data/get.xml').success(function(data) { + var xml = data; + // example JSON + $scope.jsonData = JXON.stringToJs(xml); + }); + + $scope.$watch('jsonData', function (json) { + $scope.jsonString = $filter('json')(json); + }, true); + $scope.$watch('jsonString', function (json) { + try { + $scope.jsonData = JSON.parse(json); + $scope.wellFormed = true; + } catch (e) { + $scope.wellFormed = false; + } + }, true); + + $scope.download = function(jsonData) { + var result = JXON.jsToString(jsonData); + result = result.replace(/xmlns:all/g, 'xmlns'); + $window.open("data:text/xml;charset=utf-8," + encodeURIComponent(result)); + }; +} diff --git a/js/directives.js b/js/directives.js new file mode 100644 index 00000000..73d2ee75 --- /dev/null +++ b/js/directives.js @@ -0,0 +1,255 @@ +'use strict'; + +angular.module('JSONedit', ['ui.sortable']) +.directive('ngModelOnblur', function() { + // override the default input to update on blur + // from http://jsfiddle.net/cn8VF/ + return { + restrict: 'A', + require: 'ngModel', + link: function(scope, elm, attr, ngModelCtrl) { + if (attr.type === 'radio' || attr.type === 'checkbox') return; + + elm.unbind('input').unbind('keydown').unbind('change'); + elm.bind('blur', function() { + scope.$apply(function() { + ngModelCtrl.$setViewValue(elm.val()); + }); + }); + } + }; +}) +.directive('json', ["$compile", function($compile) { + return { + restrict: 'E', + scope: { + child: '=', + type: '@', + defaultCollapsed: '=' + }, + link: function(scope, element, attributes) { + var stringName = "Text"; + var objectName = "Object"; + var arrayName = "Array"; + var refName = "Reference"; + var boolName = "Boolean" + + scope.valueTypes = [stringName, objectName, arrayName, refName, boolName]; + scope.sortableOptions = { + axis: 'y' + }; + if (scope.$parent.defaultCollapsed === undefined) { + scope.collapsed = false; + } else { + scope.collapsed = scope.defaultCollapsed; + } + if (scope.collapsed) { + scope.chevron = "glyphicon-chevron-right"; + } else { + scope.chevron = "glyphicon-chevron-down"; + } + + + ////// + // Helper functions + ////// + + var getType = function(obj) { + var type = Object.prototype.toString.call(obj); + if (type === "[object Object]") { + return "Object"; + } else if(type === "[object Array]"){ + return "Array"; + } else if(type === "[object Boolean]"){ + return "Boolean"; + } else { + return "Literal"; + } + }; + var isNumber = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + scope.getType = function(obj) { + return getType(obj); + }; + scope.toggleCollapse = function() { + if (scope.collapsed) { + scope.collapsed = false; + scope.chevron = "glyphicon-chevron-down"; + } else { + scope.collapsed = true; + scope.chevron = "glyphicon-chevron-right"; + } + }; + scope.moveKey = function(obj, key, newkey) { + //moves key to newkey in obj + if (key !== newkey) { + obj[newkey] = obj[key]; + delete obj[key]; + } + }; + scope.deleteKey = function(obj, key) { + if (getType(obj) == "Object") { + if( confirm('Delete "'+key+'" and all it contains?') ) { + delete obj[key]; + } + } else if (getType(obj) == "Array") { + if( confirm('Delete "'+obj[key]+'"?') ) { + obj.splice(key, 1); + } + } else { + console.error("object to delete from was " + obj); + } + }; + scope.addItem = function(obj) { + if (getType(obj) == "Object") { + // check input for key + if (scope.keyName == undefined || scope.keyName.length == 0){ + alert("Please fill in a name"); + } else if (scope.keyName.indexOf("$") == 0){ + alert("The name may not start with $ (the dollar sign)"); + } else if (scope.keyName.indexOf("_") == 0){ + alert("The name may not start with _ (the underscore)"); + } else { + if (obj[scope.keyName]) { + if( !confirm('An item with the name "'+scope.keyName + +'" exists already. Do you really want to replace it?') ) { + return; + } + } + // add item to object + switch(scope.valueType) { + case stringName: obj[scope.keyName] = scope.valueName ? scope.possibleNumber(scope.valueName) : ""; + break; + case objectName: obj[scope.keyName] = {}; + break; + case arrayName: obj[scope.keyName] = []; + break; + case refName: obj[scope.keyName] = {"Reference!!!!": "todo"}; + break; + case boolName: obj[scope.keyName] = false; + break; + } + //clean-up + scope.keyName = ""; + scope.valueName = ""; + scope.showAddKey = false; + } + } else if (getType(obj) == "Array") { + // add item to array + switch(scope.valueType) { + case stringName: obj.push(scope.valueName ? scope.valueName : ""); + break; + case objectName: obj.push({}); + break; + case arrayName: obj.push([]); + break; + case boolName: obj.push(false); + break; + case refName: obj.push({"Reference!!!!": "todo"}); + break; + } + scope.valueName = ""; + scope.showAddKey = false; + } else { + console.error("object to add to was " + obj); + } + }; + scope.possibleNumber = function(val) { + return isNumber(val) ? parseFloat(val) : val; + }; + + ////// + // Template Generation + ////// + + // Note: + // sometimes having a different ng-model and then saving it on ng-change + // into the object or array is necessary for all updates to work + + // recursion + var switchTemplate = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + + // display either "plus button" or "key-value inputs" + var addItemTemplate = + '
' + + ''; + if (scope.type == "object"){ + // input key + addItemTemplate += ' '; + } + addItemTemplate += + // value type dropdown + '' + // input value + + ' : ' + // Add button + + ' ' + + '' + + '' + + '' + // plus button + + '' + + '' + + '
'; + + // start template + if (scope.type == "object"){ + var template = '' + + ''+objectName+'' + + '
' + // repeat + + '' + // object key + + '' + + '' + // delete button + + '' + + '' + // object value + + '' + switchTemplate + '' + + '' + // repeat end + + addItemTemplate + + '
'; + } else if (scope.type == "array") { + var template = '' + + ''+arrayName+'' + + '
' + + '
    ' + // repeat + + '
  1. ' + // delete button + + '' + + '' + + '' + switchTemplate + '' + + '
  2. ' + // repeat end + + '
' + + addItemTemplate + + '
'; + } else { + console.error("scope.type was "+ scope.type); + } + + var newElement = angular.element(template); + $compile(newElement)(scope); + element.replaceWith ( newElement ); + } + }; +}]); From d27658e16e79e8626609fccf34382472542ec93a Mon Sep 17 00:00:00 2001 From: David Alexa Date: Mon, 20 Jul 2015 11:06:38 +0200 Subject: [PATCH 002/113] delete README content --- README.md | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/README.md b/README.md index d0a52f36..e69de29b 100644 --- a/README.md +++ b/README.md @@ -1,32 +0,0 @@ -# JSONedit - -User friendly, visual JSON editor built as an AngularJS directive. Provides a basic GUI to edit JSON. - -**[Give it a try!](http://mb21.github.io/JSONedit)** - -#### Use as Angular module - - $ bower install json-edit - -```javascript -// require module in your app: -var app = angular.module('exampleApp', ['JSONedit']); -``` - -```html - -
- -
- - - - - - - - - - - -``` From 98e29b060a9e65c2aedfff41a2645307d2fbe630 Mon Sep 17 00:00:00 2001 From: david alexa Date: Mon, 12 Oct 2015 16:03:21 +0200 Subject: [PATCH 003/113] oprava zavislosti --- bower.json | 22 +++++++++++++++------- index.html | 2 +- js/JSONedit.js | 1 - 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/bower.json b/bower.json index e7bdf385..afc48c20 100644 --- a/bower.json +++ b/bower.json @@ -1,21 +1,29 @@ { - "name": "JSONedit", - "version": "0.2.1", - "description": "User friendly, visual JSON editor built as an AngularJS directive. Provides a basic GUI to edit JSON.", + "name": "JSONtest", + "version": "0.0.1", + "description": "test for netopeergui", "repository": "https://github.com/mb21/JSONedit", "homepage": "http://mb21.github.io/JSONedit/", "license": "MIT License", "main": [ "css/styles.css", - "js/directives.js" + "js/JSONedit.js" ], "ignore": [ "index.html", - "js/JSONedit.js" + "js/JSONedit.js", + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" ], "dependencies": { "bootstrap": "3.x.x", "angular": "1.2.x", - "angular-ui-sortable": "0.12.x" - } + "angular-ui-sortable": "0.12.x", + "jxon": "~1.5.4" + }, + "moduleType": [], + "private": true } diff --git a/index.html b/index.html index 004b63a0..d82a0534 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@
-

JSONedit

+

NetopeerGUI - JXON test

diff --git a/js/JSONedit.js b/js/JSONedit.js index b8b1af4a..3584f81c 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -24,7 +24,6 @@ function MainViewCtrl($scope, $filter, $http, $window) { $scope.download = function(jsonData) { var result = JXON.jsToString(jsonData); - result = result.replace(/xmlns:all/g, 'xmlns'); $window.open("data:text/xml;charset=utf-8," + encodeURIComponent(result)); }; } From 19482286f1af2c8ba66b1dd9146af46d1559ff6e Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 3 Nov 2015 06:43:42 +0100 Subject: [PATCH 004/113] pridana podpora ciselneho vystupu --- bower.json | 5 +- css/styles.css | 6 +- data/get.xml | 2 +- data/get2.xml | 195 +++++++++++++++++++++++++++++ index.html | 5 +- js/JSONedit.js | 4 +- js/directives.js | 5 + js/directives2.js | 307 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 521 insertions(+), 8 deletions(-) create mode 100644 data/get2.xml create mode 100644 js/directives2.js diff --git a/bower.json b/bower.json index afc48c20..324ad543 100644 --- a/bower.json +++ b/bower.json @@ -20,9 +20,10 @@ ], "dependencies": { "bootstrap": "3.x.x", - "angular": "1.2.x", + "angular": "~1.4.7", "angular-ui-sortable": "0.12.x", - "jxon": "~1.5.4" + "jxon": "~1.5.4", + "angular-bootstrap": "~0.14.1" }, "moduleType": [], "private": true diff --git a/css/styles.css b/css/styles.css index d3ce2954..805926d0 100644 --- a/css/styles.css +++ b/css/styles.css @@ -1,6 +1,6 @@ #mainView { margin: 30px auto; - width: 700px; + width: 95%; } #jsonTextarea { width: 700px; @@ -32,7 +32,7 @@ height: 29px; padding-left: 5px; } -.jsonView input[type="text"] { +.jsonView input[type="text"], .jsonView input[type="number"] { margin: 0; border: 0; background: none; @@ -81,7 +81,7 @@ .jsonView .addObjectItemBtn i { display: block; } -.jsonView .deleteKeyBtn, .jsonView .moveArrayItemBtn { +.jsonView .iconButton { float: right; margin-right: 10px; position: relative; diff --git a/data/get.xml b/data/get.xml index 4d5c5b85..b937b218 100644 --- a/data/get.xml +++ b/data/get.xml @@ -170,4 +170,4 @@ - \ No newline at end of file + diff --git a/data/get2.xml b/data/get2.xml new file mode 100644 index 00000000..25e9a8b1 --- /dev/null +++ b/data/get2.xml @@ -0,0 +1,195 @@ + + + + false + permit + 0 + 0 + ano + + + + diff --git a/index.html b/index.html index d82a0534..ee9c78e7 100644 --- a/index.html +++ b/index.html @@ -6,9 +6,12 @@ + + - + + diff --git a/js/JSONedit.js b/js/JSONedit.js index 3584f81c..13ff8c9c 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -4,7 +4,7 @@ var app = angular.module('exampleApp', ['JSONedit']); function MainViewCtrl($scope, $filter, $http, $window) { - $http.get('data/get.xml').success(function(data) { + $http.get('data/get2.xml').success(function(data) { var xml = data; // example JSON $scope.jsonData = JXON.stringToJs(xml); @@ -24,6 +24,8 @@ function MainViewCtrl($scope, $filter, $http, $window) { $scope.download = function(jsonData) { var result = JXON.jsToString(jsonData); + result = result.replace(/xmlns:all/g, 'xmlns'); + result = result.replace(/\s[^(xmlns)]\w*=\"[a-zA-Z0-9\s\d\.\(\)\\\/\-,\'\|:]*\"/gim, ''); // remove all attributes $window.open("data:text/xml;charset=utf-8," + encodeURIComponent(result)); }; } diff --git a/js/directives.js b/js/directives.js index 73d2ee75..f96dc02f 100644 --- a/js/directives.js +++ b/js/directives.js @@ -62,6 +62,8 @@ angular.module('JSONedit', ['ui.sortable']) return "Array"; } else if(type === "[object Boolean]"){ return "Boolean"; + } else if(type === "[object Number]"){ + return "Number"; } else { return "Literal"; } @@ -175,6 +177,9 @@ angular.module('JSONedit', ['ui.sortable']) + '' + '' + '' + + '' + + '' + + '' + '' + '' diff --git a/js/directives2.js b/js/directives2.js new file mode 100644 index 00000000..b7162fe1 --- /dev/null +++ b/js/directives2.js @@ -0,0 +1,307 @@ +'use strict'; + +angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) +.directive('ngModelOnblur', function() { + // override the default input to update on blur + // from http://jsfiddle.net/cn8VF/ + return { + restrict: 'A', + require: 'ngModel', + link: function(scope, elm, attr, ngModelCtrl) { + if (attr.type === 'radio' || attr.type === 'checkbox') return; + + elm.unbind('input').unbind('keydown').unbind('change'); + elm.bind('blur', function() { + scope.$apply(function() { + ngModelCtrl.$setViewValue(elm.val()); + }); + }); + } + }; +}) +.directive('json', ["$compile", "$log", function($compile, $log) { + return { + restrict: 'E', + scope: { + child: '=', + type: '@', + defaultCollapsed: '=' + }, + link: function(scope, element, attributes) { + var stringName = "Text"; + var objectName = "Object"; + var arrayName = "Array"; + var numberName = "Number"; + var urlName = "Url"; + var refName = "Reference"; + var boolName = "Boolean"; + var literalName = "Literal"; + + //scope.valueTypes = [stringName, objectName, arrayName, numberName, urlName, refName, boolName, literalName]; + scope.valueTypes = [stringName, objectName, arrayName, refName, boolName]; + scope.sortableOptions = { + axis: 'y' + }; + if (scope.$parent.defaultCollapsed === undefined) { + scope.collapsed = false; + } else { + scope.collapsed = scope.defaultCollapsed; + } + if (scope.collapsed) { + scope.chevron = "glyphicon-chevron-right"; + } else { + scope.chevron = "glyphicon-chevron-down"; + } + + + ////// + // Helper functions + ////// + var isNumberType = function(type) { + return type.indexOf('int') >= 0; + }; + + var isUrlType = function(type) { + return type === "inet:uri"; + }; + + var getType = function(obj) { + // get custom yang datatype + var type = Object.prototype.toString.call(obj); + + if (type === "[object Object]") { + return objectName; + } else if(type === "[object Array]"){ + return arrayName; + } + + if (typeof obj['@type'] !== "undefined") { + type = obj['@type']; + } + + if(type === "Boolean" || type === "[object Boolean]"){ + return boolName; + } else if(isNumberType(type) || type === "[object Number]"){ + // TODO: check range + return numberName; + } else { + return literalName; + } + }; + var isNumber = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + scope.getType = function(obj) { + return getType(obj); + }; + + var editBarVisible = function(obj) { + if (typeof obj['@type'] !== "undefined") { + var type = obj['@type']; + return (type == "list" || type == "leaf-list" || type == "container"); + } + + return false; + }; + scope.editBarVisible = function(obj) { + return editBarVisible(obj); + }; + scope.toggleCollapse = function() { + if (scope.collapsed) { + scope.collapsed = false; + scope.chevron = "glyphicon-chevron-down"; + } else { + scope.collapsed = true; + scope.chevron = "glyphicon-chevron-right"; + } + }; + scope.moveKey = function(obj, key, newkey) { + //moves key to newkey in obj + if (key !== newkey) { + obj[newkey] = obj[key]; + delete obj[key]; + } + }; + scope.deleteKey = function(obj, key) { + if (getType(obj) == "Object") { + if( confirm('Delete "'+key+'" and all it contains?') ) { + delete obj[key]; + } + } else if (getType(obj) == "Array") { + if( confirm('Delete "'+obj[key]+'"?') ) { + obj.splice(key, 1); + } + } else { + console.error("object to delete from was " + obj); + } + }; + scope.addItem = function(obj) { + if (getType(obj) == "Object") { + // check input for key + if (scope.keyName == undefined || scope.keyName.length == 0){ + alert("Please fill in a name"); + } else if (scope.keyName.indexOf("$") == 0){ + alert("The name may not start with $ (the dollar sign)"); + } else if (scope.keyName.indexOf("_") == 0){ + alert("The name may not start with _ (the underscore)"); + } else { + if (obj[scope.keyName]) { + if( !confirm('An item with the name "'+scope.keyName + +'" exists already. Do you really want to replace it?') ) { + return; + } + } + // add item to object + switch(scope.valueType) { + case stringName: obj[scope.keyName] = scope.valueName ? scope.possibleNumber(scope.valueName) : ""; + break; + case objectName: obj[scope.keyName] = {}; + break; + case arrayName: obj[scope.keyName] = []; + break; + case refName: obj[scope.keyName] = {"Reference!!!!": "todo"}; + break; + case boolName: obj[scope.keyName] = false; + break; + } + //clean-up + scope.keyName = ""; + scope.valueName = ""; + scope.showAddKey = false; + } + } else if (getType(obj) == "Array") { + // add item to array + switch(scope.valueType) { + case stringName: obj.push(scope.valueName ? scope.valueName : ""); + break; + case objectName: obj.push({}); + break; + case arrayName: obj.push([]); + break; + case boolName: obj.push(false); + break; + case refName: obj.push({"Reference!!!!": "todo"}); + break; + } + scope.valueName = ""; + scope.showAddKey = false; + } else { + console.error("object to add to was " + obj); + } + }; + scope.possibleNumber = function(val) { + return isNumber(val) ? parseFloat(val) : val; + }; + + ////// + // Template Generation + ////// + + // Note: + // sometimes having a different ng-model and then saving it on ng-change + // into the object or array is necessary for all updates to work + + // recursion + var switchTemplate = + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''; + + // display either "plus button" or "key-value inputs" + var addItemTemplate = + '
' + + ''; + if (scope.type == "object"){ + // input key + addItemTemplate += ' '; + } + addItemTemplate += + // value type dropdown + '' + // input value + + ' : ' + // Add button + + ' ' + + '' + + '' + + '' + // plus button + + '' + + '' + + '
'; + + // start template + if (scope.type == "object"){ + var template = '' + + '' + //+ ''+objectName+'' + + '
' + // repeat + + '' + // object key + + '' + + '' + // delete button + + '' + // info button + + '' + + '' + // object value + + '' + switchTemplate + '' + + '' + // repeat end + + addItemTemplate + + '
'; + } else if (scope.type == "array") { + var template = '' + + '' + + ''+arrayName+'' + + '
' + + '
    ' + // repeat + + '
  1. ' + // info button + + '' + + '' + + '' + switchTemplate + '' + + '
  2. ' + // repeat end + + '
' + + addItemTemplate + + '
'; + } else { + console.error("scope.type was "+ scope.type); + } + + var newElement = angular.element(template); + $compile(newElement)(scope); + element.replaceWith ( newElement ); + } + }; +}]) +.filter('skipAttributes', function() { + return function(items) { + var result = {}; + angular.forEach(items, function(value, key) { + if (key.indexOf('@') !== 0) { + result[key] = value; + } + }); + return result; + }; +}); From e06fd2424edcc1655e1fcfe13b73e02e7d19e2e7 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 3 Nov 2015 12:59:36 +0100 Subject: [PATCH 005/113] nacitame primo JSON misto XML --- bower.json | 1 - data/get.json | 76 +++++++ data/test.json | 515 ++++++++++++++++++++++++++++++++++++++++++++++ index.html | 7 +- js/JSONedit.js | 22 +- js/directives2.js | 9 +- 6 files changed, 607 insertions(+), 23 deletions(-) create mode 100644 data/get.json create mode 100644 data/test.json diff --git a/bower.json b/bower.json index 324ad543..1fbdf1b1 100644 --- a/bower.json +++ b/bower.json @@ -22,7 +22,6 @@ "bootstrap": "3.x.x", "angular": "~1.4.7", "angular-ui-sortable": "0.12.x", - "jxon": "~1.5.4", "angular-bootstrap": "~0.14.1" }, "moduleType": [], diff --git a/data/get.json b/data/get.json new file mode 100644 index 00000000..debf537e --- /dev/null +++ b/data/get.json @@ -0,0 +1,76 @@ +{ + "$@ietf-interfaces:interfaces": { + "eltype": "leaf", + "config": "false", + "type": "enumeration", + "enumval": ["int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "string"], + "description": "The data type of the parameters argument.", + "mandatory": "false", + "iskey": "false", + "children": ["interface", "interface-state"] + }, + "ietf-interfaces:interfaces": { + + "$@interface": { + "eltype": "list", + "config": "true", + "type": "enumeration", + "iskey": "false" + }, + "interface": [ + { + "$@name": { + "config": "true", + "type": "string", + "description": "The data type of the parameters argument." + }, + "name": "eth0", + + "$@type": { + "typedef": { + "type": "uint8", + "range": "0 .. 100", + "description": "Percentage" + } + }, + "type": "iana-if-type:ethernetCsmacd", + + "$@enabled": { + "type": "boolean" + }, + "enabled": false + }, + { + "$@name": { + "config": "true", + "type": "string" + }, + "name": "eth1", + + "$@type": { + "typedef": { + "type": "uint8", + "range": "0 .. 100", + "description": "Percentage" + } + }, + "type": "iana-if-type:ethernetCsmacd", + "enabled": true, + "ex-vlan:vlan-tagging": true + } + ] + }, + + "$@ietf-interfaces:interfaces-state": { + "eltype": "leaf", + "config": "false", + "type": "enumeration", + "enumval": ["int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "string"], + "description": "The data type of the parameters argument.", + "mandatory": "false", + "iskey": "false" + }, + "ietf-interfaces:interfaces-state": { + + } +} diff --git a/data/test.json b/data/test.json new file mode 100644 index 00000000..739e5409 --- /dev/null +++ b/data/test.json @@ -0,0 +1,515 @@ +{ + "jsonQ_root": { + "$@ietf-interfaces:interfaces": { + "eltype": "leaf", + "config": "false", + "type": "enumeration", + "enumval": [ + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "float", + "string" + ], + "description": "The data type of the parameters argument.", + "mandatory": "false", + "iskey": "false", + "children": [ + "interface", + "interface-state" + ] + }, + "ietf-interfaces:interfaces": { + "$@interface": { + "eltype": "list", + "config": "true", + "type": "enumeration", + "iskey": "false" + }, + "interface": [ + { + "$@name": { + "config": "true", + "type": "string" + }, + "name": "eth0", + "$@type": { + "typedef": { + "type": "uint8", + "range": "0 .. 100", + "description": "Percentage" + } + }, + "type": "iana-if-type:ethernetCsmacd", + "$@enabled": { + "type": "boolean" + }, + "enabled": false + }, + { + "$@name": { + "config": "true", + "type": "string" + }, + "name": "eth1", + "$@type": { + "typedef": { + "type": "uint8", + "range": "0 .. 100", + "description": "Percentage" + } + }, + "type": "iana-if-type:ethernetCsmacd", + "enabled": true, + "ex-vlan:vlan-tagging": true + } + ] + }, + "$@ietf-interfaces:interfaces-state": { + "eltype": "leaf", + "config": "false", + "type": "enumeration", + "enumval": [ + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "float", + "string" + ], + "description": "The data type of the parameters argument.", + "mandatory": "false", + "iskey": "false" + }, + "ietf-interfaces:interfaces-state": {} + }, + "jsonQ_current": [ + { + "path": [] + } + ], + "$@ietf-interfaces:interfaces": [ + { + "path": [ + "$@ietf-interfaces:interfaces" + ] + } + ], + "eltype": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "eltype" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "$@interface", + "eltype" + ] + }, + { + "path": [ + "$@ietf-interfaces:interfaces-state", + "eltype" + ] + } + ], + "config": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "config" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "$@interface", + "config" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@name", + "config" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@name", + "config" + ] + }, + { + "path": [ + "$@ietf-interfaces:interfaces-state", + "config" + ] + } + ], + "type": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "$@interface", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@name", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@type", + "typedef", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@enabled", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@name", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@type", + "typedef", + "type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "type" + ] + }, + { + "path": [ + "$@ietf-interfaces:interfaces-state", + "type" + ] + } + ], + "enumval": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "enumval" + ] + }, + { + "path": [ + "$@ietf-interfaces:interfaces-state", + "enumval" + ] + } + ], + "description": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "description" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@type", + "typedef", + "description" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@type", + "typedef", + "description" + ] + }, + { + "path": [ + "$@ietf-interfaces:interfaces-state", + "description" + ] + } + ], + "mandatory": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "mandatory" + ] + }, + { + "path": [ + "$@ietf-interfaces:interfaces-state", + "mandatory" + ] + } + ], + "iskey": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "iskey" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "$@interface", + "iskey" + ] + }, + { + "path": [ + "$@ietf-interfaces:interfaces-state", + "iskey" + ] + } + ], + "children": [ + { + "path": [ + "$@ietf-interfaces:interfaces", + "children" + ] + } + ], + "ietf-interfaces:interfaces": [ + { + "path": [ + "ietf-interfaces:interfaces" + ] + } + ], + "$@interface": [ + { + "path": [ + "ietf-interfaces:interfaces", + "$@interface" + ] + } + ], + "interface": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface" + ] + } + ], + "$@name": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@name" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@name" + ] + } + ], + "name": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "name" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "name" + ] + } + ], + "$@type": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@type" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@type" + ] + } + ], + "typedef": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@type", + "typedef" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@type", + "typedef" + ] + } + ], + "range": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@type", + "typedef", + "range" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "$@type", + "typedef", + "range" + ] + } + ], + "$@enabled": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "$@enabled" + ] + } + ], + "enabled": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "0", + "enabled" + ] + }, + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "enabled" + ] + } + ], + "ex-vlan:vlan-tagging": [ + { + "path": [ + "ietf-interfaces:interfaces", + "interface", + "1", + "ex-vlan:vlan-tagging" + ] + } + ], + "$@ietf-interfaces:interfaces-state": [ + { + "path": [ + "$@ietf-interfaces:interfaces-state" + ] + } + ], + "ietf-interfaces:interfaces-state": [ + { + "path": [ + "ietf-interfaces:interfaces-state" + ] + } + ], + "length": 1, + "selector": [] +} \ No newline at end of file diff --git a/index.html b/index.html index ee9c78e7..cf51c278 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,6 @@ - + - @@ -16,9 +15,9 @@ -
+

NetopeerGUI - JXON test

- +
diff --git a/js/JSONedit.js b/js/JSONedit.js index 13ff8c9c..004638a8 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -1,13 +1,9 @@ -'use strict'; +var app = angular.module('NetopeerGUIApp', ['JSONedit']) -var app = angular.module('exampleApp', ['JSONedit']); +.controller('ConfigurationController', function($scope, $filter, $http, $window) { -function MainViewCtrl($scope, $filter, $http, $window) { - - $http.get('data/get2.xml').success(function(data) { - var xml = data; - // example JSON - $scope.jsonData = JXON.stringToJs(xml); + $http.get('data/get.json').success(function(data) { + $scope.jsonData = data; }); $scope.$watch('jsonData', function (json) { @@ -23,9 +19,11 @@ function MainViewCtrl($scope, $filter, $http, $window) { }, true); $scope.download = function(jsonData) { - var result = JXON.jsToString(jsonData); - result = result.replace(/xmlns:all/g, 'xmlns'); - result = result.replace(/\s[^(xmlns)]\w*=\"[a-zA-Z0-9\s\d\.\(\)\\\/\-,\'\|:]*\"/gim, ''); // remove all attributes - $window.open("data:text/xml;charset=utf-8," + encodeURIComponent(result)); + //var result = JSON.stringify(jsonData); + //result = result.replace(/xmlns:all/g, 'xmlns'); + //result = result.replace(/\s[^(xmlns)]\w*=\"[a-zA-Z0-9\s\d\.\(\)\\\/\-,\'\|:]*\"/gim, ''); // remove all attributes + var cleanJson = JSON.stringify(jsonData); + $window.open("data:application/json;charset=utf-8," + encodeURIComponent(cleanJson)); }; } +); \ No newline at end of file diff --git a/js/directives2.js b/js/directives2.js index b7162fe1..b086ee8b 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -250,15 +250,15 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) //+ ''+objectName+'' + '
' // repeat - + '' + + '' // object key + '' + '' // delete button - + '' + + '' // info button - + '' + + '' + '' // object value + '' + switchTemplate + '' @@ -275,9 +275,6 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) + '
    ' // repeat + '
  1. ' - // info button - + '' - + '' + '' + switchTemplate + '' + '
  2. ' // repeat end From 88b00f67937006e2f70c057d8d2c52388f1194c1 Mon Sep 17 00:00:00 2001 From: david alexa Date: Wed, 4 Nov 2015 09:08:15 +0100 Subject: [PATCH 006/113] oprava nacitani JSON (uz neignoruje $@), vystup je od techto informaci odfiltrovan. Lehka uprava vzhledu vypisu. --- css/styles.css | 15 ++++++++++----- index.html | 2 +- js/JSONedit.js | 5 +++-- js/directives2.js | 21 ++++++++++++++------- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/css/styles.css b/css/styles.css index 805926d0..846d097e 100644 --- a/css/styles.css +++ b/css/styles.css @@ -58,7 +58,7 @@ } /* chevrons */ -.jsonView .glyphicon-chevron-right, .jsonView .glyphicon-chevron-down { +.jsonView .glyphicon-menu-right, .jsonView .glyphicon-menu-down { float: left; cursor: pointer; position: relative; @@ -66,7 +66,7 @@ right: 22px; margin-right: -15px; } -.jsonView > json > .glyphicon-chevron-down { +.jsonView > json > .glyphicon-menu-down { display: none; } /* add and delete */ @@ -97,6 +97,7 @@ .jsonContents { margin-left: 25px; } +li .jsonContents { margin-left: 0px; } .jsonView .block { display: block; } @@ -123,10 +124,14 @@ /* array numbering */ .jsonView ol.arrayOl { margin: 0; - padding-left: 25px; + padding-left: 20px; } -.jsonView ol.arrayOl > li > span > span > json > .glyphicon-chevron-down, -.jsonView ol.arrayOl > li > span > span > json > .glyphicon-chevron-right { +.jsonView li { clear: both; min-height: 30px; } +.jsonView ol.arrayOl .glyphicon-menu-down { + margin-left: -20px; +} +.jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-down, +.jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-right { left: -40px; } .jsonView ol.arrayOl li { diff --git a/index.html b/index.html index cf51c278..bcee25ab 100644 --- a/index.html +++ b/index.html @@ -16,7 +16,7 @@
    -

    NetopeerGUI - JXON test

    +

    NetopeerGUI - JSON test

    diff --git a/js/JSONedit.js b/js/JSONedit.js index 004638a8..b3a42721 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -7,7 +7,7 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit']) }); $scope.$watch('jsonData', function (json) { - $scope.jsonString = $filter('json')(json); + $scope.jsonString = JSON.stringify(json); }, true); $scope.$watch('jsonString', function (json) { try { @@ -22,7 +22,8 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit']) //var result = JSON.stringify(jsonData); //result = result.replace(/xmlns:all/g, 'xmlns'); //result = result.replace(/\s[^(xmlns)]\w*=\"[a-zA-Z0-9\s\d\.\(\)\\\/\-,\'\|:]*\"/gim, ''); // remove all attributes - var cleanJson = JSON.stringify(jsonData); + //var cleanJson = JSON.stringify(jsonData); + var cleanJson = $filter('json')(jsonData); $window.open("data:application/json;charset=utf-8," + encodeURIComponent(cleanJson)); }; } diff --git a/js/directives2.js b/js/directives2.js index b086ee8b..690ba279 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -1,5 +1,9 @@ 'use strict'; +var counts = { + object: 0 +}; + angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) .directive('ngModelOnblur', function() { // override the default input to update on blur @@ -48,9 +52,9 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) scope.collapsed = scope.defaultCollapsed; } if (scope.collapsed) { - scope.chevron = "glyphicon-chevron-right"; + scope.chevron = "glyphicon-menu-right"; } else { - scope.chevron = "glyphicon-chevron-down"; + scope.chevron = "glyphicon-menu-down"; } @@ -109,10 +113,10 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) scope.toggleCollapse = function() { if (scope.collapsed) { scope.collapsed = false; - scope.chevron = "glyphicon-chevron-down"; + scope.chevron = "glyphicon-menu-down"; } else { scope.collapsed = true; - scope.chevron = "glyphicon-chevron-right"; + scope.chevron = "glyphicon-menu-right"; } }; scope.moveKey = function(obj, key, newkey) { @@ -245,8 +249,11 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) // start template if (scope.type == "object"){ - var template = '' - + '' + var template = ''; + if (counts.object++ > 0) { + template += ''; + } + template = template //+ ''+objectName+'' + '
    ' // repeat @@ -270,7 +277,7 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) var template = '' + '' - + ''+arrayName+'' + //+ ''+arrayName+'' + '
    ' + '
      ' // repeat From 7d52f83fa2940585a113ab2c70868dc3b8fb435c Mon Sep 17 00:00:00 2001 From: David Alexa Date: Fri, 6 Nov 2015 15:18:21 +0100 Subject: [PATCH 007/113] sablony jsou rozcleneny do samostatnych souboru. Nastaveno cachovani techto sablon pomoci gulp prikazu --- .gitignore | 1 + gulpfile.js | 11 +++ index.html | 8 +- js/directives/addItem.js | 6 ++ js/directives/switchItem.js | 6 ++ js/directives2.js | 115 +++++---------------------- public/templates.js | 4 + templates/directives/addItem.html | 22 +++++ templates/directives/switchItem.html | 13 +++ templates/types/array.html | 9 +++ templates/types/object.html | 13 +++ 11 files changed, 109 insertions(+), 99 deletions(-) create mode 100644 gulpfile.js create mode 100644 js/directives/addItem.js create mode 100644 js/directives/switchItem.js create mode 100644 public/templates.js create mode 100644 templates/directives/addItem.html create mode 100644 templates/directives/switchItem.html create mode 100644 templates/types/array.html create mode 100644 templates/types/object.html diff --git a/.gitignore b/.gitignore index ea4793b8..0da92878 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.DS_STORE *.swp bower_components/* +node_modules .idea diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..0e1e6272 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,11 @@ +var gulp = require('gulp'); +var templateCache = require('gulp-angular-templatecache'); + +gulp.task('default', function () { + return gulp.src('templates/**/*.html') + .pipe(templateCache('templates.js', { + standalone: true, + module: 'configurationTemplates' + })) + .pipe(gulp.dest('public')); +}); \ No newline at end of file diff --git a/index.html b/index.html index bcee25ab..e946054c 100644 --- a/index.html +++ b/index.html @@ -9,9 +9,13 @@ - + + + + + @@ -20,7 +24,7 @@

      NetopeerGUI - JSON test

      - +

      diff --git a/js/directives/addItem.js b/js/directives/addItem.js new file mode 100644 index 00000000..c9569517 --- /dev/null +++ b/js/directives/addItem.js @@ -0,0 +1,6 @@ +NetopeerGUI.directive('addItem', function() { + return { + restrict: 'E', + templateUrl: 'templates/directives/addItem.html' + }; +}) \ No newline at end of file diff --git a/js/directives/switchItem.js b/js/directives/switchItem.js new file mode 100644 index 00000000..567e8aa1 --- /dev/null +++ b/js/directives/switchItem.js @@ -0,0 +1,6 @@ +NetopeerGUI.directive('switchItem', function() { + return { + restrict: 'E', + templateUrl: 'templates/directives/switchItem.html' + }; +}); \ No newline at end of file diff --git a/js/directives2.js b/js/directives2.js index 690ba279..364f0352 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -4,8 +4,9 @@ var counts = { object: 0 }; -angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) -.directive('ngModelOnblur', function() { +var NetopeerGUI = angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap', 'configurationTemplates']); + +NetopeerGUI.directive('ngModelOnblur', function() { // override the default input to update on blur // from http://jsfiddle.net/cn8VF/ return { @@ -23,13 +24,22 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) } }; }) -.directive('json', ["$compile", "$log", function($compile, $log) { +.directive('json', function($compile, $log) { return { restrict: 'E', scope: { child: '=', type: '@', - defaultCollapsed: '=' + defaultCollapsed: '=', + hideCollapse: '=' + }, + controller: function($scope) { + $scope.getTemplateUrl = function(type) { + if (typeof type === 'undefined') { + type = $scope.type; + } + return 'types/'+type+'.html'; + }; }, link: function(scope, element, attributes) { var stringName = "Text"; @@ -99,7 +109,7 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) return getType(obj); }; - var editBarVisible = function(obj) { + scope.editBarVisible = function(obj) { if (typeof obj['@type'] !== "undefined") { var type = obj['@type']; return (type == "list" || type == "leaf-list" || type == "container"); @@ -107,9 +117,6 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) return false; }; - scope.editBarVisible = function(obj) { - return editBarVisible(obj); - }; scope.toggleCollapse = function() { if (scope.collapsed) { scope.collapsed = false; @@ -204,100 +211,14 @@ angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap']) // Note: // sometimes having a different ng-model and then saving it on ng-change // into the object or array is necessary for all updates to work - - // recursion - var switchTemplate = - '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + ''; - - // display either "plus button" or "key-value inputs" - var addItemTemplate = - '
      ' - + ''; - if (scope.type == "object"){ - // input key - addItemTemplate += ' '; - } - addItemTemplate += - // value type dropdown - '' - // input value - + ' : ' - // Add button - + ' ' - + '' - + '' - + '' - // plus button - + '' - + '' - + '
      '; - - // start template - if (scope.type == "object"){ - var template = ''; - if (counts.object++ > 0) { - template += ''; - } - template = template - //+ ''+objectName+'' - + '
      ' - // repeat - + '' - // object key - + '' - + '' - // delete button - + '' - // info button - + '' - + '' - // object value - + '' + switchTemplate + '' - + '' - // repeat end - + addItemTemplate - + '
      '; - } else if (scope.type == "array") { - var template = '' - + '' - //+ ''+arrayName+'' - + '
      ' - + '
        ' - // repeat - + '
      1. ' - + '' + switchTemplate + '' - + '
      2. ' - // repeat end - + '
      ' - + addItemTemplate - + '
      '; - } else { - console.error("scope.type was "+ scope.type); - } - var newElement = angular.element(template); + var newElement = '
      '; + newElement = angular.element(newElement); $compile(newElement)(scope); element.replaceWith ( newElement ); } }; -}]) +}) .filter('skipAttributes', function() { return function(items) { var result = {}; diff --git a/public/templates.js b/public/templates.js new file mode 100644 index 00000000..7d55270d --- /dev/null +++ b/public/templates.js @@ -0,0 +1,4 @@ +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n\n \n\n : \n\n \n \n \n \n \n \n
      "); +$templateCache.put("directives/switchItem.html","\n \n \n \n \n \n \n \n \n \n \n \n"); +$templateCache.put("types/array.html","\n
      \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); +$templateCache.put("types/object.html","\n
      \n \n \n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html new file mode 100644 index 00000000..b2fe3493 --- /dev/null +++ b/templates/directives/addItem.html @@ -0,0 +1,22 @@ +
      + + + + + + : + + + + + + + +
      \ No newline at end of file diff --git a/templates/directives/switchItem.html b/templates/directives/switchItem.html new file mode 100644 index 00000000..be9557db --- /dev/null +++ b/templates/directives/switchItem.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/types/array.html b/templates/types/array.html new file mode 100644 index 00000000..f1214a96 --- /dev/null +++ b/templates/types/array.html @@ -0,0 +1,9 @@ + +
      +
        +
      1. + +
      2. +
      + +
      \ No newline at end of file diff --git a/templates/types/object.html b/templates/types/object.html new file mode 100644 index 00000000..b16ccfbc --- /dev/null +++ b/templates/types/object.html @@ -0,0 +1,13 @@ + +
      + + + + + + + + + + +
      \ No newline at end of file From 7a30dab9edd5a1aa1d6e9787c35241478d1cc191 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 25 Nov 2015 09:37:30 +0100 Subject: [PATCH 008/113] implementace zakladni historie undo/redo (nefunguje jeste v switch-item). Upravy spojene se zmenou formatu (nove v real.json) obdrzenem ze serveru. --- css/styles.css | 18 +- data/real.json | 3284 ++++++++++++++++++++++++++ index.html | 4 + js/JSONedit.js | 93 +- js/directives.js | 260 -- js/directives2.js | 41 +- public/templates.js | 4 +- templates/directives/addItem.html | 8 +- templates/directives/switchItem.html | 12 +- 9 files changed, 3409 insertions(+), 315 deletions(-) create mode 100644 data/real.json delete mode 100644 js/directives.js diff --git a/css/styles.css b/css/styles.css index 846d097e..00c2a85f 100644 --- a/css/styles.css +++ b/css/styles.css @@ -15,11 +15,7 @@ /* striped background */ .jsonView { - background-color: #f3f6fa; - background-image: linear-gradient(rgba(255, 255, 255, 1) 50%, transparent 50%, transparent); - background-size: 60px 60px; padding: 30px 0 0 5px; - background-attachment: local; } /* inputs */ .jsonView select.form-control { @@ -34,7 +30,7 @@ } .jsonView input[type="text"], .jsonView input[type="number"] { margin: 0; - border: 0; + border: 1px solid #ccc; background: none; } .jsonView input[type="checkbox"] { @@ -62,7 +58,7 @@ float: left; cursor: pointer; position: relative; - top: 7px; + top: -22px; right: 22px; margin-right: -15px; } @@ -127,9 +123,15 @@ li .jsonContents { margin-left: 0px; } padding-left: 20px; } .jsonView li { clear: both; min-height: 30px; } -.jsonView ol.arrayOl .glyphicon-menu-down { +.jsonView ol.arrayOl .glyphicon-menu-down, .jsonView ol.arrayOl .glyphicon-menu-right { margin-left: -20px; } +.jsonView ol.arrayOl .glyphicon-menu-down { + top: 7px; +} +.jsonView ol.arrayOl .glyphicon-menu-right { + top: -16px; +} .jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-down, .jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-right { left: -40px; @@ -144,7 +146,7 @@ li .jsonContents { margin-left: 0px; } font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal; } -.jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc) { +.jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { color: black; } diff --git a/data/real.json b/data/real.json new file mode 100644 index 00000000..000058d4 --- /dev/null +++ b/data/real.json @@ -0,0 +1,3284 @@ +{ + "netopeer-cfgnetopeer:netopeer": { + "tls": { + "server-cert": "MIID+TCCAuGgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMCQ1ox\nFjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoM\nBkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJ\nKoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTE0MDcyNDE0MzI0NVoX\nDTE1MDcyNDE0MzI0NVowdjELMAkGA1UEBhMCQ1oxFjAUBgNVBAgMDVNvdXRoIE1v\ncmF2aWExDzANBgNVBAoMBkNFU05FVDEMMAoGA1UECwwDVE1DMQ8wDQYDVQQDDAZz\nZXJ2ZXIxHzAdBgkqhkiG9w0BCQEWEHNlcnZlckBsb2NhbGhvc3QwggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0jVMGPNfU+BBcW48LDn+RDBTuqSuGKsx\nwUBeEjwShd6k9r18oBW4yMdbfY\/qc3MOmeEV7RgZ02WggQ3eEknztxU6qPijvNkx\nurfNUbYvwCzsxMDy1hebZ9IL\/SsjHFFF6ZwZRczSr7gsQAKNmPak4qidqK8XlVuG\nA2M8I7UmP9NqZRzRpWITnvsL0v0SI5sYz5sZtptaT8pYouy\/FRz6wpldonumxNWC\nmCAkCRSzOWbA5CAWIxJHncT38ICRBiHMZUKYfjhWzofOzdFmM5Ntx7jCviieCIDk\nts95I1IIWPL2WgqloTWu06OQ0FV2I08JBOYu44NdRMqCR4v72\/87AgMBAAGjezB5\nMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENl\ncnRpZmljYXRlMB0GA1UdDgQWBBTzeoS1AMXMO8uhogi+qJTqTuPW6zAfBgNVHSME\nGDAWgBRzVhAiqNmwdXCV5rQAHg36KU0jaDANBgkqhkiG9w0BAQUFAAOCAQEAnyBQ\nx\/5caVqR2S0kBD8VG4BER5mIk3biDY2urzKHVG2GubvsFgrct1+vDUToFHyYwZtP\neRBORApiugqIP2WhKTIs1SDJ41X4IDnT\/ChNpZ89b31zja1TnuJTzTdXEebBGkb9\nns98BH8Tg2+QIFcNB0eXqIiG5HG++MVoc4WzKB12fvfVJHKm9iHPpAC+EyTVScVv\nL5otbwVhwp0MiaMDjEqoUJEbrT4JhtZh1BgCXzhw7LcNOD8Ukr6Q1uRue\/jjpJbC\nN6ofbnrSras5tJH9QWaW6tT5iDdIlKPExfrwHUqC4YHO0+3Q15yttwfh7wCwNU2H\ndP4VfSRdn\/LaTmR68Q==", + "server-key": { + "key-data": "MIIEowIBAAKCAQEAsdI1TBjzX1PgQXFuPCw5\/kQwU7qkrhirMcFAXhI8EoXepPa9\nfKAVuMjHW32P6nNzDpnhFe0YGdNloIEN3hJJ87cVOqj4o7zZMbq3zVG2L8As7MTA\n8tYXm2fSC\/0rIxxRRemcGUXM0q+4LEACjZj2pOKonaivF5VbhgNjPCO1Jj\/TamUc\n0aViE577C9L9EiObGM+bGbabWk\/KWKLsvxUc+sKZXaJ7psTVgpggJAkUszlmwOQg\nFiMSR53E9\/CAkQYhzGVCmH44Vs6Hzs3RZjOTbce4wr4ongiA5LbPeSNSCFjy9loK\npaE1rtOjkNBVdiNPCQTmLuODXUTKgkeL+9v\/OwIDAQABAoIBAG\/4MG1JbL4C\/7vV\npBcpth7Aaznd1eJ2UB4VVOWnT8JOH2L6p1h5KRRhAP9AMkXsCnAQPyZiVAG3FlAZ\n01SZaY2YJDr6uQ3JVW4155TWtgSdWux\/\/Ass+lJ17lJ0SRxjsV13ez6CsDWeRjc+\n2xy0S+KJgqk71XzhJG9fZLYyuddp3U\/i3xFPUAcQM9xXKxcaD7g6LJf+a9pt6rim\nEqq\/pjJxDgTsRLARsazYuxrlOB445mvnLiYhOf2\/MvI80jIUKaj8BeAhg49UIg\/k\nmIh0xdevkcxBFer\/BjBjscWaFjx14D6nkFMw7vtCum5KfalLN2edZKAzByOudGD4\n5KnRp3ECgYEA6vnSoNGg9Do80JOpXRGYWhcR1lIDO5yRW5rVagncCcW5Pn\/GMtNd\nx2q6k1ks8mXKR9CxZrxZGqeYObZ9a\/5SLih7ZkpiVWXG8ZiBIPhP6lnwm5OeIqLa\nhr0BYWcRfrGg1phj5uySZgsVBE+D8jH42O9ccdvrWv1OiryAHfKIcwMCgYEAwbs+\nHfQtvHOQXSYNhtOeA7IetkGy3cKVg2oILNcROvI96hS0MZKt1Rko0UAapx96eCIr\nel7vfdT0eUzNqt2wTKp1zmiG+SnX3fMDJNzMwu\/jb\/b4wQ20IHWNDnqcqTUVRUnL\niksLFoHbTxsN5NpEQExcSt\/zzP4qi1W2Bmo18WkCgYEAnhrk16LVux9ohiulHONW\n8N9u+BeM51JtGAcxrDzgGo85Gs2czdwc0K6GxdiN\/rfxCKtqgqcfCWlVaxfYgo7I\nOxiwF17blXx7BVrJICcUlqpX1Ebac5HCmkCYqjJQuj\/I6jv1lI7\/3rt8M79RF+j5\n+PXt7Qq97SZd78nwJrZni4MCgYAiPjZ8lOyAouyhilhZvI3xmUpUbMhw6jQDRnqr\nclhZUvgeqAoxuPuA7zGHywzq\/WVoVqHYv28Vjs6noiu4R\/chlf+8vD0fTYYadRnZ\nKi4HRt+sqrrNZN6x3hVQudt3DSr1VFXl293Z3JonIWETUoE93EFz+qHdWg+rETtb\nZuqiAQKBgD+HI\/syLECyO8UynuEaDD7qPl87PJ\/CmZLMxa2\/ZZUjhaXAW7CJMaS6\n9PIzsLk33y3O4Qer0wx\/tEdfnxMTBJrgGt\/lFFdAKhSJroZ45l5apiavg1oZYp89\njSd0lVxWSmrBjBZLnqOl336gzaBVkBD5ND+XUPdR1UuVQExJlem4", + "key-type": "RSA", + "$@key-data": { + "eltype": "leaf", + "description": "Server private key (in base64-encoded DER) matching\n the server certificate.", + "config": true, + "status": "current", + "mandatory": true, + "type": "binary", + "iskey": false + }, + "$@key-type": { + "eltype": "leaf", + "description": "The type of the server private key.", + "config": true, + "status": "current", + "mandatory": true, + "type": "enumeration", + "enumval": [ + "DSA", + "RSA" + ], + "iskey": false + } + }, + "trusted-ca-certs": { + "trusted-ca-cert": [ + "MIID7TCCAtWgAwIBAgIJAMtE1NGAR5KoMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD\nVQQGEwJDWjEWMBQGA1UECAwNU291dGggTW9yYXZpYTENMAsGA1UEBwwEQnJubzEP\nMA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxEzARBgNVBAMMCmV4YW1wbGUg\nQ0ExIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVjYUBsb2NhbGhvc3QwHhcNMTQwNzI0\nMTQxOTAyWhcNMjQwNzIxMTQxOTAyWjCBjDELMAkGA1UEBhMCQ1oxFjAUBgNVBAgM\nDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEM\nMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkB\nFhNleGFtcGxlY2FAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEArD3TDHPAMT2Z84orK4lMlarbgooIUCcRZyLe+QM+8KY8Hn+mGaxPEOTS\nL3ywszqefB\/Utm2hPKLHX684iRC14ID9WDGHxPjvoPArhgFhfV+qnPfxKTgxZC12\nuOj4u1V9y+SkTCocFbRfXVBGpojrBuDHXkDMDEWNvr8\/52YCv7bGaiBwUHolcLCU\nbmtKILCG0RNJyTaJpXQdAeq5Z1SJotpbfYFFtAXB32hVoLug1dzl2tjG9sb1wq3Q\naDExcbC5w6P65qOkNoyym9ne6QlQagCqVDyFn3vcqkRaTjvZmxauCeUxXgJoXkyW\ncm0lM1KMHdoTArmchw2Dz0yHHSyDAQIDAQABo1AwTjAdBgNVHQ4EFgQUc1YQIqjZ\nsHVwlea0AB4N+ilNI2gwHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gw\nDAYDVR0TBAUwAwEB\/zANBgkqhkiG9w0BAQUFAAOCAQEAI\/1KH60qnw9Xs2RGfi0\/\nIKf5EynXt4bQX8EIyVKwSkYKe04zZxYfLIl\/Q2HOPYoFmm3daj5ddr0ZS1i4p4fT\nUhstjsYWvXs3W\/HhVmFUslakkn3PrswhP77fCk6eEJLxdfyJ1C7Uudq2m1isZbKi\nh+XF0mG1LxJaDMocSz4eAya7M5brwjy8DoOmA1TnLQFCVcpn+sCr7VC4wE\/JqxyV\nhBCk\/MuGqqM3B1j90bGFZ112ZOecyE0EDSr6IbiRBtmeNbEwOFjKXhNLYdxpBZ9D\n8A\/368OckZkCrVLGuJNxK9UwCVTe8IhotHUqU9EqFDmxdV8oIdU\/OzUwwNPA\/Bd\/\n9g==" + ], + "$@trusted-ca-cert": { + "eltype": "leaf-list", + "description": "The binary certificate structure (DER) encoded\n in base64.", + "config": true, + "status": "current", + "mandatory": false, + "type": "binary" + } + }, + "cert-maps": { + "cert-to-name": [ + { + "id": 1, + "fingerprint": "02:E9:38:1F:F6:8B:62:DE:0A:0B:C5:03:81:A8:03:49:A0:00:7F:8B:F3", + "map-type": "ietf-x509-cert-to-name:specified", + "name": "default_ca", + "$@id": { + "eltype": "leaf", + "description": "The id specifies the order in which the entries in the\ncert-to-name list are searched. Entries with lower\nnumbers are searched first.", + "reference": "SNMP-TLS-TM-MIB.snmpTlstmCertToTSNID", + "config": true, + "status": "current", + "mandatory": false, + "type": "uint32", + "iskey": true + }, + "$@fingerprint": { + "eltype": "leaf", + "description": "Specifies a value with which the fingerprint of the\ncertificate presented by the peer is compared. If the\nfingerprint of the certificate presented by the peer does\nnot match the fingerprint configured, then the entry is\nskipped and the search for a match continues.", + "reference": "SNMP-TLS-TM-MIB.snmpTlstmCertToTSNFingerprint", + "config": true, + "status": "current", + "mandatory": true, + "type": "ietf-x509-cert-to-name:tls-fingerprint", + "typedef": { + "description": "A fingerprint value that can be used to uniquely reference\nother data of potentially arbitrary length.\n\nAn tls-fingerprint value is composed of a 1-octet hashing\nalgorithm identifier followed by the fingerprint value. The\nfirst octet value identifying the hashing algorithm is taken\nfrom the IANA TLS HashAlgorithm Registry (RFC 5246). The\nremaining octets are filled using the results of the hashing\nalgorithm.", + "reference": "SNMP-TLS-TM-MIB.SnmpTLSFingerprint", + "status": "current", + "type": "ietf-yang-types:hex-string", + "typedef": { + "description": "A hexadecimal string with octets represented as hex digits\nseparated by colons. The canonical representation uses\nlowercase characters.", + "status": "current", + "type": "string", + "pattern": [ + "([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?" + ] + } + }, + "iskey": false + }, + "$@map-type": { + "eltype": "leaf", + "description": "Specifies the algorithm used to map the certificate\npresented by the peer to a name.\n\nMappings that need additional configuration objects should\nuse the 'when' statement to make them conditional based on\nthe 'map-type'.", + "reference": "SNMP-TLS-TM-MIB.snmpTlstmCertToTSNMapType", + "config": true, + "status": "current", + "mandatory": true, + "type": "identityref", + "identityval": [ + "cert-to-name", + "specified", + "san-rfc822-name", + "san-dns-name", + "san-ip-address", + "san-any", + "common-name" + ], + "iskey": false + }, + "$@name": { + "eltype": "leaf", + "description": "Directly specifies the NETCONF username when the\n'map-type' is 'specified'.", + "reference": "SNMP-TLS-TM-MIB.snmpTlstmCertToTSNData", + "config": true, + "status": "current", + "mandatory": true, + "type": "string", + "when": "..\/map-type = 'ietf-x509-cert-to-name:specified'", + "iskey": false + } + } + ], + "$@cert-to-name": { + "eltype": "list", + "description": "This list defines how certificates are mapped to names.\nThe name is derived by considering each cert-to-name\nlist entry in order. The cert-to-name entry's fingerprint\ndetermines whether the list entry is a match:\n\n1) If the cert-to-name list entry's fingerprint value\n matches that of the presented certificate, then consider\n the list entry as a successful match.\n\n2) If the cert-to-name list entry's fingerprint value\n matches that of a locally held copy of a trusted CA\n certificate, and that CA certificate was part of the CA\n certificate chain to the presented certificate, then\n consider the list entry as a successful match.\n\nOnce a matching cert-to-name list entry has been found, the\nmap-type is used to determine how the name associated with\nthe certificate should be determined. See the map-type\nleaf's description for details on determining the name value.\nIf it is impossible to determine a name from the cert-to-name\nlist entry's data combined with the data presented in the\ncertificate, then additional cert-to-name list entries MUST\nbe searched looking for another potential match.\n\nSecurity administrators are encouraged to make use of\ncertificates with subjectAltName fields that can be mapped to\nnames so that a single root CA certificate can allow all\nchild certificate's subjectAltName to map directly to a name\nvia a 1:1 transformation.", + "reference": "SNMP-TLS-TM-MIB.snmpTlstmCertToTSNEntry", + "config": true, + "status": "current", + "mandatory": false, + "keys": [ + "id" + ] + } + }, + "$@server-cert": { + "eltype": "leaf", + "description": "Server certificate (in base64-encoded DER) presented to clients.", + "config": true, + "status": "current", + "mandatory": false, + "type": "binary", + "iskey": false + }, + "$@server-key": { + "eltype": "container", + "config": true, + "status": "current", + "mandatory": false, + "children": [ + "key-data", + "key-type" + ] + }, + "$@trusted-ca-certs": { + "eltype": "container", + "description": "A list of Certificate Authority (CA) certificates that a\nNETCONF server can use to authenticate a NETCONF client's\ncertificate. A client's certificate is authenticated if\nits Issuer matches one of the configured trusted CA\ncertificates.", + "config": true, + "status": "current", + "mandatory": false, + "children": [ + "trusted-ca-cert" + ] + }, + "$@cert-maps": { + "eltype": "container", + "description": "The cert-maps container is used by a NETCONF server to\nmap the NETCONF client's presented X.509 certificate to\na NETCONF username.\n\nIf no matching and valid cert-to-name list entry can be\nfound, then the NETCONF server MUST close the connection,\nand MUST NOT accept NETCONF messages over it.", + "config": true, + "status": "current", + "mandatory": false + } + }, + "$@tls": { + "eltype": "container", + "description": "Netopeer TLS options.", + "config": true, + "status": "current", + "mandatory": false, + "children": [ + "server-cert", + "server-key", + "trusted-ca-certs", + "trusted-client-certs", + "crl-dir", + "cert-maps" + ] + } + }, + "ietf-netconf-monitoring:netconf-state": { + "capabilities": { + "capability": [ + "urn:ietf:params:netconf:base:1.0", + "urn:ietf:params:netconf:base:1.1", + "urn:ietf:params:netconf:capability:writable-running:1.0", + "urn:ietf:params:netconf:capability:candidate:1.0", + "urn:ietf:params:netconf:capability:startup:1.0", + "urn:ietf:params:netconf:capability:rollback-on-error:1.0", + "urn:ietf:params:netconf:capability:interleave:1.0", + "urn:ietf:params:netconf:capability:notification:1.0", + "urn:ietf:params:netconf:capability:validate:1.0", + "urn:ietf:params:netconf:capability:validate:1.1", + "urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all,report-all-tagged,trim,explicit", + "urn:ietf:params:netconf:capability:url:1.0?scheme=scp,file", + "urn:cesnet:tmc:netopeer:1.0?module=netopeer-cfgnetopeer&revision=2015-05-19&features=ssh,tls,dynamic-modules", + "urn:ietf:params:xml:ns:yang:ietf-netconf-server?module=ietf-netconf-server&revision=2014-01-24&features=ssh,inbound-ssh,outbound-ssh,tls,inbound-tls,outbound-tls", + "urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name?module=ietf-x509-cert-to-name&revision=2013-03-26", + "urn:ietf:params:xml:ns:yang:ietf-netconf-acm?module=ietf-netconf-acm&revision=2012-02-22", + "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults?module=ietf-netconf-with-defaults&revision=2010-06-09", + "urn:ietf:params:xml:ns:netconf:notification:1.0?module=notifications&revision=2008-07-14", + "urn:ietf:params:xml:ns:netmod:notification?module=nc-notifications&revision=2008-07-14", + "urn:ietf:params:xml:ns:yang:ietf-netconf-notifications?module=ietf-netconf-notifications&revision=2012-02-06", + "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04", + "urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&revision=2011-03-08&features=writable-running,candidate,rollback-on-error,validate,startup,url", + "urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2013-07-15", + "urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2013-07-15" + ], + "$@capability": { + "eltype": "leaf-list", + "description": "List of NETCONF capabilities supported by the server.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + }, + "datastores": { + "datastore": [ + { + "name": "running", + "$@name": { + "eltype": "leaf", + "description": "Name of the datastore associated with this list entry.", + "config": false, + "status": "current", + "mandatory": false, + "type": "netconf-datastore-type", + "typedef": { + "description": "Enumeration of possible NETCONF datastore types.", + "reference": "RFC 4741: NETCONF Configuration Protocol", + "status": "current", + "type": "enumeration", + "enumval": [ + "running", + "candidate", + "startup" + ] + }, + "iskey": true + } + }, + { + "name": "startup", + "$@name": { + "eltype": "leaf", + "description": "Name of the datastore associated with this list entry.", + "config": false, + "status": "current", + "mandatory": false, + "type": "netconf-datastore-type", + "typedef": { + "description": "Enumeration of possible NETCONF datastore types.", + "reference": "RFC 4741: NETCONF Configuration Protocol", + "status": "current", + "type": "enumeration", + "enumval": [ + "running", + "candidate", + "startup" + ] + }, + "iskey": true + } + }, + { + "name": "candidate", + "$@name": { + "eltype": "leaf", + "description": "Name of the datastore associated with this list entry.", + "config": false, + "status": "current", + "mandatory": false, + "type": "netconf-datastore-type", + "typedef": { + "description": "Enumeration of possible NETCONF datastore types.", + "reference": "RFC 4741: NETCONF Configuration Protocol", + "status": "current", + "type": "enumeration", + "enumval": [ + "running", + "candidate", + "startup" + ] + }, + "iskey": true + } + } + ], + "$@datastore": { + "eltype": "list", + "description": "List of NETCONF configuration datastores supported by\nthe NETCONF server and related information.", + "config": false, + "status": "current", + "mandatory": false, + "keys": [ + "name" + ] + } + }, + "sessions": { + "session": [ + { + "session-id": 8, + "transport": "netconf-ssh", + "username": "vasko", + "source-host": "UNKNOWN", + "login-time": "0000-01-01T00:00:00Z", + "in-rpcs": 13, + "in-bad-rpcs": 0, + "out-rpc-errors": 0, + "out-notifications": 0, + "$@session-id": { + "eltype": "leaf", + "description": "Unique identifier for the session. This value is the\nNETCONF session identifier, as defined in RFC 4741.", + "reference": "RFC 4741: NETCONF Configuration Protocol", + "config": false, + "status": "current", + "mandatory": false, + "type": "uint32", + "range": "1..max", + "iskey": true + }, + "$@transport": { + "eltype": "leaf", + "description": "Identifies the transport for each session, e.g.,\n'netconf-ssh', 'netconf-soap', etc.", + "config": false, + "status": "current", + "mandatory": true, + "type": "identityref", + "identityval": [ + "transport", + "netconf-ssh", + "netconf-soap-over-beep", + "netconf-soap-over-https", + "netconf-beep", + "netconf-tls" + ], + "iskey": false + }, + "$@username": { + "eltype": "leaf", + "description": "The username is the client identity that was authenticated\nby the NETCONF transport protocol. The algorithm used to\nderive the username is NETCONF transport protocol specific\nand in addition specific to the authentication mechanism\nused by the NETCONF transport protocol.", + "config": false, + "status": "current", + "mandatory": true, + "type": "string", + "iskey": false + }, + "$@source-host": { + "eltype": "leaf", + "description": "Host identifier of the NETCONF client. The value\nreturned is implementation specific (e.g., hostname,\nIPv4 address, IPv6 address)", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-inet-types:host", + "typedef": { + "description": "The host type represents either an IP address or a DNS\ndomain name.", + "status": "current", + "type": "union", + "types": [ + { + "type": "ip-address", + "typedef": { + "description": "The ip-address type represents an IP address and is IP\nversion neutral. The format of the textual representation\nimplies the IP version. This type supports scoped addresses\nby allowing zone identifiers in the address format.", + "reference": "RFC 4007: IPv6 Scoped Address Architecture", + "status": "current", + "type": "union", + "types": [ + { + "type": "ipv4-address", + "typedef": { + "description": "The ipv4-address type represents an IPv4 address in\ndotted-quad notation. The IPv4 address may include a zone\nindex, separated by a % sign.\n\nThe zone index is used to disambiguate identical address\nvalues. For link-local addresses, the zone index will\ntypically be the interface index number or the name of an\ninterface. If the zone index is not present, the default\nzone of the device will be used.\n\nThe canonical format for the zone index is the numerical\nformat", + "status": "current", + "type": "string", + "pattern": [ + "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(%[\\p{N}\\p{L}]+)?" + ] + } + }, + { + "type": "ipv6-address", + "typedef": { + "description": "The ipv6-address type represents an IPv6 address in full,\nmixed, shortened, and shortened-mixed notation. The IPv6\naddress may include a zone index, separated by a % sign.\n\nThe zone index is used to disambiguate identical address\nvalues. For link-local addresses, the zone index will\ntypically be the interface index number or the name of an\ninterface. If the zone index is not present, the default\nzone of the device will be used.\n\n\n\nThe canonical format of IPv6 addresses uses the textual\nrepresentation defined in Section 4 of RFC 5952. The\ncanonical format for the zone index is the numerical\nformat as described in Section 11.2 of RFC 4007.", + "reference": "RFC 4291: IP Version 6 Addressing Architecture\nRFC 4007: IPv6 Scoped Address Architecture\nRFC 5952: A Recommendation for IPv6 Address Text\n Representation", + "status": "current", + "type": "string", + "pattern": [ + "((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(%[\\p{N}\\p{L}]+)?", + "((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))(%[\\p{N}\\p{L}]+)?" + ] + } + } + ] + } + }, + { + "type": "domain-name", + "typedef": { + "description": "The domain-name type represents a DNS domain name. The\nname SHOULD be fully qualified whenever possible.\n\nInternet domain names are only loosely specified. Section\n3.5 of RFC 1034 recommends a syntax (modified in Section\n2.1 of RFC 1123). The pattern above is intended to allow\nfor current practice in domain name use, and some possible\nfuture expansion. It is designed to hold various types of\ndomain names, including names used for A or AAAA records\n(host names) and other records, such as SRV records. Note\nthat Internet host names have a stricter syntax (described\nin RFC 952) than the DNS recommendations in RFCs 1034 and\n1123, and that systems that want to store host names in\nschema nodes using the domain-name type are recommended to\nadhere to this stricter standard to ensure interoperability.\n\nThe encoding of DNS names in the DNS protocol is limited\nto 255 characters. Since the encoding consists of labels\nprefixed by a length bytes and there is a trailing NULL\nbyte, only 253 characters can appear in the textual dotted\nnotation.\n\nThe description clause of schema nodes using the domain-name\ntype MUST describe when and how these names are resolved to\nIP addresses. Note that the resolution of a domain-name value\nmay require to query multiple DNS records (e.g., A for IPv4\nand AAAA for IPv6). The order of the resolution process and\nwhich DNS record takes precedence can either be defined\nexplicitly or may depend on the configuration of the\nresolver.\n\nDomain-name values use the US-ASCII encoding. Their canonical\nformat uses lowercase US-ASCII characters. Internationalized\ndomain names MUST be A-labels as per RFC 5890.", + "reference": "RFC 952: DoD Internet Host Table Specification\nRFC 1034: Domain Names - Concepts and Facilities\nRFC 1123: Requirements for Internet Hosts -- Application\n and Support\nRFC 2782: A DNS RR for specifying the location of services\n (DNS SRV)\nRFC 5890: Internationalized Domain Names in Applications\n (IDNA): Definitions and Document Framework", + "status": "current", + "type": "string", + "length": "1..253", + "pattern": [ + "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\." + ] + } + } + ] + }, + "iskey": false + }, + "$@login-time": { + "eltype": "leaf", + "description": "Time at the server at which the session was established.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-yang-types:date-and-time", + "typedef": { + "description": "The date-and-time type is a profile of the ISO 8601\nstandard for representation of dates and times using the\nGregorian calendar. The profile is defined by the\ndate-time production in Section 5.6 of RFC 3339.\n\nThe date-and-time type is compatible with the dateTime XML\nschema type with the following notable exceptions:\n\n(a) The date-and-time type does not allow negative years.\n\n(b) The date-and-time time-offset -00:00 indicates an unknown\n time zone (see RFC 3339) while -00:00 and +00:00 and Z\n all represent the same time zone in dateTime.\n\n(c) The canonical format (see below) of data-and-time values\n differs from the canonical format used by the dateTime XML\n schema type, which requires all times to be in UTC using\n the time-offset 'Z'.\n\nThis type is not equivalent to the DateAndTime textual\nconvention of the SMIv2 since RFC 3339 uses a different\nseparator between full-date and full-time and provides\nhigher resolution of time-secfrac.\n\nThe canonical format for date-and-time values with a known time\nzone uses a numeric time zone offset that is calculated using\nthe device's configured known offset to UTC time. A change of\nthe device's offset to UTC time will cause date-and-time values\nto change accordingly. Such changes might happen periodically\nin case a server follows automatically daylight saving time\n(DST) time zone offset changes. The canonical format for\ndate-and-time values with an unknown time zone (usually\nreferring to the notion of local time) uses the time-offset\n-00:00.", + "reference": "RFC 3339: Date and Time on the Internet: Timestamps\nRFC 2579: Textual Conventions for SMIv2\nXSD-TYPES: XML Schema Part 2: Datatypes Second Edition", + "status": "current", + "type": "string", + "pattern": [ + "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[\\+\\-]\\d{2}:\\d{2})" + ] + }, + "iskey": false + }, + "$@in-rpcs": { + "eltype": "leaf", + "description": "Number of correct messages received.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@in-bad-rpcs": { + "eltype": "leaf", + "description": "Number of messages received when an message was expected,\nthat were not correct messages. This includes XML parse\nerrors and errors on the rpc layer.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@out-rpc-errors": { + "eltype": "leaf", + "description": "Number of messages sent that contained an\n element.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@out-notifications": { + "eltype": "leaf", + "description": "Number of messages sent.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + } + } + ], + "$@session": { + "eltype": "list", + "description": "All NETCONF sessions managed by the NETCONF server\nMUST be reported in this list.", + "config": false, + "status": "current", + "mandatory": false, + "keys": [ + "session-id" + ] + } + }, + "schemas": { + "schema": [ + { + "identifier": "netopeer-cfgnetopeer", + "version": "2015-05-19", + "format": "yin", + "namespace": "urn:cesnet:tmc:netopeer:1.0", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "netopeer-cfgnetopeer", + "version": "2015-05-19", + "format": "yang", + "namespace": "urn:cesnet:tmc:netopeer:1.0", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-server", + "version": "2014-01-24", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-server", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-server", + "version": "2014-01-24", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-server", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-x509-cert-to-name", + "version": "2013-03-26", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-x509-cert-to-name", + "version": "2013-03-26", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-acm", + "version": "2012-02-22", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-acm", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-acm", + "version": "2012-02-22", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-acm", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-with-defaults", + "version": "2010-06-09", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-with-defaults", + "version": "2010-06-09", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "notifications", + "version": "2008-07-14", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:netconf:notification:1.0", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "notifications", + "version": "2008-07-14", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:netconf:notification:1.0", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "nc-notifications", + "version": "2008-07-14", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:netmod:notification", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "nc-notifications", + "version": "2008-07-14", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:netmod:notification", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-notifications", + "version": "2012-02-06", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-notifications", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-notifications", + "version": "2012-02-06", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-notifications", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-monitoring", + "version": "2010-10-04", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf-monitoring", + "version": "2010-10-04", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf", + "version": "2011-03-08", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:netconf:base:1.0", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-netconf", + "version": "2011-03-08", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:netconf:base:1.0", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-yang-types", + "version": "2013-07-15", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-yang-types", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-yang-types", + "version": "2013-07-15", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-yang-types", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-inet-types", + "version": "2013-07-15", + "format": "yin", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + }, + { + "identifier": "ietf-inet-types", + "version": "2013-07-15", + "format": "yang", + "namespace": "urn:ietf:params:xml:ns:yang:ietf-inet-types", + "location": [ + "NETCONF" + ], + "$@identifier": { + "eltype": "leaf", + "description": "Identifier to uniquely reference the schema. The\nidentifier is used in the operation and may\nbe used for other purposes such as file retrieval.\n\nFor modeling languages that support or require a data\nmodel name (e.g., YANG module name) the identifier MUST\nmatch that name. For YANG data models, the identifier is\nthe name of the module or submodule. In other cases, an\nidentifier such as a filename MAY be used instead.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@version": { + "eltype": "leaf", + "description": "Version of the schema supported. Multiple versions MAY be\nsupported simultaneously by a NETCONF server. Each\nversion MUST be reported individually in the schema list,\ni.e., with same identifier, possibly different location,\nbut different version.\n\nFor YANG data models, version is the value of the most\nrecent YANG 'revision' statement in the module or\nsubmodule, or the empty string if no 'revision' statement\nis present.", + "config": false, + "status": "current", + "mandatory": false, + "type": "string", + "iskey": true + }, + "$@format": { + "eltype": "leaf", + "description": "The data modeling language the schema is written\nin (currently xsd, yang, yin, rng, or rnc).\nFor YANG data models, 'yang' format MUST be supported and\n'yin' format MAY also be provided.", + "config": false, + "status": "current", + "mandatory": false, + "type": "identityref", + "identityval": [ + "schema-format", + "xsd", + "yang", + "yin", + "rng", + "rnc" + ], + "iskey": true + }, + "$@namespace": { + "eltype": "leaf", + "description": "The XML namespace defined by the data model.\n\nFor YANG data models, this is the module's namespace.\nIf the list entry describes a submodule, this field\ncontains the namespace of the module to which the\nsubmodule belongs.", + "config": false, + "status": "current", + "mandatory": true, + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + }, + "iskey": false + }, + "$@location": { + "eltype": "leaf-list", + "description": "One or more locations from which the schema can be\nretrieved. This list SHOULD contain at least one\nentry per schema.\n\nA schema entry may be located on a remote file system\n(e.g., reference to file system for ftp retrieval) or\nretrieved directly from a server supporting the\n operation (denoted by the value 'NETCONF').", + "config": false, + "status": "current", + "mandatory": false, + "type": "union", + "types": [ + { + "type": "enumeration", + "enumval": [ + "NETCONF" + ] + }, + { + "type": "ietf-inet-types:uri", + "typedef": { + "description": "The uri type represents a Uniform Resource Identifier\n(URI) as defined by STD 66.\n\nObjects using the uri type MUST be in US-ASCII encoding,\nand MUST be normalized as described by RFC 3986 Sections\n6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary\npercent-encoding is removed, and all case-insensitive\ncharacters are set to lowercase except for hexadecimal\ndigits, which are normalized to uppercase as described in\nSection 6.2.2.1.\n\nThe purpose of this normalization is to help provide\nunique URIs. Note that this normalization is not\nsufficient to provide uniqueness. Two URIs that are\ntextually distinct after this normalization may still be\nequivalent.\n\nObjects using the uri type may restrict the schemes that\nthey permit. For example, 'data:' and 'urn:' schemes\nmight not be appropriate.\n\nA zero-length URI is not a valid URI. This can be used to\nexpress 'URI absent' where required.\n\nIn the value set and its semantics, this type is equivalent\nto the Uri SMIv2 textual convention defined in RFC 5017.", + "reference": "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax\nRFC 3305: Report from the Joint W3C\/IETF URI Planning Interest\n Group: Uniform Resource Identifiers (URIs), URLs,\n and Uniform Resource Names (URNs): Clarifications\n and Recommendations\nRFC 5017: MIB Textual Conventions for Uniform Resource\n Identifiers (URIs)", + "status": "current", + "type": "string" + } + } + ] + } + } + ], + "$@schema": { + "eltype": "list", + "description": "List of data model schemas supported by the server.", + "config": false, + "status": "current", + "mandatory": false, + "keys": [ + "identifier", + "version", + "format" + ] + } + }, + "statistics": { + "netconf-start-time": "2015-11-23T08:31:36Z", + "in-bad-hellos": 0, + "in-sessions": 8, + "dropped-sessions": 6, + "in-rpcs": 105, + "in-bad-rpcs": 6, + "out-rpc-errors": 0, + "out-notifications": 0, + "$@netconf-start-time": { + "eltype": "leaf", + "description": "Date and time at which the management subsystem was\nstarted.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:date-and-time", + "typedef": { + "description": "The date-and-time type is a profile of the ISO 8601\nstandard for representation of dates and times using the\nGregorian calendar. The profile is defined by the\ndate-time production in Section 5.6 of RFC 3339.\n\nThe date-and-time type is compatible with the dateTime XML\nschema type with the following notable exceptions:\n\n(a) The date-and-time type does not allow negative years.\n\n(b) The date-and-time time-offset -00:00 indicates an unknown\n time zone (see RFC 3339) while -00:00 and +00:00 and Z\n all represent the same time zone in dateTime.\n\n(c) The canonical format (see below) of data-and-time values\n differs from the canonical format used by the dateTime XML\n schema type, which requires all times to be in UTC using\n the time-offset 'Z'.\n\nThis type is not equivalent to the DateAndTime textual\nconvention of the SMIv2 since RFC 3339 uses a different\nseparator between full-date and full-time and provides\nhigher resolution of time-secfrac.\n\nThe canonical format for date-and-time values with a known time\nzone uses a numeric time zone offset that is calculated using\nthe device's configured known offset to UTC time. A change of\nthe device's offset to UTC time will cause date-and-time values\nto change accordingly. Such changes might happen periodically\nin case a server follows automatically daylight saving time\n(DST) time zone offset changes. The canonical format for\ndate-and-time values with an unknown time zone (usually\nreferring to the notion of local time) uses the time-offset\n-00:00.", + "reference": "RFC 3339: Date and Time on the Internet: Timestamps\nRFC 2579: Textual Conventions for SMIv2\nXSD-TYPES: XML Schema Part 2: Datatypes Second Edition", + "status": "current", + "type": "string", + "pattern": [ + "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[\\+\\-]\\d{2}:\\d{2})" + ] + }, + "iskey": false + }, + "$@in-bad-hellos": { + "eltype": "leaf", + "description": "Number of sessions silently dropped because an\ninvalid message was received. This includes \nmessages with a 'session-id' attribute, bad namespace, and\nbad capability declarations.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@in-sessions": { + "eltype": "leaf", + "description": "Number of sessions started. This counter is incremented\nwhen a message with a is sent.\n\n'in-sessions' - 'in-bad-hellos' =\n 'number of correctly started netconf sessions'", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@dropped-sessions": { + "eltype": "leaf", + "description": "Number of sessions that were abnormally terminated, e.g.,\ndue to idle timeout or transport close. This counter is not\nincremented when a session is properly closed by a\n operation, or killed by a \noperation.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@in-rpcs": { + "eltype": "leaf", + "description": "Number of correct messages received.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@in-bad-rpcs": { + "eltype": "leaf", + "description": "Number of messages received when an message was expected,\nthat were not correct messages. This includes XML parse\nerrors and errors on the rpc layer.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@out-rpc-errors": { + "eltype": "leaf", + "description": "Number of messages sent that contained an\n element.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@out-notifications": { + "eltype": "leaf", + "description": "Number of messages sent.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + } + }, + "$@capabilities": { + "eltype": "container", + "description": "Contains the list of NETCONF capabilities supported by the\nserver.", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "capability" + ] + }, + "$@datastores": { + "eltype": "container", + "description": "Contains the list of NETCONF configuration datastores.", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "datastore" + ] + }, + "$@sessions": { + "eltype": "container", + "description": "The sessions container includes session-specific data for\nNETCONF management sessions. The session list MUST include\nall currently active NETCONF sessions.", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "session" + ] + }, + "$@schemas": { + "eltype": "container", + "description": "Contains the list of data model schemas supported by the\nserver.", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "schema" + ] + }, + "$@statistics": { + "eltype": "container", + "description": "Statistical data pertaining to the NETCONF server.", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "netconf-start-time", + "in-bad-hellos", + "in-sessions", + "dropped-sessions" + ] + } + }, + "nc-notifications:netconf": { + "streams": { + "stream": [ + { + "name": "NETCONF", + "description": "NETCONF Base Notifications", + "replaySupport": true, + "replayLogCreationTime": "2014-09-22T09:25:33Z", + "$@name": { + "eltype": "leaf", + "description": "The name of the event stream. If this is the default\nNETCONF stream, this must have the value 'NETCONF'.", + "config": false, + "status": "current", + "mandatory": false, + "type": "notifications:streamNameType", + "typedef": { + "description": "The name of an event stream.", + "status": "current", + "type": "string" + }, + "iskey": true + }, + "$@description": { + "eltype": "leaf", + "description": "A description of the event stream, including such\ninformation as the type of events that are sent over\nthis stream.", + "config": false, + "status": "current", + "mandatory": true, + "type": "string", + "iskey": false + }, + "$@replaySupport": { + "eltype": "leaf", + "description": "A description of the event stream, including such\ninformation as the type of events that are sent over\nthis stream.", + "config": false, + "status": "current", + "mandatory": true, + "type": "bool", + "iskey": false + }, + "$@replayLogCreationTime": { + "eltype": "leaf", + "description": "The timestamp of the creation of the log used to support\nthe replay function on this stream. Note that this might\nbe earlier then the earliest available notification in\nthe log. This object is updated if the log resets for \nsome reason. This object MUST be present if replay is\nsupported.", + "config": false, + "status": "current", + "mandatory": false, + "type": "ietf-yang-types:date-and-time", + "typedef": { + "description": "The date-and-time type is a profile of the ISO 8601\nstandard for representation of dates and times using the\nGregorian calendar. The profile is defined by the\ndate-time production in Section 5.6 of RFC 3339.\n\nThe date-and-time type is compatible with the dateTime XML\nschema type with the following notable exceptions:\n\n(a) The date-and-time type does not allow negative years.\n\n(b) The date-and-time time-offset -00:00 indicates an unknown\n time zone (see RFC 3339) while -00:00 and +00:00 and Z\n all represent the same time zone in dateTime.\n\n(c) The canonical format (see below) of data-and-time values\n differs from the canonical format used by the dateTime XML\n schema type, which requires all times to be in UTC using\n the time-offset 'Z'.\n\nThis type is not equivalent to the DateAndTime textual\nconvention of the SMIv2 since RFC 3339 uses a different\nseparator between full-date and full-time and provides\nhigher resolution of time-secfrac.\n\nThe canonical format for date-and-time values with a known time\nzone uses a numeric time zone offset that is calculated using\nthe device's configured known offset to UTC time. A change of\nthe device's offset to UTC time will cause date-and-time values\nto change accordingly. Such changes might happen periodically\nin case a server follows automatically daylight saving time\n(DST) time zone offset changes. The canonical format for\ndate-and-time values with an unknown time zone (usually\nreferring to the notion of local time) uses the time-offset\n-00:00.", + "reference": "RFC 3339: Date and Time on the Internet: Timestamps\nRFC 2579: Textual Conventions for SMIv2\nXSD-TYPES: XML Schema Part 2: Datatypes Second Edition", + "status": "current", + "type": "string", + "pattern": [ + "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[\\+\\-]\\d{2}:\\d{2})" + ] + }, + "iskey": false + } + } + ], + "$@stream": { + "eltype": "list", + "description": "Stream name, description and other information.", + "config": false, + "status": "current", + "mandatory": false, + "min-elements": 1, + "keys": [ + "name" + ] + } + }, + "$@streams": { + "eltype": "container", + "description": "The list of event streams supported by the system. When\na query is issued, the returned set of streams is \ndetermined based on user privileges.", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "stream" + ] + } + }, + "ietf-netconf-acm:nacm": { + "rule-list": [ + { + "name": "almighty", + "group": [ + "almighty" + ], + "rule": [ + { + "name": "almighty", + "module-name": "*", + "access-operations": "*", + "action": "permit", + "$@name": { + "eltype": "leaf", + "description": "Arbitrary name assigned to the rule.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "type": "string", + "length": "1..max", + "iskey": true + }, + "$@module-name": { + "eltype": "leaf", + "description": "Name of the module associated with this rule.\n\nThis leaf matches if it has the value '*' or if the\nobject being accessed is defined in the module with the\nspecified module name.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "type": "union", + "types": [ + { + "type": "matchall-string-type", + "typedef": { + "description": "The string containing a single asterisk '*' is used\nto conceptually represent all possible values\nfor the particular leaf using this data type.", + "status": "current", + "type": "string", + "pattern": [ + "\\*" + ] + } + }, + { + "type": "string" + } + ], + "default": "*", + "iskey": false + }, + "$@access-operations": { + "eltype": "leaf", + "description": "Access operations associated with this rule.\n\nThis leaf matches if it has the value '*' or if the\nbit corresponding to the requested operation is set.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "type": "union", + "types": [ + { + "type": "matchall-string-type", + "typedef": { + "description": "The string containing a single asterisk '*' is used\nto conceptually represent all possible values\nfor the particular leaf using this data type.", + "status": "current", + "type": "string", + "pattern": [ + "\\*" + ] + } + }, + { + "type": "access-operations-type", + "typedef": { + "description": "NETCONF Access Operation.", + "status": "current", + "type": "bits", + "bits": [ + { + "name": "create", + "position": 0 + }, + { + "name": "read", + "position": 1 + }, + { + "name": "update", + "position": 2 + }, + { + "name": "delete", + "position": 3 + }, + { + "name": "exec", + "position": 4 + } + ] + } + } + ], + "default": "*", + "iskey": false + }, + "$@action": { + "eltype": "leaf", + "description": "The access control action associated with the\nrule. If a rule is determined to match a\nparticular request, then this object is used\nto determine whether to permit or deny the\nrequest.", + "config": true, + "status": "current", + "mandatory": true, + "ext": "default-deny-all", + "type": "action-type", + "typedef": { + "description": "Action taken by the server when a particular\nrule matches.", + "status": "current", + "type": "enumeration", + "enumval": [ + "permit", + "deny" + ] + }, + "iskey": false + } + } + ], + "$@name": { + "eltype": "leaf", + "description": "Arbitrary name assigned to the rule-list.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "type": "string", + "length": "1..max", + "iskey": true + }, + "$@group": { + "eltype": "leaf-list", + "description": "List of administrative groups that will be\nassigned the associated access rights\ndefined by the 'rule' list.\n\nThe string '*' indicates that all groups apply to the\nentry.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "type": "union", + "types": [ + { + "type": "matchall-string-type", + "typedef": { + "description": "The string containing a single asterisk '*' is used\nto conceptually represent all possible values\nfor the particular leaf using this data type.", + "status": "current", + "type": "string", + "pattern": [ + "\\*" + ] + } + }, + { + "type": "group-name-type", + "typedef": { + "description": "Name of administrative group to which\nusers can be assigned.", + "status": "current", + "type": "string", + "length": "1..max", + "pattern": [ + "[^\\*].*" + ] + } + } + ] + }, + "$@rule": { + "eltype": "list", + "description": "One access control rule.\n\nRules are processed in user-defined order until a match is\nfound. A rule matches if 'module-name', 'rule-type', and\n'access-operations' match the request. If a rule\nmatches, the 'action' leaf determines if access is granted\nor not.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "keys": [ + "name" + ] + } + } + ], + "groups": { + "group": [ + { + "name": "almighty", + "user-name": [ + "vasko" + ], + "$@name": { + "eltype": "leaf", + "description": "Group name associated with this entry.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "type": "group-name-type", + "typedef": { + "description": "Name of administrative group to which\nusers can be assigned.", + "status": "current", + "type": "string", + "length": "1..max", + "pattern": [ + "[^\\*].*" + ] + }, + "iskey": true + }, + "$@user-name": { + "eltype": "leaf-list", + "description": "Each entry identifies the username of\na member of the group associated with\nthis entry.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "type": "user-name-type", + "typedef": { + "description": "General Purpose Username string.", + "status": "current", + "type": "string", + "length": "1..max" + } + } + } + ], + "$@group": { + "eltype": "list", + "description": "One NACM Group Entry. This list will only contain\nconfigured entries, not any entries learned from\nany transport protocols.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "keys": [ + "name" + ] + } + }, + "denied-operations": 0, + "denied-data-writes": 0, + "denied-notifications": 0, + "$@rule-list": { + "eltype": "list", + "description": "An ordered collection of access control rules.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "keys": [ + "name" + ] + }, + "$@groups": { + "eltype": "container", + "description": "NETCONF Access Control Groups.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "children": [ + "group" + ] + }, + "$@denied-operations": { + "eltype": "leaf", + "description": "Number of times since the server last restarted that a\nprotocol operation request was denied.", + "config": false, + "status": "current", + "mandatory": true, + "ext": "default-deny-all", + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@denied-data-writes": { + "eltype": "leaf", + "description": "Number of times since the server last restarted that a\nprotocol operation request to alter\na configuration datastore was denied.", + "config": false, + "status": "current", + "mandatory": true, + "ext": "default-deny-all", + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + }, + "$@denied-notifications": { + "eltype": "leaf", + "description": "Number of times since the server last restarted that\na notification was dropped for a subscription because\naccess to the event type was denied.", + "config": false, + "status": "current", + "mandatory": true, + "ext": "default-deny-all", + "type": "ietf-yang-types:zero-based-counter32", + "typedef": { + "description": "The zero-based-counter32 type represents a counter32\nthat has the defined 'initial' value zero.\n\nA schema node of this type will be set to zero (0) on creation\nand will thereafter increase monotonically until it reaches\na maximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nProvided that an application discovers a new schema node\nof this type within the minimum time to wrap, it can use the\n'initial' value as a delta. It is important for a management\nstation to be aware of this minimum time and the actual time\nbetween polls, and to discard data if the actual time is too\nlong or there is no defined minimum time.\n\nIn the value set and its semantics, this type is equivalent\nto the ZeroBasedCounter32 textual convention of the SMIv2.", + "reference": "RFC 4502: Remote Network Monitoring Management Information\n Base Version 2", + "status": "current", + "type": "counter32", + "typedef": { + "description": "The counter32 type represents a non-negative integer\nthat monotonically increases until it reaches a\nmaximum value of 2^32-1 (4294967295 decimal), when it\nwraps around and starts increasing again from zero.\n\nCounters have no defined 'initial' value, and thus, a\nsingle value of a counter has (in general) no information\ncontent. Discontinuities in the monotonically increasing\nvalue normally occur at re-initialization of the\nmanagement system, and at other times as specified in the\ndescription of a schema node using this type. If such\nother times can occur, for example, the creation of\na schema node of type counter32 at times other than\nre-initialization, then a corresponding schema node\nshould be defined, with an appropriate type, to indicate\nthe last discontinuity.\n\nThe counter32 type should not be used for configuration\nschema nodes. A default statement SHOULD NOT be used in\ncombination with the type counter32.\n\nIn the value set and its semantics, this type is equivalent\nto the Counter32 type of the SMIv2.", + "reference": "RFC 2578: Structure of Management Information Version 2\n (SMIv2)", + "status": "current", + "type": "uint32" + }, + "default": "0" + }, + "iskey": false + } + }, + "$@netopeer-cfgnetopeer:netopeer": { + "eltype": "container", + "config": true, + "status": "current", + "mandatory": false, + "children": [ + "hello-timeout", + "idle-timeout", + "max-sessions", + "response-time", + "ssh", + "tls", + "modules" + ] + }, + "$@ietf-netconf-monitoring:netconf-state": { + "eltype": "container", + "description": "The netconf-state container is the root of the monitoring\ndata model.", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "capabilities", + "datastores", + "schemas", + "sessions", + "statistics" + ] + }, + "$@nc-notifications:netconf": { + "eltype": "container", + "description": "Top-level element in the notification namespace", + "config": false, + "status": "current", + "mandatory": false, + "children": [ + "streams" + ] + }, + "$@ietf-netconf-acm:nacm": { + "eltype": "container", + "description": "Parameters for NETCONF Access Control Model.", + "config": true, + "status": "current", + "mandatory": false, + "ext": "default-deny-all", + "children": [ + "enable-nacm", + "read-default", + "write-default", + "exec-default", + "enable-external-groups", + "denied-operations", + "denied-data-writes", + "denied-notifications", + "groups", + "rule-list" + ] + } +} diff --git a/index.html b/index.html index e946054c..bd9dcad7 100644 --- a/index.html +++ b/index.html @@ -9,6 +9,8 @@ + + @@ -22,6 +24,8 @@

      NetopeerGUI - JSON test

      + +
      diff --git a/js/JSONedit.js b/js/JSONedit.js index b3a42721..ff3c15ae 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -1,30 +1,75 @@ +var storage = Rhaboo.perishable("Some unique name"); +var historyIndex = 0, + historyUndo = 0; + var app = angular.module('NetopeerGUIApp', ['JSONedit']) -.controller('ConfigurationController', function($scope, $filter, $http, $window) { + .controller('ConfigurationController', function ($scope, $filter, $http, $window, $timeout) { + + storage.write('revisions', []); + storage.erase('revisions'); + storage.write('revisions', []); + + $scope.hasUndo = function() { + return (historyIndex - historyUndo - 1) <= 0; + }; + $scope.hasRedo = function() { + return (historyIndex - historyUndo) >= storage.revisions.length; + }; + var isUndo = false, + isRedo = false; + + $http.get('data/real.json').success(function (data) { + $scope.jsonData = data; + }); + + $scope.$watch('jsonData', function (newValue, oldValue) { + $timeout(function() { + $scope.jsonString = JSON.stringify(newValue); + }, 100); + if ( !isUndo && !isRedo && newValue !== oldValue ) { + historyIndex = historyIndex - historyUndo; + historyUndo = 0; - $http.get('data/get.json').success(function(data) { - $scope.jsonData = data; - }); + // prevent the future + storage.revisions.slice(0, historyIndex + 1); + storage.revisions.push(JSON.stringify(newValue)); + + historyIndex++; + } + isUndo = false; + isRedo = false; + }, true); + $scope.$watch('jsonString', function (json) { + try { + $scope.jsonData = JSON.parse(json); + $scope.wellFormed = true; + } catch (e) { + $scope.wellFormed = false; + } + }, true); + + $scope.download = function (jsonData) { + //var result = JSON.stringify(jsonData); + //result = result.replace(/xmlns:all/g, 'xmlns'); + //result = result.replace(/\s[^(xmlns)]\w*=\"[a-zA-Z0-9\s\d\.\(\)\\\/\-,\'\|:]*\"/gim, ''); // remove all attributes + //var cleanJson = JSON.stringify(jsonData); + var cleanJson = $filter('json')(jsonData); + $window.open("data:application/json;charset=utf-8," + encodeURIComponent(cleanJson)); + }; + + $scope.undo = function() { + var json = storage.revisions[historyIndex - historyUndo - 2]; + isUndo = true; + $scope.jsonData = JSON.parse(json); + historyUndo++; + }; - $scope.$watch('jsonData', function (json) { - $scope.jsonString = JSON.stringify(json); - }, true); - $scope.$watch('jsonString', function (json) { - try { + $scope.redo = function() { + var json = storage.revisions[historyIndex - historyUndo]; + isRedo = true; $scope.jsonData = JSON.parse(json); - $scope.wellFormed = true; - } catch (e) { - $scope.wellFormed = false; - } - }, true); - - $scope.download = function(jsonData) { - //var result = JSON.stringify(jsonData); - //result = result.replace(/xmlns:all/g, 'xmlns'); - //result = result.replace(/\s[^(xmlns)]\w*=\"[a-zA-Z0-9\s\d\.\(\)\\\/\-,\'\|:]*\"/gim, ''); // remove all attributes - //var cleanJson = JSON.stringify(jsonData); - var cleanJson = $filter('json')(jsonData); - $window.open("data:application/json;charset=utf-8," + encodeURIComponent(cleanJson)); - }; -} + historyUndo--; + }; + } ); \ No newline at end of file diff --git a/js/directives.js b/js/directives.js deleted file mode 100644 index f96dc02f..00000000 --- a/js/directives.js +++ /dev/null @@ -1,260 +0,0 @@ -'use strict'; - -angular.module('JSONedit', ['ui.sortable']) -.directive('ngModelOnblur', function() { - // override the default input to update on blur - // from http://jsfiddle.net/cn8VF/ - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, elm, attr, ngModelCtrl) { - if (attr.type === 'radio' || attr.type === 'checkbox') return; - - elm.unbind('input').unbind('keydown').unbind('change'); - elm.bind('blur', function() { - scope.$apply(function() { - ngModelCtrl.$setViewValue(elm.val()); - }); - }); - } - }; -}) -.directive('json', ["$compile", function($compile) { - return { - restrict: 'E', - scope: { - child: '=', - type: '@', - defaultCollapsed: '=' - }, - link: function(scope, element, attributes) { - var stringName = "Text"; - var objectName = "Object"; - var arrayName = "Array"; - var refName = "Reference"; - var boolName = "Boolean" - - scope.valueTypes = [stringName, objectName, arrayName, refName, boolName]; - scope.sortableOptions = { - axis: 'y' - }; - if (scope.$parent.defaultCollapsed === undefined) { - scope.collapsed = false; - } else { - scope.collapsed = scope.defaultCollapsed; - } - if (scope.collapsed) { - scope.chevron = "glyphicon-chevron-right"; - } else { - scope.chevron = "glyphicon-chevron-down"; - } - - - ////// - // Helper functions - ////// - - var getType = function(obj) { - var type = Object.prototype.toString.call(obj); - if (type === "[object Object]") { - return "Object"; - } else if(type === "[object Array]"){ - return "Array"; - } else if(type === "[object Boolean]"){ - return "Boolean"; - } else if(type === "[object Number]"){ - return "Number"; - } else { - return "Literal"; - } - }; - var isNumber = function(n) { - return !isNaN(parseFloat(n)) && isFinite(n); - }; - scope.getType = function(obj) { - return getType(obj); - }; - scope.toggleCollapse = function() { - if (scope.collapsed) { - scope.collapsed = false; - scope.chevron = "glyphicon-chevron-down"; - } else { - scope.collapsed = true; - scope.chevron = "glyphicon-chevron-right"; - } - }; - scope.moveKey = function(obj, key, newkey) { - //moves key to newkey in obj - if (key !== newkey) { - obj[newkey] = obj[key]; - delete obj[key]; - } - }; - scope.deleteKey = function(obj, key) { - if (getType(obj) == "Object") { - if( confirm('Delete "'+key+'" and all it contains?') ) { - delete obj[key]; - } - } else if (getType(obj) == "Array") { - if( confirm('Delete "'+obj[key]+'"?') ) { - obj.splice(key, 1); - } - } else { - console.error("object to delete from was " + obj); - } - }; - scope.addItem = function(obj) { - if (getType(obj) == "Object") { - // check input for key - if (scope.keyName == undefined || scope.keyName.length == 0){ - alert("Please fill in a name"); - } else if (scope.keyName.indexOf("$") == 0){ - alert("The name may not start with $ (the dollar sign)"); - } else if (scope.keyName.indexOf("_") == 0){ - alert("The name may not start with _ (the underscore)"); - } else { - if (obj[scope.keyName]) { - if( !confirm('An item with the name "'+scope.keyName - +'" exists already. Do you really want to replace it?') ) { - return; - } - } - // add item to object - switch(scope.valueType) { - case stringName: obj[scope.keyName] = scope.valueName ? scope.possibleNumber(scope.valueName) : ""; - break; - case objectName: obj[scope.keyName] = {}; - break; - case arrayName: obj[scope.keyName] = []; - break; - case refName: obj[scope.keyName] = {"Reference!!!!": "todo"}; - break; - case boolName: obj[scope.keyName] = false; - break; - } - //clean-up - scope.keyName = ""; - scope.valueName = ""; - scope.showAddKey = false; - } - } else if (getType(obj) == "Array") { - // add item to array - switch(scope.valueType) { - case stringName: obj.push(scope.valueName ? scope.valueName : ""); - break; - case objectName: obj.push({}); - break; - case arrayName: obj.push([]); - break; - case boolName: obj.push(false); - break; - case refName: obj.push({"Reference!!!!": "todo"}); - break; - } - scope.valueName = ""; - scope.showAddKey = false; - } else { - console.error("object to add to was " + obj); - } - }; - scope.possibleNumber = function(val) { - return isNumber(val) ? parseFloat(val) : val; - }; - - ////// - // Template Generation - ////// - - // Note: - // sometimes having a different ng-model and then saving it on ng-change - // into the object or array is necessary for all updates to work - - // recursion - var switchTemplate = - '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + '' - + ''; - - // display either "plus button" or "key-value inputs" - var addItemTemplate = - '
      ' - + ''; - if (scope.type == "object"){ - // input key - addItemTemplate += ' '; - } - addItemTemplate += - // value type dropdown - '' - // input value - + ' : ' - // Add button - + ' ' - + '' - + '' - + '' - // plus button - + '' - + '' - + '
      '; - - // start template - if (scope.type == "object"){ - var template = '' - + ''+objectName+'' - + '
      ' - // repeat - + '' - // object key - + '' - + '' - // delete button - + '' - + '' - // object value - + '' + switchTemplate + '' - + '' - // repeat end - + addItemTemplate - + '
      '; - } else if (scope.type == "array") { - var template = '' - + ''+arrayName+'' - + '
      ' - + '
        ' - // repeat - + '
      1. ' - // delete button - + '' - + '' - + '' + switchTemplate + '' - + '
      2. ' - // repeat end - + '
      ' - + addItemTemplate - + '
      '; - } else { - console.error("scope.type was "+ scope.type); - } - - var newElement = angular.element(template); - $compile(newElement)(scope); - element.replaceWith ( newElement ); - } - }; -}]); diff --git a/js/directives2.js b/js/directives2.js index 364f0352..f7a7d0f2 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -10,7 +10,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { // override the default input to update on blur // from http://jsfiddle.net/cn8VF/ return { - restrict: 'A', + restrict: 'EAC', require: 'ngModel', link: function(scope, elm, attr, ngModelCtrl) { if (attr.type === 'radio' || attr.type === 'checkbox') return; @@ -38,7 +38,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { if (typeof type === 'undefined') { type = $scope.type; } - return 'types/'+type+'.html'; + return 'templates/types/'+type+'.html'; }; }, link: function(scope, element, attributes) { @@ -79,7 +79,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { return type === "inet:uri"; }; - var getType = function(obj) { + var getType = function(key, obj, parent) { + var schema = getSchemaFromKey(key, parent); // get custom yang datatype var type = Object.prototype.toString.call(obj); @@ -89,8 +90,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { return arrayName; } - if (typeof obj['@type'] !== "undefined") { - type = obj['@type']; + if (schema && typeof schema['type'] !== "undefined") { + type = schema['type']; } if(type === "Boolean" || type === "[object Boolean]"){ @@ -105,13 +106,26 @@ NetopeerGUI.directive('ngModelOnblur', function() { var isNumber = function(n) { return !isNaN(parseFloat(n)) && isFinite(n); }; - scope.getType = function(obj) { - return getType(obj); + scope.getType = function(key, obj, parent) { + return getType(key, obj, parent); }; - scope.editBarVisible = function(obj) { - if (typeof obj['@type'] !== "undefined") { - var type = obj['@type']; + var getSchemaFromKey = function(key, parent) { + if (typeof parent['$@'+key] === "undefined") { + return false; + } + return parent['$@'+key]; + }; + + scope.isConfig = function(key, parent) { + var schema = getSchemaFromKey(key, parent); + return (schema && typeof schema['config'] !== "undefined" && schema['config'] === true); + }; + + scope.editBarVisible = function(key, parent) { + var schema = getSchemaFromKey(key, parent); + if (schema && typeof schema['type'] !== "undefined") { + var type = schema['type']; return (type == "list" || type == "leaf-list" || type == "container"); } @@ -146,8 +160,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { console.error("object to delete from was " + obj); } }; - scope.addItem = function(obj) { - if (getType(obj) == "Object") { + scope.addItem = function(key, obj, parent) { + var type = getType(key, obj, parent); + if (type == "Object") { // check input for key if (scope.keyName == undefined || scope.keyName.length == 0){ alert("Please fill in a name"); @@ -180,7 +195,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.valueName = ""; scope.showAddKey = false; } - } else if (getType(obj) == "Array") { + } else if (type == "Array") { // add item to array switch(scope.valueType) { case stringName: obj.push(scope.valueName ? scope.valueName : ""); diff --git a/public/templates.js b/public/templates.js index 7d55270d..1ac789ca 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ -angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n\n \n\n : \n\n \n \n \n \n \n \n
      "); -$templateCache.put("directives/switchItem.html","\n \n \n \n \n \n \n \n \n \n \n \n"); +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n\n \n\n : \n\n \n \n \n \n \n \n
      "); +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
      \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); $templateCache.put("types/object.html","\n
      \n \n \n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index b2fe3493..e292e02d 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -1,13 +1,13 @@
      - - + - : + : - \n \n \n \n \n \n
      "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
      \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); -$templateCache.put("types/object.html","\n
      \n \n \n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file +$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file diff --git a/templates/types/object.html b/templates/types/object.html index b16ccfbc..291d119a 100644 --- a/templates/types/object.html +++ b/templates/types/object.html @@ -2,7 +2,8 @@
      - + {{ key }} + From c61d75e6386b8a2df95dae613be8e2b8db9a441c Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 25 Nov 2015 09:55:32 +0100 Subject: [PATCH 010/113] zakladni prevedeni stylu do compassu --- .gitignore | 1 + css/config.rb | 25 ++++ css/sass/ie.scss | 5 + css/sass/print.scss | 3 + css/sass/screen.scss | 95 ++++++++++++++++ css/styles.css | 175 ---------------------------- css/stylesheets/ie.css | 5 + css/stylesheets/print.css | 3 + css/stylesheets/screen.css | 228 +++++++++++++++++++++++++++++++++++++ index.html | 2 +- 10 files changed, 366 insertions(+), 176 deletions(-) create mode 100644 css/config.rb create mode 100644 css/sass/ie.scss create mode 100644 css/sass/print.scss create mode 100644 css/sass/screen.scss delete mode 100644 css/styles.css create mode 100644 css/stylesheets/ie.css create mode 100644 css/stylesheets/print.css create mode 100644 css/stylesheets/screen.css diff --git a/.gitignore b/.gitignore index 0da92878..96e08a88 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ bower_components/* node_modules .idea +css/.sass-cache diff --git a/css/config.rb b/css/config.rb new file mode 100644 index 00000000..53e2d41d --- /dev/null +++ b/css/config.rb @@ -0,0 +1,25 @@ +require 'compass/import-once/activate' +# Require any additional compass plugins here. + +# Set this to the root of your project when deployed: +http_path = "/" +css_dir = "stylesheets" +sass_dir = "sass" +images_dir = "images" +javascripts_dir = "javascripts" + +# You can select your preferred output style here (can be overridden via the command line): +# output_style = :expanded or :nested or :compact or :compressed + +# To enable relative paths to assets via compass helper functions. Uncomment: +# relative_assets = true + +# To disable debugging comments that display the original location of your selectors. Uncomment: +# line_comments = false + + +# If you prefer the indented syntax, you might want to regenerate this +# project again passing --syntax sass, or you can uncomment this: +# preferred_syntax = :sass +# and then run: +# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass diff --git a/css/sass/ie.scss b/css/sass/ie.scss new file mode 100644 index 00000000..5cd5b6c5 --- /dev/null +++ b/css/sass/ie.scss @@ -0,0 +1,5 @@ +/* Welcome to Compass. Use this file to write IE specific override styles. + * Import this file using the following HTML or equivalent: + * */ diff --git a/css/sass/print.scss b/css/sass/print.scss new file mode 100644 index 00000000..b0e9e456 --- /dev/null +++ b/css/sass/print.scss @@ -0,0 +1,3 @@ +/* Welcome to Compass. Use this file to define print styles. + * Import this file using the following HTML or equivalent: + * */ diff --git a/css/sass/screen.scss b/css/sass/screen.scss new file mode 100644 index 00000000..e7703978 --- /dev/null +++ b/css/sass/screen.scss @@ -0,0 +1,95 @@ +//@import "compass/reset"; + +#mainView { margin: 30px auto; width: 95%; } + +#jsonTextarea { width: 700px; height: 300px; } + +.red { color: red; } + +/* JSON VIEW */ + +/* striped background */ + +.jsonView { padding: 30px 0 0 5px; + select.form-control { margin: 0; padding: 0; width: 100px; display: inline; height: 29px; padding-left: 5px; + } + input { height: 30px; margin: 0; padding: 0; + &.form-control { width: 100px; display: inline; height: 29px; padding-left: 5px; } + &[type="text"], &[type="number"] { margin: 0; border: 1px solid #ccc; background: none; } + &[type="checkbox"] { position: absolute; } + &.keyinput { font-weight: bold; } + + &[type="text"] { + &.addItemKeyInput, &.addItemValueInput { border: 1px solid #ccc; background: white; margin-left: 0; } + } + } + .addItemKeyInput { font-weight: bold; } + .glyphicon-menu-right, .glyphicon-menu-down { float: left; cursor: pointer; position: relative; top: -22px; right: 22px; margin-right: -15px; } + > json > .glyphicon-menu-down { display: none; } + .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; height: 30px; display: block; + i { display: block; } + } + .iconButton { float: right; margin-right: 10px; position: relative; top: 7px; z-index: 99999999999999; cursor: pointer; } + .jsonObjectKey { font-weight: bold; margin-right: 25px; } +} + +/* inputs */ + +/* chevrons */ + +/* add and delete */ + +/* basic layout */ + +.jsonContents { margin-left: 25px; } + +li .jsonContents { margin-left: 0px; } + +.jsonView { + .block { display: block; } + .jsonItemDesc { font-family: Georgia, serif; color: grey; font-style: italic; cursor: default; line-height: 30px; } + .objectDesc { cursor: default; } + > json > .jsonItemDesc { display: block; float: left; position: relative; bottom: 25px; height: 0; width: 0; } + ol.arrayOl { margin: 0; padding-left: 20px; } + li {clear: both;min-height: 30px; } + ol.arrayOl { + .glyphicon-menu-down, .glyphicon-menu-right { margin-left: -20px; } + .glyphicon-menu-down { top: 7px; } + .glyphicon-menu-right { top: -16px; } + > li > span > span > json > { + .glyphicon-menu-down, .glyphicon-menu-right { left: -40px; } + } + li { color: grey; font-style: italic; font-family: Georgia, serif; list-style-type: decimal; + input { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal; } + } + } + li { + select, button { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal;} + } + ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { color: black; } + li li { + list-style-type: lower-roman; + li { + list-style-type: upper-roman; + li { + list-style-type: lower-latin; + li { + list-style-type: upper-latin; + li { + list-style-type: lower-greek; + li { + list-style-type: decimal; + } + } + } + } + } + } +} + +/* first brace */ + +/* array numbering */ + +.sortable-placeholder { height: 20px; display: block; } + diff --git a/css/styles.css b/css/styles.css deleted file mode 100644 index e5e04e16..00000000 --- a/css/styles.css +++ /dev/null @@ -1,175 +0,0 @@ -#mainView { - margin: 30px auto; - width: 95%; -} -#jsonTextarea { - width: 700px; - height: 300px; -} -.red { - color: red; -} - - -/* JSON VIEW */ - -/* striped background */ -.jsonView { - padding: 30px 0 0 5px; -} -/* inputs */ -.jsonView select.form-control { - margin: 0; - padding: 0; -} -.jsonView select.form-control, .jsonView input.form-control { - width: 100px; - display: inline; - height: 29px; - padding-left: 5px; -} -.jsonView input[type="text"], .jsonView input[type="number"] { - margin: 0; - border: 1px solid #ccc; - background: none; -} -.jsonView input[type="checkbox"] { - position: absolute; -} -.jsonView input.keyinput { - font-weight: bold; -} -.jsonView input { - height: 30px; - margin: 0; - padding: 0; -} -.jsonView input[type="text"].addItemKeyInput, .jsonView input[type="text"].addItemValueInput { - border: 1px solid #ccc; - background: white; - margin-left: 0; -} -.jsonView .addItemKeyInput { - font-weight: bold; -} - -/* chevrons */ -.jsonView .glyphicon-menu-right, .jsonView .glyphicon-menu-down { - float: left; - cursor: pointer; - position: relative; - top: -22px; - right: 22px; - margin-right: -15px; -} -.jsonView > json > .glyphicon-menu-down { - display: none; -} -/* add and delete */ -.jsonView .addObjectItemBtn { - background-color: transparent; - border-color: transparent; - padding: 0; - border: 0; - height: 30px; - display: block; -} -.jsonView .addObjectItemBtn i { - display: block; -} -.jsonView .iconButton { - float: right; - margin-right: 10px; - position: relative; - top: 7px; - z-index: 99999999999999; - cursor: pointer; -} - -/* basic layout */ -.jsonView .jsonObjectKey { - font-weight: bold; margin-right: 25px; -} -.jsonContents { - margin-left: 25px; -} -li .jsonContents { margin-left: 0px; } -.jsonView .block { - display: block; -} -.jsonView .jsonItemDesc { - font-family: Georgia, serif; - color: grey; - font-style: italic; - cursor: default; - line-height: 30px -} -.jsonView .objectDesc { - cursor: default; -} -/* first brace */ -.jsonView > json > .jsonItemDesc { - display: block; - float: left; - position: relative; - bottom: 25px; - height: 0; - width: 0; -} - -/* array numbering */ -.jsonView ol.arrayOl { - margin: 0; - padding-left: 20px; -} -.jsonView li { clear: both; min-height: 30px; } -.jsonView ol.arrayOl .glyphicon-menu-down, .jsonView ol.arrayOl .glyphicon-menu-right { - margin-left: -20px; -} -.jsonView ol.arrayOl .glyphicon-menu-down { - top: 7px; -} -.jsonView ol.arrayOl .glyphicon-menu-right { - top: -16px; -} -.jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-down, -.jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-right { - left: -40px; -} -.jsonView ol.arrayOl li { - color: grey; - font-style: italic; - font-family: Georgia, serif; - list-style-type: decimal; -} -.jsonView ol.arrayOl li input, .jsonView li select, .jsonView li button { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-style: normal; -} -.jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { - color: black; -} - -.jsonView li li { - list-style-type: lower-roman; -} -.jsonView li li li { - list-style-type: upper-roman; -} -.jsonView li li li li { - list-style-type: lower-latin; -} -.jsonView li li li li li { - list-style-type: upper-latin; -} -.jsonView li li li li li li { - list-style-type: lower-greek; -} -.jsonView li li li li li li li { - list-style-type: decimal; -} -.sortable-placeholder { - height: 20px; - display: block; -} - diff --git a/css/stylesheets/ie.css b/css/stylesheets/ie.css new file mode 100644 index 00000000..5cd5b6c5 --- /dev/null +++ b/css/stylesheets/ie.css @@ -0,0 +1,5 @@ +/* Welcome to Compass. Use this file to write IE specific override styles. + * Import this file using the following HTML or equivalent: + * */ diff --git a/css/stylesheets/print.css b/css/stylesheets/print.css new file mode 100644 index 00000000..b0e9e456 --- /dev/null +++ b/css/stylesheets/print.css @@ -0,0 +1,3 @@ +/* Welcome to Compass. Use this file to define print styles. + * Import this file using the following HTML or equivalent: + * */ diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css new file mode 100644 index 00000000..21b312b5 --- /dev/null +++ b/css/stylesheets/screen.css @@ -0,0 +1,228 @@ +/* line 3, ../sass/screen.scss */ +#mainView { + margin: 30px auto; + width: 95%; +} + +/* line 5, ../sass/screen.scss */ +#jsonTextarea { + width: 700px; + height: 300px; +} + +/* line 7, ../sass/screen.scss */ +.red { + color: red; +} + +/* JSON VIEW */ +/* striped background */ +/* line 13, ../sass/screen.scss */ +.jsonView { + padding: 30px 0 0 5px; +} +/* line 14, ../sass/screen.scss */ +.jsonView select.form-control { + margin: 0; + padding: 0; + width: 100px; + display: inline; + height: 29px; + padding-left: 5px; +} +/* line 16, ../sass/screen.scss */ +.jsonView input { + height: 30px; + margin: 0; + padding: 0; +} +/* line 17, ../sass/screen.scss */ +.jsonView input.form-control { + width: 100px; + display: inline; + height: 29px; + padding-left: 5px; +} +/* line 18, ../sass/screen.scss */ +.jsonView input[type="text"], .jsonView input[type="number"] { + margin: 0; + border: 1px solid #ccc; + background: none; +} +/* line 19, ../sass/screen.scss */ +.jsonView input[type="checkbox"] { + position: absolute; +} +/* line 20, ../sass/screen.scss */ +.jsonView input.keyinput { + font-weight: bold; +} +/* line 23, ../sass/screen.scss */ +.jsonView input[type="text"].addItemKeyInput, .jsonView input[type="text"].addItemValueInput { + border: 1px solid #ccc; + background: white; + margin-left: 0; +} +/* line 26, ../sass/screen.scss */ +.jsonView .addItemKeyInput { + font-weight: bold; +} +/* line 27, ../sass/screen.scss */ +.jsonView .glyphicon-menu-right, .jsonView .glyphicon-menu-down { + float: left; + cursor: pointer; + position: relative; + top: -22px; + right: 22px; + margin-right: -15px; +} +/* line 28, ../sass/screen.scss */ +.jsonView > json > .glyphicon-menu-down { + display: none; +} +/* line 29, ../sass/screen.scss */ +.jsonView .addObjectItemBtn { + background-color: transparent; + border-color: transparent; + padding: 0; + border: 0; + height: 30px; + display: block; +} +/* line 30, ../sass/screen.scss */ +.jsonView .addObjectItemBtn i { + display: block; +} +/* line 32, ../sass/screen.scss */ +.jsonView .iconButton { + float: right; + margin-right: 10px; + position: relative; + top: 7px; + z-index: 99999999999999; + cursor: pointer; +} +/* line 33, ../sass/screen.scss */ +.jsonView .jsonObjectKey { + font-weight: bold; + margin-right: 25px; +} + +/* inputs */ +/* chevrons */ +/* add and delete */ +/* basic layout */ +/* line 44, ../sass/screen.scss */ +.jsonContents { + margin-left: 25px; +} + +/* line 46, ../sass/screen.scss */ +li .jsonContents { + margin-left: 0px; +} + +/* line 49, ../sass/screen.scss */ +.jsonView .block { + display: block; +} +/* line 50, ../sass/screen.scss */ +.jsonView .jsonItemDesc { + font-family: Georgia, serif; + color: grey; + font-style: italic; + cursor: default; + line-height: 30px; +} +/* line 51, ../sass/screen.scss */ +.jsonView .objectDesc { + cursor: default; +} +/* line 52, ../sass/screen.scss */ +.jsonView > json > .jsonItemDesc { + display: block; + float: left; + position: relative; + bottom: 25px; + height: 0; + width: 0; +} +/* line 53, ../sass/screen.scss */ +.jsonView ol.arrayOl { + margin: 0; + padding-left: 20px; +} +/* line 54, ../sass/screen.scss */ +.jsonView li { + clear: both; + min-height: 30px; +} +/* line 56, ../sass/screen.scss */ +.jsonView ol.arrayOl .glyphicon-menu-down, .jsonView ol.arrayOl .glyphicon-menu-right { + margin-left: -20px; +} +/* line 57, ../sass/screen.scss */ +.jsonView ol.arrayOl .glyphicon-menu-down { + top: 7px; +} +/* line 58, ../sass/screen.scss */ +.jsonView ol.arrayOl .glyphicon-menu-right { + top: -16px; +} +/* line 60, ../sass/screen.scss */ +.jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-down, .jsonView ol.arrayOl > li > span > span > json > .glyphicon-menu-right { + left: -40px; +} +/* line 62, ../sass/screen.scss */ +.jsonView ol.arrayOl li { + color: grey; + font-style: italic; + font-family: Georgia, serif; + list-style-type: decimal; +} +/* line 63, ../sass/screen.scss */ +.jsonView ol.arrayOl li input { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: normal; +} +/* line 67, ../sass/screen.scss */ +.jsonView li select, .jsonView li button { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: normal; +} +/* line 69, ../sass/screen.scss */ +.jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { + color: black; +} +/* line 70, ../sass/screen.scss */ +.jsonView li li { + list-style-type: lower-roman; +} +/* line 72, ../sass/screen.scss */ +.jsonView li li li { + list-style-type: upper-roman; +} +/* line 74, ../sass/screen.scss */ +.jsonView li li li li { + list-style-type: lower-latin; +} +/* line 76, ../sass/screen.scss */ +.jsonView li li li li li { + list-style-type: upper-latin; +} +/* line 78, ../sass/screen.scss */ +.jsonView li li li li li li { + list-style-type: lower-greek; +} +/* line 80, ../sass/screen.scss */ +.jsonView li li li li li li li { + list-style-type: decimal; +} + +/* first brace */ +/* array numbering */ +/* line 94, ../sass/screen.scss */ +.sortable-placeholder { + height: 20px; + display: block; +} diff --git a/index.html b/index.html index bd9dcad7..5b68ea90 100644 --- a/index.html +++ b/index.html @@ -18,7 +18,7 @@ - +
      From 3a6410a4c65b3484b13d0776951742ecc7681f21 Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 15 Dec 2015 11:09:50 +0100 Subject: [PATCH 011/113] remove first level of schema informations for modified array export --- bower.json | 3 ++- js/JSONedit.js | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/bower.json b/bower.json index 1fbdf1b1..791307e0 100644 --- a/bower.json +++ b/bower.json @@ -22,7 +22,8 @@ "bootstrap": "3.x.x", "angular": "~1.4.7", "angular-ui-sortable": "0.12.x", - "angular-bootstrap": "~0.14.1" + "angular-bootstrap": "~0.14.1", + "angular-history": "~0.x.x" }, "moduleType": [], "private": true diff --git a/js/JSONedit.js b/js/JSONedit.js index ff3c15ae..ea1055f6 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -50,11 +50,22 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit']) }, true); $scope.download = function (jsonData) { - //var result = JSON.stringify(jsonData); - //result = result.replace(/xmlns:all/g, 'xmlns'); - //result = result.replace(/\s[^(xmlns)]\w*=\"[a-zA-Z0-9\s\d\.\(\)\\\/\-,\'\|:]*\"/gim, ''); // remove all attributes - //var cleanJson = JSON.stringify(jsonData); var cleanJson = $filter('json')(jsonData); + var jsonObj = angular.fromJson(cleanJson); + var removeSchemaNodes = function(obj) { + Object.keys(obj).filter(function (v) { + return v.indexOf('$@') !== -1; + }).forEach(function (v) { + delete obj[v]; + }); + + for (var child in obj) { + //removeSchemaNodes(obj[child]); + // TODO make recursive + } + }; + removeSchemaNodes(jsonObj); + cleanJson = $filter('json')(jsonObj); $window.open("data:application/json;charset=utf-8," + encodeURIComponent(cleanJson)); }; From 417ebb675c9ebab8046f106c80dfa4488690d0b9 Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 15 Dec 2015 11:36:09 +0100 Subject: [PATCH 012/113] rekurzivni odebirani vsech schema informaci pomoci ngTraverse --- bower.json | 3 ++- index.html | 1 + js/JSONedit.js | 19 ++++++++----------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/bower.json b/bower.json index 791307e0..17ee2658 100644 --- a/bower.json +++ b/bower.json @@ -23,7 +23,8 @@ "angular": "~1.4.7", "angular-ui-sortable": "0.12.x", "angular-bootstrap": "~0.14.1", - "angular-history": "~0.x.x" + "angular-history": "~0.x.x", + "ngTraverse": "0.x.x" }, "moduleType": [], "private": true diff --git a/index.html b/index.html index 5b68ea90..540617dc 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,7 @@ + diff --git a/js/JSONedit.js b/js/JSONedit.js index ea1055f6..a37f11fc 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -2,9 +2,9 @@ var storage = Rhaboo.perishable("Some unique name"); var historyIndex = 0, historyUndo = 0; -var app = angular.module('NetopeerGUIApp', ['JSONedit']) +var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) - .controller('ConfigurationController', function ($scope, $filter, $http, $window, $timeout) { + .controller('ConfigurationController', function ($scope, $filter, $http, $window, $timeout, traverse) { storage.write('revisions', []); storage.erase('revisions'); @@ -53,16 +53,13 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit']) var cleanJson = $filter('json')(jsonData); var jsonObj = angular.fromJson(cleanJson); var removeSchemaNodes = function(obj) { - Object.keys(obj).filter(function (v) { - return v.indexOf('$@') !== -1; - }).forEach(function (v) { - delete obj[v]; + traverse(obj).forEach(function (element, index, array) { + if (typeof this.key !== "undefined") { + if (this.key.indexOf('$@') !== -1) { + this.remove(); + } + } }); - - for (var child in obj) { - //removeSchemaNodes(obj[child]); - // TODO make recursive - } }; removeSchemaNodes(jsonObj); cleanJson = $filter('json')(jsonObj); From c7e45734be40acb7710cbd4e580fa7c51d48f1ec Mon Sep 17 00:00:00 2001 From: David Alexa Date: Thu, 21 Jan 2016 11:30:53 +0100 Subject: [PATCH 013/113] rewrite api of data.php to support new netopeerguid. not tested, not working probably --- src/FIT/NetopeerBundle/Models/Data.php | 747 ++++++++++++++----------- 1 file changed, 435 insertions(+), 312 deletions(-) diff --git a/src/FIT/NetopeerBundle/Models/Data.php b/src/FIT/NetopeerBundle/Models/Data.php index 9955fe22..a0dc1dd2 100755 --- a/src/FIT/NetopeerBundle/Models/Data.php +++ b/src/FIT/NetopeerBundle/Models/Data.php @@ -203,16 +203,32 @@ private function unwrapRFC6242($message) { /** * Get hash for current connection * - * @param int $key session key - * @return string + * @todo: presunout do separatni sluzby + * + * @param int|array $keys array of session keys + * @param bool $associative return array with connId as key + * @return array */ - private function getHashFromKey($key) { - $conn = $this->getConnectionSessionForKey($key); + private function getHashFromKeys($keys, $associative = false) { + if (is_int($keys)) { + $keys = array($keys); + } + + $res = array(); + foreach ($keys as $key) { + $conn = $this->getConnectionSessionForKey($key); - if (isset($conn->hash)) { - return $conn->hash; + if (isset($conn->hash)) { + if ($associative) { + $res[$key] = $conn->hash; + } else { + $res[] = $conn->hash; + } + } } - //throw new \ErrorException("No identification key was found."); + + if (!empty($res)) return $res; + return "NOHASH"; } @@ -342,6 +358,8 @@ public function getModulePathByNS($key, $ns) { /** * Find instance of SessionConnection.class for key. * + * @todo: presunout do separatni sluzby + * * @param int $key session key * @return bool|ConnectionSession */ @@ -468,18 +486,25 @@ public function getCapabilitiesArrForKey($key) { /** * Updates array of SessionConnections. * - * @param int $key session key + * @todo: presunout do connection functionality + * + * @param int|array $keys session connection keys * @param string $targetDataStore target datastore identifier */ - private function updateConnLock($key, $targetDataStore) { - $conn = $this->getConnectionSessionForKey($key); - - if ($conn == false) { - return; + private function updateConnLock($keys, $targetDataStore) { + if (is_int($keys)) { + $keys = array($keys); } + foreach ($keys as $key) { + $conn = $this->getConnectionSessionForKey($key); + + if ($conn == false) { + continue; + } - $conn->toggleLockOfDatastore($targetDataStore); - $this->persistConnectionSessionForKey($key, $conn); + $conn->toggleLockOfDatastore($targetDataStore); + $this->persistConnectionSessionForKey($key, $conn); + } } /** @@ -614,7 +639,34 @@ private function getJsonError() { } /** - * Handles connection to the socket + * Adds params from sourceArr to targetArr if is defined in optionalParams + * + * @param array $targetArr + * @param array $sourceArr + * @param array $params + * + * @return mixed + */ + private function addOptionalParams(array $targetArr, array $sourceArr, array $optionalParams) { + foreach ($optionalParams as $param) { + if (isset($sourceArr[$param])) { + $targetArr[$param] = $sourceArr[$param]; + } + } + + return $targetArr; + } + + /** + * Request to create NETCONF session (connect) + * key: type (int), value: 4 + * key: user (string) + * + * Optional: + * key: host (string), "localhost" if not specified + * key: port (string), "830" if not specified + * key: pass (string), value: plain text password, mandatory if “privatekey” is not set + * key: privatekey (string), value: filesystem path to the private key, if set, “pass” parameter is optional and changes into the pass for this private key * * @param resource &$sock socket descriptor * @param array &$params connection params for mod_netconf @@ -624,22 +676,29 @@ private function getJsonError() { private function handle_connect(&$sock, &$params, &$result = null) { $session = $this->container->get('request')->getSession(); - $connect = json_encode(array( - "type" => self::MSG_CONNECT, - "host" => $params["host"], - "port" => $params["port"], - "user" => $params["user"], - "pass" => $params["pass"], - "capabilities" => $params["capabilities"], - )); + $connectParams = array( + "type" => self::MSG_CONNECT, + "host" => $params["host"], + "port" => $params["port"], + "user" => $params["user"], + "pass" => $params["pass"], + "capabilities" => $params["capabilities"], + ); + $connectParams = $this->addOptionalParams($connectParams, $params, array('host', 'port', 'user', 'pass', 'privatekey')); + + $connect = json_encode($connectParams); $this->write2socket($sock, $connect); $response = $this->readnetconf($sock); $decoded = json_decode($response, true); - if ($decoded && ($decoded["type"] == self::REPLY_OK)) { - $param = array( "session" => $decoded["session"] ); + if ($decoded) { + $newConnection = reset($decoded); + } + + if (isset($newConnection["type"]) && ($newConnection["type"] == self::REPLY_OK)) { + $param = array( "sessions" => array($newConnection['session'])); $status = $this->handle_info($sock, $param); - $newconnection = new ConnectionSession($decoded["session"], $params["host"], $params["port"], $params["user"]); + $newconnection = new ConnectionSession($newConnection['session'], $params["host"], $params["port"], $params["user"]); $newconnection->sessionStatus = json_encode($status); $newconnection = serialize($newconnection); @@ -655,9 +714,9 @@ private function handle_connect(&$sock, &$params, &$result = null) { return 0; } else { - $this->logger->addError("Could not connect.", array("error" => (isset($decoded["errors"])?" Error: ".var_export($decoded["errors"], true) : var_export($this->getJsonError(), true)))); - if (isset($decoded['errors'])) { - foreach ($decoded['errors'] as $error) { + $this->logger->addError("Could not connect.", array("error" => (isset($newConnection["errors"])?" Error: ".var_export($newConnection["errors"], true) : var_export($this->getJsonError(), true)))); + if (isset($newConnection['errors'])) { + foreach ($newConnection['errors'] as $error) { $session->getFlashBag()->add('error', $error); } } else { @@ -668,7 +727,52 @@ private function handle_connect(&$sock, &$params, &$result = null) { } /** - * handle get action + * Request to close NETCONF session (disconnect) + * key: type (int), value: 5 + * key: sessions (array of ints), value: array of SIDs + * + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) + * @return int 0 on success, 1 on error + */ + private function handle_disconnect(&$sock, &$params) { + if ($this->checkLoggedKeys() != 0) { + return 1; + } + $session = $this->container->get('request')->getSession(); + $sessionConnections = $session->get('session-connections'); + $sessionKeys = $this->getHashFromKeys($params['connIds'], true); + + $decoded = $this->execute_operation($sock, array( + "type" => self::MSG_DISCONNECT, + "sessions" => array_keys($sessionKeys) + )); + + foreach ($decoded as $sid => $response) { + if ($response["type"] === self::REPLY_OK) { + $session->getFlashBag()->add('success', "Session ".$sid." successfully disconnected."); + } else { + $this->logger->addError("Could not disconnect.", array("error" => var_export($response, true))); + $session->getFlashBag()->add('error', "Could not disconnect session ".$sid." from server. "); + } + + $key = array_search($sid, $sessionKeys); + if ($key) { + unset( $sessionConnections[$key] ); + } + } + + $session->set("session-connections", $sessionConnections); + } + + /** + * NETCONF (returns merged data) + * key: type (int), value: 6 + * key: sessions (array of ints), value: array of SIDs + * key: strict (bool), value: whether return error on unknown data + * + * Optional: + * key: filter (string), value: xml subtree filter * * @param resource &$sock socket descriptor * @param array &$params array of values for mod_netconf (type, params...) @@ -679,167 +783,158 @@ public function handle_get(&$sock, &$params) { return 1; } - $sessionKey = $this->getHashFromKey($params['key']); - - $get_params = array( + $getParams = array( "type" => self::MSG_GET, - "session" => $sessionKey, + "sessions" => $this->getHashFromKeys($params['connIds']), "source" => "running", ); - if ($params['filter'] !== "") { - $get_params["filter"] = $params['filter']; - } + $getParams = $this->addOptionalParams($getParams, $params, array('filters')); - $decoded = $this->execute_operation($sock, $get_params); + $decoded = $this->execute_operation($sock, $getParams); return $this->checkDecodedData($decoded); } /** - * handle get config action + * NETCONF (returns array of responses merged with schema) + * key: type (int), value: 7 + * key: sessions (array of ints), value: array of SIDs + * key: source (string), value: running|startup|candidate + * key: strict (bool), value: whether return error on unknown data * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return mixed decoded data on success, 1 on error + * Optional: + * key: filter (string), value: xml subtree filter + * + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) * + * @return mixed decoded data on success, 1 on error */ public function handle_getconfig(&$sock, &$params) { if ( $this->checkLoggedKeys() != 0) { return 1; } - $sessionKey = $this->getHashFromKey($params['key']); - $getconfigparams = array( + $getconfigParams = array( "type" => self::MSG_GETCONFIG, - "session" => $sessionKey, + "sessions" => $this->getHashFromKeys($params['connIds']), "source" => $params['source'], ); - if(isset($params['filter']) && $params['filter'] !== "") { - $getconfigparams["filter"] = $params['filter']; - } - $decoded = $this->execute_operation($sock, $getconfigparams); + $this->addOptionalParams($getconfigParams, $params, array('filters')); + + $decoded = $this->execute_operation($sock, $getconfigParams); return $this->checkDecodedData($decoded); } - /** - * handle edit config action + /** NETCONF + * key: type (int), value: 8 + * key: sessions (array of ints), value: array of SIDs + * key: target (string), value: running|startup|candidate + * key: configs (array of sJSON, with the same order as sessions), value: array of edit configuration data according to NETCONF RFC for each session * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return mixed decoded data on success, 1 on error + * Optional: + * key: source (string), value: config|url, default value: config + * key: default-operation (string), value: merge|replace|none + * key: error-option (string), value: stop-on-error|continue-on-error|rollback-on-error + * key: uri-source (string), required when "source" is "url", value: uri + * key: test-option (string), value: notset|testset|set|test, default value: testset + * + * + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) + * + * @return mixed decoded data on success, 1 on error */ private function handle_editconfig(&$sock, &$params) { if ( $this->checkLoggedKeys() != 0) { return 1; } - $sessionKey = $this->getHashFromKey($params['key']); - /* syntax highlighting problem if XML def. is in one string */ - $replaceWhatArr = array( - "", - "<".XMLoperations::$customRootElement.">", - "" - ); - $replaceWithArr = array( - "", - "", - "" - ); - $params['config'] = str_replace($replaceWhatArr, $replaceWithArr, $params['config']); /* edit-config to store new values */ $editparams = array( "type" => self::MSG_EDITCONFIG, - "session" => $sessionKey, + "sessions" => $this->getHashFromKeys($params['connIds']), "target" => $params['target'], + "configs" => $params['configs'], ); - if (isset($params['source']) && ($params['source'] === "url")) { - /* required 'uri-source' when 'source' is 'url' */ - $editparams['source'] = 'url'; - $editparams['uri-source'] = $params['uri-source']; - } else { - /* source can be set to "config" or "url" */ - $editparams['source'] = 'config'; - $editparams['config'] = $params['config']; - } - if (isset($params['default-operation']) && ($params['default-operation'] !== "")) { - $editparams['default-operation'] = $params['default-operation']; - } - if (isset($params['type']) && ($params['type'] !== "")) { - $editparams['type'] = $params['type']; - } - if (isset($params['test-option']) && ($params['test-option'] !== "")) { - $editparams['test-option'] = $params['test-option']; - } + $editparams = $this->addOptionalParams($editparams, $params, array('source', 'default-operation', 'error-option', 'uri-source', 'test-option')); + $decoded = $this->execute_operation($sock, $editparams); return $this->checkDecodedData($decoded); } /** - * handle copy config action + * NETCONF + * key: type (int), value: 9 + * key: sessions (array of ints), value: array of SIDs + * key: source (string), value: running|startup|candidate|url|config + * key: target (string), value: running|startup|candidate|url * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return mixed decoded data on success, 1 on error + * Optional: + * key: uri-source (string), required when "source" is "url", value: uri + * key: uri-target (string), required when "target" is "url", value: uri + * key: configs (array of sJSON, with the same order as sessions), required when “source” is “config”, value: array of new complete configuration data for each session, + * + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) + * + * @return mixed decoded data on success, 1 on error */ private function handle_copyconfig(&$sock, &$params) { if ( $this->checkLoggedKeys() != 0) { return 1; } - $sessionKey = $this->getHashFromKey($params['key']); - /* copy-config parameters */ - $newparams = array( + + $copyParams = array( "type" => self::MSG_COPYCONFIG, - "session" => $sessionKey, + "sessions" => $this->getHashFromKeys($params['connIds']), "source" => $params['source'], "target" => $params['target'], ); - if ($params['source'] === "url") { - $newparams['uri-source'] = $params['uri-source']; - } - if ($params['target'] === "url") { - $newparams['uri-target'] = $params['uri-target']; - } - $decoded = $this->execute_operation($sock, $newparams); + $copyParams = $this->addOptionalParams($copyParams, $params, array('uri-source', 'uri-target', 'configs')); + + $decoded = $this->execute_operation($sock, $copyParams); return $this->checkDecodedData($decoded); } /** - * handle get config action + * NETCONF + * key: type (int), value: 10 + * key: sessions (array of ints), value: array of SIDs + * key: target (string), value: running|startup|candidate|url + * Optional: + * key: url (string), value: target URL + * + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return int 0 on success, 1 on error + * @return mixed decoded data on success, 1 on error */ - private function handle_disconnect(&$sock, &$params) { - if ($this->checkLoggedKeys() != 0) { + private function handle_deleteconfig(&$sock, &$params) { + if ( $this->checkLoggedKeys() != 0) { return 1; } - $session = $this->container->get('request')->getSession(); - $sessionConnections = $session->get('session-connections'); - $requestKey = $params['key']; - $sessionKey = $this->getHashFromKey($params['key']); - - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_DISCONNECT, - "session" => $sessionKey - )); - if ($decoded["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Successfully disconnected."); - } else { - $this->logger->addError("Could not disconnecd.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not disconnect from server. "); - } + $deleteParams = array( + "type" => self::MSG_DELETECONFIG, + "sessions" => $this->getHashFromKeys($params['connIds']), + "target" => $params['target'], + ); + $deleteParams = $this->addOptionalParams($deleteParams, $params, array('url')); - unset( $sessionConnections[ $requestKey] ); - $session->set("session-connections", $sessionConnections); + $decoded = $this->execute_operation($sock, $deleteParams); + return $this->checkDecodedData($decoded); } /** - * handle lock action + * NETCONF + * key: type (int), value: 11 + * key: sessions (array of ints), value: array of SIDs + * key: target (string), value: running|startup|candidate * * @param resource &$sock socket descriptor * @param array &$params array of values for mod_netconf (type, params...) - * @return int 0 on success, 1 on error + * + * @return null|int 1 on error */ private function handle_lock(&$sock, &$params) { @@ -847,262 +942,291 @@ private function handle_lock(&$sock, &$params) { return 1; } $session = $this->container->get('request')->getSession(); - $sessionKey = $this->getHashFromKey($params['key']); + $sessionKeys = $this->getHashFromKeys($params['connIds'], true); $decoded = $this->execute_operation($sock, array( "type" => self::MSG_LOCK, "target" => $params['target'], - "session" => $sessionKey + "session" => array_values($sessionKeys) )); - if ($decoded["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Successfully locked."); - $this->updateConnLock($params['key'], $params['target']); - } else { - $this->logger->addError("Could not lock.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not lock datastore. "); + $lockedConnIds = array(); + foreach ($decoded as $sid => $response) { + if ($response["type"] === self::REPLY_OK) { + $session->getFlashBag()->add('success', "Session ".$sid." successfully locked."); + $lockedConnIds[] = array_search($sid, $sessionKeys); + } else { + $this->logger->addError("Could not lock.", array("error" => var_export($response, true))); + $session->getFlashBag()->add('error', "Could not lock datastore for session " .$sid. ". "); + } } + + $this->updateConnLock($lockedConnIds, $params['target']); } /** - * handle unlock action + * NETCONF + * key: type (int), value: 12 + * key: sessions (array of ints), value: array of SIDs + * key: target (string), value: running|startup|candidate * * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return int 0 on success, 1 on error + * @param array &$params array of values for mod_netconf (type, params...) + * + * @return int 0 on success, 1 on error */ private function handle_unlock(&$sock, &$params) { if ($this->checkLoggedKeys() != 0) { return 1; } $session = $this->container->get('request')->getSession(); - $sessionKey = $this->getHashFromKey($params['key']); + $sessionKeys = $this->getHashFromKeys($params['connIds'], true); $decoded = $this->execute_operation($sock, array( "type" => self::MSG_UNLOCK, "target" => $params['target'], - "session" => $sessionKey + "sessions" => array_values($sessionKeys), )); - if ($decoded["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Successfully unlocked."); - $this->updateConnLock($params['key'], $params['target']); - } else { - $this->logger->addError("Could not unlock.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not unlock datastore. "); + $lockedConnIds = array(); + foreach ($decoded as $sid => $response) { + if ($response["type"] === self::REPLY_OK) { + $session->getFlashBag()->add('success', "Session ".$sid." successfully unlocked."); + $lockedConnIds[] = array_search($sid, $sessionKeys); + } else { + $this->logger->addError("Could not unlock.", array("error" => var_export($response, true))); + $session->getFlashBag()->add('error', "Could not unlock session ".$sid.". "); + } } + + $this->updateConnLock($lockedConnIds, $params['target']); } /** - * handle User RPC method + * NETCONF + * key: type (int), value: 13 + * key: sessions (array of ints), value: array of SIDs + * key: session-id (int), value: SID of the session to kill * - * @param resource &$sock socket descriptor - * @param array &$params must contain "identifier" of schema, can contain "version" and "format" of schema - * @param mixed &$result decoded data from response - * @return int 0 on success, 1 on error + * @param resource &$sock socket descriptor + * @param array &$params must contain "session-id" + * @param mixed &$result decoded data from response + * + * @return int 0 on success, 1 on error */ - private function handle_userrpc(&$sock, &$params, &$result) { - + private function handle_killsession(&$sock, &$params, &$result) { if ($this->checkLoggedKeys() != 0) { return 1; } $session = $this->container->get('request')->getSession(); - $sessionKey = $this->getHashFromKey($params['key']); + $sessionKeys = $this->getHashFromKeys($params['connIds'], true); - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_GENERIC, - "content" => $params['content'], - "session" => $sessionKey - )); + $arguments = array( + "type" => self::MSG_KILL, + "sessions" => array_values($sessionKeys), + "session-id" => $params["session-id"], + ); - if ($decoded["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Successful call of method."); - } else if ($decoded["type"] === self::REPLY_DATA) { - $result = $decoded["data"]; - return 0; - } else { - $this->logger->addError("User RPC call.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "RPC error: ". - ((isset($decoded["errors"]) && sizeof($decoded['errors'])) ? $decoded["errors"][0] : "")); - return 1; + $decoded = $this->execute_operation($sock, $arguments); + + foreach ($decoded as $sid => $response) { + if ($response["type"] === self::REPLY_OK) { + $session->getFlashBag()->add('success', "Session ".$sid." successfully killed."); + } else { + $this->logger->addError("Could not kill session.", array("error" => var_export($response, true))); + $session->getFlashBag()->add('error', "Could not kill session ".$sid."."); + } } } /** - * handle reload info action + * Provide information about NETCONF session + * key: type (int), value: 14 + * key: sessions (array of ints), value: array of SIDs * - * Result is the same as from handle_info() - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return int 0 on success, 1 on error + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) + * + * @return int 0 on success, 1 on error */ - private function handle_reloadhello(&$sock, &$params) { - $session = $this->container->get('request')->getSession(); - - if (isset($params["session"]) && ($params["session"] !== "")) { - $sessionKey = $params['session']; + private function handle_info(&$sock, &$params) { + if (isset($params["sessions"])) { + $sessionKeys = $params['sessions']; } else { if ($this->checkLoggedKeys() != 0) { return 1; } - $sessionKey = $this->getHashFromKey($params['key']); + $sessionKeys = $this->getHashFromKeys($params['connIds']); } + $session = $this->container->get('request')->getSession(); $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_RELOADHELLO, - "session" => $sessionKey + "type" => self::MSG_INFO, + "sessions" => $sessionKeys )); if (!$decoded) { /* error occurred, unexpected response */ - $this->logger->addError("Could get reload hello.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not reload device informations."); - return 1; + $this->logger->addError("Could get session info.", array("error" => var_export($decoded, true))); + $session->getFlashBag()->add('error', "Could not get session info."); } - return $decoded; + return $this->checkDecodedData($decoded); } /** - * handle getting notifications history + * Perform generic operation not included in base NETCONF + * key: type (int), value: 15 + * key: sessions (array of ints), value: array of SIDs + * key: contents (array of sJSON with same index order as sessions array), value: array of sJSON data as content of the NETCONF's envelope * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return int 0 on success, 1 on error + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) + * + * @return int 0 on success, 1 on error */ - private function handle_ntf_gethistory(&$sock, &$params) { - if (isset($params["session"]) && ($params["session"] !== "")) { - $sessionKey = $params['session']; - } else { - $session = $this->container->get('request')->getSession(); - $sessionKey = $this->getHashFromKey($params['key']); - } - - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_NTF_GETHISTORY, - "session" => $sessionKey, - "from" => $params['from'], - "to" => $params['to'] - )); - - if (!$decoded) { - /* error occurred, unexpected response */ - $this->logger->addError("Could get notifications history.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not get notifications history."); + private function handle_generic(&$sock, &$params) { + if ( $this->checkLoggedKeys() != 0) { return 1; } - return $decoded; - } - - /** - * handle info action - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return int 0 on success, 1 on error - */ - private function handle_info(&$sock, &$params) { - if (isset($params["session"]) && ($params["session"] !== "")) { - $sessionKey = $params['session']; - } else { - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $session = $this->container->get('request')->getSession(); - $sessionKey = $this->getHashFromKey($params['key']); - } + $genericParams = array( + "type" => self::MSG_GENERIC, + "sessions" => $this->getHashFromKeys($params['connIds']), + "contents" => $params['contents'], + ); - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_INFO, - "session" => $sessionKey - )); + $decoded = $this->execute_operation($sock, $genericParams); - if (!$decoded) { - /* error occurred, unexpected response */ - $this->logger->addError("Could get session info.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not get session info."); + foreach ($decoded as $sid => $response) { + if ($response["type"] === self::REPLY_OK) { + $session->getFlashBag()->add('success', "Successful call of method."); + } else { + $this->logger->addError("User RPC call.", array("error" => var_export($response, true))); + $session->getFlashBag()->add('error', "RPC error: ". + ((isset($response["errors"]) && sizeof($response['errors'])) ? $response["errors"][0] : "")); + } } - return $decoded; + return $this->checkDecodedData($decoded); } /** * handle getschema action + * key: type (int), value: 16 + * key: sessions (array of ints), value: array of SIDs + * key: identifiers (array of strings with same index order as sessions array), value: array of schema identifiers + * Optional: + * key: format (string), value: format of the schema (yin or yang) * - * @param resource &$sock socket descriptor - * @param array &$params must contain "identifier" of schema, can contain "version" and "format" of schema - * @param mixed &$result decoded data from response - * @return int 0 on success, 1 on error + * @param resource &$sock socket descriptor + * @param array &$params must contain "identifier" of schema, can contain "version" and "format" of schema + * @param mixed &$result decoded data from response + * + * @return int 0 on success, 1 on error */ private function handle_getschema(&$sock, &$params, &$result) { if ($this->checkLoggedKeys() != 0) { return 1; } $session = $this->container->get('request')->getSession(); - $sessionKey = $this->getHashFromKey($params['key']); - /* TODO check if: "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring" - is in capabilities */ + $sessionKeys = $this->getHashFromKeys($params['connIds'], true); $arguments = array( "type" => self::MSG_GETSCHEMA, - "session" => $sessionKey, - "identifier" => $params["identifier"], /* TODO escape string $params["identifier"]? */ + "sessions" => array_values($sessionKeys), + "identifiers" => $params["identifiers"], ); - - if (isset($params["format"])) $arguments["format"] = $params["format"]; - if (isset($params["version"])) $arguments["version"] = $params["version"]; + $arguments = $this->addOptionalParams($arguments, $params, array('format', 'version')); $decoded = $this->execute_operation($sock, $arguments); + return $this->checkDecodedData($decoded); + } + /** + * Update hello message of NETCONF session + * key: type (int), value: 17 + * key: sessions (array of ints), value: array of SIDs + * + * Result is the same as from handle_info() + * + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) + * + * @return int 0 on success, 1 on error + */ + private function handle_reloadhello(&$sock, &$params) { + $session = $this->container->get('request')->getSession(); - if ($decoded["type"] === self::REPLY_DATA) { - $result = $decoded["data"]; - return 0; + if (isset($params["sessions"]) && ($params["sessions"] !== "")) { + $sessionKeys = $params['sessions']; } else { - $this->logger->addError("Get-schema failed.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Get-schema failed." - . ((isset($decoded["errors"]) && sizeof($decoded['errors'])) ? " Reason: ".$decoded["errors"][0] : "") - . (isset($decoded["bad-element"])?" (". $decoded["bad-element"] .")":"") - ); + if ($this->checkLoggedKeys() != 0) { + return 1; + } + $sessionKeys = $this->getHashFromKeys($params['connIds']); + } + + $decoded = $this->execute_operation($sock, array( + "type" => self::MSG_RELOADHELLO, + "sessions" => $sessionKeys + )); + + if (!$decoded) { + /* error occurred, unexpected response */ + $this->logger->addError("Could get reload hello.", array("error" => var_export($decoded, true))); + $session->getFlashBag()->add('error', "Could not reload device informations."); return 1; } + + return $this->checkDecodedData($decoded); } /** - * handle kill-session action + * Provide list of notifications from past. + * key: type (int), value: 18 + * key: sessions (array of ints), value: array of SIDs + * key: from (int64), value: start time in history + * key: to (int64), value: end time + * + * @param resource &$sock socket descriptor + * @param array &$params array of values for mod_netconf (type, params...) * - * @param resource &$sock socket descriptor - * @param array &$params must contain "session-id" - * @param mixed &$result decoded data from response - * @return int 0 on success, 1 on error + * @return int 0 on success, 1 on error */ - private function handle_killsession(&$sock, &$params, &$result) { - if ($this->checkLoggedKeys() != 0) { - return 1; + private function handle_notif_history(&$sock, &$params) { + if (isset($params["sessions"]) && ($params["sessions"] !== "")) { + $sessionKeys = $params['sessions']; + } else { + $session = $this->container->get('request')->getSession(); + $sessionKeys = $this->getHashFromKeys($params['connIds']); } - $session = $this->container->get('request')->getSession(); - $sessionKey = $this->getHashFromKey($params['key']); - $arguments = array( - "type" => self::MSG_KILL, - "session" => $sessionKey, - "session-id" => $params["session-id"], - ); - - $decoded = $this->execute_operation($sock, $arguments); + $decoded = $this->execute_operation($sock, array( + "type" => self::MSG_NTF_GETHISTORY, + "sessions" => $sessionKeys, + "from" => $params['from'], + "to" => $params['to'] + )); - if ($decoded["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Session successfully killed."); - $this->updateConnLock($params['key'], $params['target']); - } else { - $this->logger->addError("Could not kill session.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not kill session."); + if (!$decoded) { + /* error occurred, unexpected response */ + $this->logger->addError("Could get notifications history.", array("error" => var_export($decoded, true))); + $session->getFlashBag()->add('error', "Could not get notifications history."); + return 1; } + + return $this->checkDecodedData($decoded); } + /** - * validates datastore on server + * Validate datastore or url + * key: type (int), value: 19 + * key: sessions (array of ints), value: array of SIDs + * key: target (string), value: running|startup|candidate|url + * Required when target is "url": + * key: url (string), value: URL of datastore to validate * * @param $sock * @param $params @@ -1114,24 +1238,19 @@ public function handle_validate(&$sock, &$params) { return 1; } - $sessionKey = $this->getHashFromKey($params['key']); - - $get_params = array( + $validateParams = array( "type" => self::MSG_VALIDATE, - "session" => $sessionKey, + "session" => $this->getHashFromKeys($params['connIds']), "target" => $params['target'], ); - if (isset($params['url']) && ($params['url'] != NULL) && ($params['target'] == 'url')) { - $get_params["url"] = $params['url']; - } - if ($params['filter'] !== "") { - $get_params["filter"] = $params['filter']; - } + $validateParams = $this->addOptionalParams($validateParams, $params, array('url')); - $decoded = $this->execute_operation($sock, $get_params); + $decoded = $this->execute_operation($sock, $validateParams); return $this->checkDecodedData($decoded); } + + /** * checks, if logged keys are valid * @@ -1306,7 +1425,7 @@ public function handle($command, $params = array(), $merge = true, &$result = nu // } // } - $socket_path = '/var/run/mod_netconf.sock'; + $socket_path = '/var/run/netopeerguid.sock'; if (!file_exists($socket_path)) { $this->logger->addError('Backend is not running or socket file does not exist.', array($socket_path)); $this->container->get('request')->getSession()->getFlashBag()->add('error', "Backend is not running or socket file does not exist: ".$socket_path); @@ -1343,6 +1462,9 @@ public function handle($command, $params = array(), $merge = true, &$result = nu case "connect": $res = $this->handle_connect($sock, $params, $result); break; + case "disconnect": + $res = $this->handle_disconnect($sock, $params); + break; case "get": $res = $this->handle_get($sock, $params); break; @@ -1357,8 +1479,8 @@ public function handle($command, $params = array(), $merge = true, &$result = nu case "copyconfig": $res = $this->handle_copyconfig($sock, $params); break; - case "disconnect": - $res = $this->handle_disconnect($sock, $params); + case "deleteconfig": + $res = $this->handle_deleteconfig($sock, $params); break; case "lock": $res = $this->handle_lock($sock, $params); @@ -1366,28 +1488,29 @@ public function handle($command, $params = array(), $merge = true, &$result = nu case "unlock": $res = $this->handle_unlock($sock, $params); break; - case "reloadhello": - $res = $this->handle_reloadhello($sock, $params); - break; - case "notificationsHistory": - // JSON encoded data OR 1 on error, so we can return it now - return $this->handle_ntf_gethistory($sock, $params); + case "killsession": + $res = $this->handle_killsession($sock, $params, $result); break; case "info": $res = $this->handle_info($sock, $params); break; + case "userrpc": + case "generic": + $res = $this->handle_generic($sock, $params, $result); + break; case "getschema": $res = $this->handle_getschema($sock, $params, $result); break; - case "killsession": - $res = $this->handle_killsession($sock, $params, $result); + case "reloadhello": + $res = $this->handle_reloadhello($sock, $params); + break; + case "notif_history": + // JSON encoded data OR 1 on error, so we can return it now + return $this->handle_notif_history($sock, $params); break; case "validate": $res = $this->handle_validate($sock, $params, $result); break; - case "userrpc": - $res = $this->handle_userrpc($sock, $params, $result); - break; case "backup": $params["source"] = "startup"; $res_startup = "".$this->handle_getconfig($sock, $params).""; @@ -1645,7 +1768,7 @@ public function getModels($key = -1) { if ($key === -1) { $key = $this->container->get('request')->get('key'); } - $hashedKey = $this->getHashFromKey($key); + $hashedKey = $this->getHashFromKeys($key); if ($hashedKey && $cache->contains('menuStructure_'.$hashedKey)) { // $this->logger->addInfo("Cached file for menuStructure found.", array('key' => 'menuStructure_'.$hashedKey)); return $cache->fetch('menuStructure_'.$hashedKey); @@ -1665,7 +1788,7 @@ public function setModels($key, $folders, $lifetime = 6000) { * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache */ $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKey($key); + $hashedKey = $this->getHashFromKeys($key); $this->models = $folders; $cache->save('menuStructure_'.$hashedKey, $folders, $lifetime); } @@ -1681,7 +1804,7 @@ public function getModelNamespaces($key) { * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache */ $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKey($key); + $hashedKey = $this->getHashFromKeys($key); if ($hashedKey && $cache->contains('modelNamespaces_'.$hashedKey)) { // $this->logger->addInfo("Cached file for modelNamespaces found.", array('key' => 'modelNamespaces_'.$hashedKey)); return $cache->fetch('modelNamespaces_'.$hashedKey); @@ -1718,7 +1841,7 @@ public function setModelNamespaces($key, $namespaces, $lifetime = 6000) { * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache */ $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKey($key); + $hashedKey = $this->getHashFromKeys($key); $this->modelNamespaces = $namespaces; $cache->save('modelNamespaces_'.$hashedKey, $namespaces, $lifetime); } @@ -1743,7 +1866,7 @@ public function invalidateMenuStructureForKey($key) { * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache */ $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKey($key); + $hashedKey = $this->getHashFromKeys($key); if ($hashedKey && $cache->contains('modelNamespaces_'.$hashedKey)) { $this->logger->addInfo("Invalidate cached file", array('key' => 'modelNamespaces_'.$hashedKey)); $cache->delete('modelNamespaces_'.$hashedKey); From 862aa171a11ac5efdbcde7e518d04c377f40c0d9 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Thu, 21 Jan 2016 16:49:56 +0100 Subject: [PATCH 014/113] DataModel class is split into Netconf and Connection Functionality. Controllers supports new backend in NetconfFunctionality partly (could connect succesfully) --- app/config/config.yml | 2 +- .../Controller/ModuleController.php | 7 +- .../Resources/views/Module/section.html.twig | 2 + .../Controller/BaseController.php | 41 +- .../Controller/DefaultController.php | 48 +- .../Controller/ModuleController.php | 88 +- .../EventListener/ModuleListener.php | 16 +- src/FIT/NetopeerBundle/Models/Data.php | 2116 ----------------- .../Resources/config/functionality.yml | 51 + .../Resources/config/services.yml | 33 +- .../views/Default/connections.html.twig | 27 - .../Functionality/ConnectionFunctionality.php | 782 ++++++ .../Functionality/NetconfFunctionality.php | 1117 +++++++++ 13 files changed, 2053 insertions(+), 2277 deletions(-) delete mode 100755 src/FIT/NetopeerBundle/Models/Data.php create mode 100644 src/FIT/NetopeerBundle/Resources/config/functionality.yml create mode 100644 src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php create mode 100644 src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php diff --git a/app/config/config.yml b/app/config/config.yml index 6c5d5054..0fe0bcb8 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -28,7 +28,7 @@ parameters: #fit_netopeer.single_instance.host: 'localhost' #fit_netopeer.single_instance.port: '830' - netopeer.data.class: FIT\NetopeerBundle\Models\Data + netopeer.netconf.functionality: FIT\NetopeerBundle\Services\Functionality\NetconfFunctionality # Twig Configuration twig: diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php b/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php index 2f1b0f42..ddb229fd 100644 --- a/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php +++ b/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php @@ -22,10 +22,7 @@ class ModuleController extends \FIT\NetopeerBundle\Controller\ModuleController i */ public function moduleAction($key, $module = null, $subsection = null) { - /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass - */ - $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); $res = $this->prepareDataForModuleAction("FITModuleDefaultBundle", $key, $module, $subsection); /* parent module did not prepares data, but returns redirect response, @@ -59,7 +56,7 @@ public function moduleAction($key, $module = null, $subsection = null) $this->assign('singleColumnLayout', true); $this->setOnlyConfigSection(); } else { - $conn = $dataClass->getConnectionSessionForKey($key); + $conn = $connectionFunc->getConnectionSessionForKey($key); if ($conn->getCurrentDatastore() !== "running") { $this->loadConfigArr(false, $merge); $this->setOnlyConfigSection(); diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig b/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig index a6f2a3d7..f2e40c6c 100644 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig @@ -69,6 +69,7 @@ if advised of the possibility of such damage. {{ configSingleContent|raw }} {% else %}

      {% if stateSectionTitle is defined %}{{stateSectionTitle}}{% else %}Config & State data{% endif %}

      + {{ stateJson }} {% if stateArr is defined and (not(stateArr is empty) or (isEmptyModule is defined and isEmptyModule == true)) %}
      @@ -118,6 +119,7 @@ if advised of the possibility of such damage.

      {% if configSectionTitle is defined %}{{configSectionTitle}}{% else %}Config data only{% endif %}


      + {{ configJson }} {% if (configArr is defined and not(configArr is empty)) or (isEmptyModule is defined and isEmptyModule == true) %}
      diff --git a/src/FIT/NetopeerBundle/Controller/BaseController.php b/src/FIT/NetopeerBundle/Controller/BaseController.php index 90605e29..3cd57af0 100644 --- a/src/FIT/NetopeerBundle/Controller/BaseController.php +++ b/src/FIT/NetopeerBundle/Controller/BaseController.php @@ -159,23 +159,20 @@ protected function prepareGlobalTwigVariables() { ); $this->assign('app', $app); - /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass - */ - $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); if (!in_array($this->getRequest()->get('_route'), array('connections', '_login')) && !strpos($this->getRequest()->get('_controller'), 'AjaxController')) { if (!in_array($this->getRequest()->get('_route'), array('createEmptyModule'))) { - $dataClass->buildMenuStructure($this->activeSectionKey); + $connectionFunc->buildMenuStructure($this->activeSectionKey); } - $this->assign('topmenu', $dataClass->getModels()); - $this->assign('submenu', $dataClass->getSubmenu($this->submenuUrl, $this->getRequest()->get('key'))); + $this->assign('topmenu', $connectionFunc->getModels()); + $this->assign('submenu', $connectionFunc->getSubmenu($this->submenuUrl, $this->getRequest()->get('key'))); } try { $key = $this->getRequest()->get('key'); if ($key != "") { - $conn = $dataClass->getConnectionSessionForKey($key); + $conn = $connectionFunc->getConnectionSessionForKey($key); if ($conn !== false) { $this->assign('lockedConn', $conn->getLockForDatastore()); $this->assign('sessionStatus', $conn->sessionStatus); @@ -187,7 +184,7 @@ protected function prepareGlobalTwigVariables() { $session->getFlashBag()->add('error', "Trying to use unknown connection. Please, connect to the device."); } - $this->assign("ncFeatures", $dataClass->getCapabilitiesArrForKey($key)); + $this->assign("ncFeatures", $connectionFunc->getCapabilitiesArrForKey($key)); } /** @@ -199,11 +196,8 @@ protected function prepareGlobalTwigVariables() { * @param string $sourceConfig source param of config */ protected function setSectionFormsParams($key, $filterState = "", $filterConfig = "", $sourceConfig = "") { - /** - * @var $dataClass \FIT\NetopeerBundle\Models\Data - */ - $dataClass = $this->get('DataModel'); - $conn = $dataClass->getConnectionSessionForKey($key); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); + $conn = $connectionFunc->getConnectionSessionForKey($key); if ($conn) { if ($sourceConfig !== "") { @@ -212,10 +206,10 @@ protected function setSectionFormsParams($key, $filterState = "", $filterConfig $this->setConfigParams('source', $conn->getCurrentDatastore()); } - $this->setStateParams('key', $key); + $this->setStateParams('connIds', array($key)); $this->setStateParams('filter', $filterState); - $this->setConfigParams('key', $key); + $this->setConfigParams('connIds', array($key)); $this->setConfigParams('filter', $filterConfig); } @@ -225,9 +219,9 @@ protected function setSectionFormsParams($key, $filterState = "", $filterConfig * @param $key Identifier of connection (connected device ID) */ protected function setEmptyModuleForm($key) { - $dataClass = $this->get("DataModel"); - $tmpArr = $dataClass->getModuleIdentifiersForCurrentDevice($key); - $tmpArr = $dataClass->getRootNamesForModuleIdentifiers($key, $tmpArr); + $connectionFunc = $this->get("fitnetopeerbundle.service.connection.functionality"); + $tmpArr = $connectionFunc->getModuleIdentifiersForCurrentDevice($key); + $tmpArr = $connectionFunc->getRootNamesForModuleIdentifiers($key, $tmpArr); // use small hack when appending space at the end of key, which will fire all options in typeahead $nsArr = array(); @@ -291,6 +285,8 @@ protected function setOnlyConfigSection() { */ protected function createRPCListFromModel($module, $subsection = "") { + // TODO; + return; if (!empty($this::$rpcs)) return $this::$rpcs; /** * @var \FIT\NetopeerBundle\Models\Data $dataClass @@ -347,11 +343,8 @@ private function getRPCinputAttributesAndChildren(\SimpleXMLElement $root_elem, * @return bool|string */ protected function getCurrentDatastoreForKey($key) { - /** - * @var $dataClass \FIT\NetopeerBundle\Models\Data - */ - $dataClass = $this->get('DataModel'); - $conn = $dataClass->getConnectionSessionForKey($key); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); + $conn = $connectionFunc->getConnectionSessionForKey($key); if ($conn) { return $conn->getCurrentDatastore(); diff --git a/src/FIT/NetopeerBundle/Controller/DefaultController.php b/src/FIT/NetopeerBundle/Controller/DefaultController.php index 333089b0..0d7eabf9 100644 --- a/src/FIT/NetopeerBundle/Controller/DefaultController.php +++ b/src/FIT/NetopeerBundle/Controller/DefaultController.php @@ -47,6 +47,7 @@ use FIT\NetopeerBundle\Models\Array2XML; // these import the "@Route" and "@Template" annotations +use FIT\NetopeerBundle\Services\Functionality\NetconfFunctionality; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -92,11 +93,11 @@ public function connectionsAction($connectedDeviceId = NULL) */ $session = $this->getRequest()->getSession(); $singleInstance = $this->container->getParameter('fit_netopeer.single_instance'); - // DependencyInjection (DI) - defined in Resources/config/services.yml + /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass + * @var NetconfFunctionality */ - $dataClass = $this->get('DataModel'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $this->addAjaxBlock('FITNetopeerBundle:Default:connections.html.twig', 'title'); $this->addAjaxBlock('FITNetopeerBundle:Default:connections.html.twig', 'additionalTitle'); @@ -166,7 +167,7 @@ public function connectionsAction($connectedDeviceId = NULL) // state flash = state -> left column in the layout $result = ""; - $res = $dataClass->handle("connect", $params, false, $result); + $res = $netconfFunc->handle("connect", $params, false, $result); // if connection is broken (Could not connect) if ($res == 0) { @@ -190,7 +191,7 @@ public function connectionsAction($connectedDeviceId = NULL) $baseConn->saveConnectionIntoDB($post_vals['host'], $post_vals['port'], $post_vals['user']); } else { // update models - $dataClass->updateLocalModels($result); + $netconfFunc->updateLocalModels($result); setcookie("singleInstanceLoginFailed", false); return $this->redirect($this->generateUrl('handleConnection', array('command' => 'get', 'key' => $result))); } @@ -256,18 +257,15 @@ public function changeColumnLayoutAction($newValue) */ public function reloadDeviceAction($key) { - /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass - */ - $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); + $netconfFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); /* reload hello message */ $params = array('key' => $key); - if (($res = $dataClass->handle("reloadhello", $params) == 0)) { + if (($res = $netconfFunc->handle("reloadhello", $params) == 0)) { } - $dataClass->updateLocalModels($key); - $dataClass->invalidateAndRebuildMenuStructureForKey($key); + $connectionFunc->invalidateAndRebuildMenuStructureForKey($key); //reconstructs a routing path and gets a routing array called $route_params if ($this->getRequest()->isXmlHttpRequest()) { @@ -298,9 +296,9 @@ public function reloadDeviceAction($key) */ public function handleConnectionAction($command, $key, $identifier = "") { - $dataClass = $this->get('DataModel'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $params = array( - 'key' => $key, + 'connIds' => array($key), 'filter' => '', ); @@ -319,8 +317,7 @@ public function handleConnectionAction($command, $key, $identifier = "") $params['target'] = $this->getCurrentDatastoreForKey($key); $this->getRequest()->getSession()->set('isLocking', true); } - - $res = $dataClass->handle($command, $params, false); + $res = $netconfFunc->handle($command, $params, false); if ( $res != 1 && !in_array($command, array("connect", "disconnect"))) { return $this->redirect($this->generateUrl('section', array('key' => $key))); @@ -345,19 +342,20 @@ public function handleConnectionAction($command, $key, $identifier = "") */ public function handleBackupAction($key) { - $dataClass = $this->get('DataModel'); + $netconfFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); $params = array( 'key' => $key, 'filter' => '', ); - $res = $dataClass->handle('backup', $params, false); + $res = $netconfFunc->handle('backup', $params, false); $resp = new Response(); $resp->setStatusCode(200); $resp->headers->set('Cache-Control', 'private'); $resp->headers->set('Content-Length', strlen($res)); $resp->headers->set('Content-Type', 'application/force-download'); - $resp->headers->set('Content-Disposition', sprintf('attachment; filename="%s-%s.xml"', date("Y-m-d"), $dataClass->getHostFromKey($key))); + $resp->headers->set('Content-Disposition', sprintf('attachment; filename="%s-%s.xml"', date("Y-m-d"), $connectionFunc->getHostFromKey($key))); $resp->sendHeaders(); $resp->setContent($res); $resp->sendContent(); @@ -376,12 +374,10 @@ public function handleBackupAction($key) */ public function sessionInfoAction($key, $action) { - /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass - */ - $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); parent::setActiveSectionKey($key); - $dataClass->buildMenuStructure($key); + $connectionFunc->buildMenuStructure($key); $this->addAjaxBlock('FITModuleDefaultBundle:Module:section.html.twig', 'moduleJavascripts'); $this->addAjaxBlock('FITModuleDefaultBundle:Module:section.html.twig', 'moduleStylesheet'); @@ -428,7 +424,7 @@ public function sessionInfoAction($key, $action) } } - $connVarsArr['connection-'.$connKey][$connKey]['nc_features'] = $dataClass->getCapabilitiesArrForKey($connKey); + $connVarsArr['connection-'.$connKey][$connKey]['nc_features'] = $connectionFunc->getCapabilitiesArrForKey($connKey); } $sessionArr['session-connections'] = $connVarsArr; } @@ -443,7 +439,7 @@ public function sessionInfoAction($key, $action) $this->assign('hideStateSubmitButton', true); } else if ($action == "reload") { $params = array('key' => $key); - $dataClass->handle("reloadhello", $params); + $netconfFunc->handle("reloadhello", $params); } $this->assign('singleColumnLayout', true); diff --git a/src/FIT/NetopeerBundle/Controller/ModuleController.php b/src/FIT/NetopeerBundle/Controller/ModuleController.php index ffb76fd3..c91f0f64 100644 --- a/src/FIT/NetopeerBundle/Controller/ModuleController.php +++ b/src/FIT/NetopeerBundle/Controller/ModuleController.php @@ -76,10 +76,8 @@ class ModuleController extends BaseController { */ protected function prepareDataForModuleAction($bundleName, $key, $module = null, $subsection = null) { - /** - * @var Data $dataClass - */ - $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $this->bundleName = $bundleName; if ($this->getRequest()->getSession()->get('isLocking') !== true) { @@ -95,7 +93,7 @@ protected function prepareDataForModuleAction($bundleName, $key, $module = null, $this->addAjaxBlock($bundleName.':Module:section.html.twig', 'alerts'); $this->addAjaxBlock($bundleName.':Module:section.html.twig', 'topMenu'); - if ($dataClass->checkLoggedKeys() === 1) { + if ($connectionFunc->checkLoggedKeys() === 1) { $url = $this->get('request')->headers->get('referer'); if (!strlen($url)) { $url = $this->generateUrl('connections'); @@ -104,7 +102,7 @@ protected function prepareDataForModuleAction($bundleName, $key, $module = null, } /* build correct menu structure for this module, generates module structure too */ - $dataClass->buildMenuStructure($key); + $connectionFunc->buildMenuStructure($key); /* Show the first module we have */ if ( $module == null ) { @@ -113,7 +111,7 @@ protected function prepareDataForModuleAction($bundleName, $key, $module = null, // now, we could set forms params with filter (even if we don't have module or subsection) // filter will be empty - $filters = $dataClass->loadFilters($module, $subsection); + $filters = $connectionFunc->loadFilters($module, $subsection); $this->setSectionFormsParams($key, $filters['state'], $filters['config']); /** prepare necessary data for left column */ @@ -139,17 +137,11 @@ protected function prepareDataForModuleAction($bundleName, $key, $module = null, } // load model tree dump - $modelTree = $dataClass->getModelTreeDump($module); + $modelTree = $connectionFunc->getModelTreeDump($module); if ($modelTree) { $this->assign('modelTreeDump', $modelTree); } - // load identity refs array - $identities = $dataClass->loadIdentityRefsForModule($key, $module); - if ($identities) { - $this->assign('moduleIdentityRefs', $identities); - } - // loading state part = get Action // we will load it every time, because state column will we show everytime try { @@ -160,10 +152,9 @@ protected function prepareDataForModuleAction($bundleName, $key, $module = null, $merge = true; } - if ( ($xml = $dataClass->handle('get', $this->getStateParams(), $merge)) != 1 ) { - $xml = simplexml_load_string($xml, 'SimpleXMLIterator'); - $this->assign("stateArr", $xml); - return $xml; + if ( ($json = $netconfFunc->handle('get', $this->getStateParams(), $merge)) != 1 ) { + $this->assign("stateJson", $json); + return $json; } } catch (\ErrorException $e) { $this->get('data_logger')->err("State: Could not parse filter correctly.", array("message" => $e->getMessage())); @@ -180,14 +171,11 @@ protected function prepareDataForModuleAction($bundleName, $key, $module = null, * @return array */ protected function setModuleOutputStyles($key, $module) { - /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass - */ - $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); $controllers = array(); - $namespace = $dataClass->getNamespaceForModule($key, $module); - $record = $dataClass->getModuleControllers($module, $namespace); + $namespace = $connectionFunc->getNamespaceForModule($key, $module); + $record = $connectionFunc->getModuleControllers($module, $namespace); if ($record) { $controllers = $record->getControllerActions(); } @@ -206,8 +194,8 @@ protected function setModuleOutputStyles($key, $module) { } // build form for controller output change - $conn = $dataClass->getConnectionSessionForKey($key); - $controllerAction = $conn->getActiveControllersForNS($dataClass->getNamespaceForModule($key, $module)); + $conn = $connectionFunc->getConnectionSessionForKey($key); + $controllerAction = $conn->getActiveControllersForNS($connectionFunc->getNamespaceForModule($key, $module)); $form = $this->createFormBuilder(null, array('csrf_protection' => false)) ->add('controllerAction', 'choice', array( @@ -226,7 +214,7 @@ protected function setModuleOutputStyles($key, $module) { $postVals = $this->getRequest()->get("form"); if ( isset($postVals['controllerAction']) ) { $conn->setActiveController($namespace, $postVals['controllerAction']); - $dataClass->persistConnectionSessionForKey($key, $conn); + $connectionFunc->persistConnectionSessionForKey($key, $conn); } } @@ -243,14 +231,14 @@ protected function setModuleOutputStyles($key, $module) { * @return null|RedirectResponse */ protected function setModuleOrSectionName($key, $module, $subsection) { - $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); // if we have module, we are definitely in module or subsection action, so we could load names if ( $module ) { parent::setSubmenuUrl($module); - $this->assign('sectionName', $dataClass->getSectionName($module)); + $this->assign('sectionName', $connectionFunc->getSectionName($module)); if ( $subsection ) { - $this->assign('subsectionName', $dataClass->getSubsectionName($subsection)); + $this->assign('subsectionName', $connectionFunc->getSubsectionName($subsection)); } // we are in section @@ -281,9 +269,10 @@ protected function generateTypeaheadPath($key, $module, $subsection) { // path for creating node typeahead $typeaheadParams = array( 'formId' => "FORMID", - 'key' => $key, + 'connIds' => array($key), 'xPath' => "XPATH" ); + return; // TODO $valuesTypeaheadPath = $this->generateUrl('getValuesForLabel', $typeaheadParams); if (!is_null($module)) { $typeaheadParams['module'] = $module; @@ -305,7 +294,10 @@ protected function generateTypeaheadPath($key, $module, $subsection) { * @return RedirectResponse */ protected function redirectToFirstModule($key) { - $dataClass = $this->get('DataModel'); + // TODO + return $this->redirect($this->generateUrl("module", array('key' => $key, 'module' => 'all'))); + +// $dataClass = $this->get('DataModel'); $retArr['key'] = $key; $routeName = 'module'; $modules = $dataClass->getModels(); @@ -373,7 +365,7 @@ protected function processSectionForms($key, $module = null, $subsection = null) // we will redirect page after completion, because we want to load edited get and get-config // and what's more, flash message lives exactly one redirect, so without redirect flash message // would stay on the next page, what we do not want... - $retArr['key'] = $key; + $retArr['connIds'] = array($key); $routeName = 'section'; if ( $module ) { $retArr['module'] = $module; @@ -463,14 +455,17 @@ protected function loadConfigArr($addConfigSection = true, $merge = true, $bundl $bundleName = $this->bundleName; } try { - $dataClass = $this->get('dataModel'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); if ($addConfigSection) { $this->addAjaxBlock($bundleName.':Module:section.html.twig', 'config'); } // getcofig part - if ( ($xml = $dataClass->handle('getconfig', $this->getConfigParams(), $merge)) != 1 ) { - $xml = simplexml_load_string($xml, 'SimpleXMLIterator'); + if ( ($json = $netconfFunc->handle('getconfig', $this->getConfigParams(), $merge)) != 1 ) { + + $this->assign("configJson", $json); + return; + // TODO; // we have only root module if ($xml->count() == 0 && $xml->getName() == XMLoperations::$customRootElement) { @@ -542,7 +537,7 @@ private function handleFilterState(&$key, $post_vals) { $this->filterForms['state']->bind($this->getRequest()); if ( $this->filterForms['state']->isValid() ) { - $this->setStateParams("key", $key); + $this->setStateParams("connIds", array($key)); $this->setStateParams("filter", $post_vals["filter"]); return 0; } else { @@ -563,16 +558,13 @@ private function handleFilterConfig(&$key) { if ( $this->filterForms['config']->isValid() ) { $post_vals = $this->getRequest()->get("form"); - $this->setConfigParams("key", $key); + $this->setConfigParams("connIds", array($key)); // $this->setConfigParams("filter", $post_vals["filter"]); - /** - * @var $dataClass \FIT\NetopeerBundle\Models\Data - */ - $dataClass = $this->get('DataModel'); - $conn = $dataClass->getConnectionSessionForKey($key); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); + $conn = $connectionFunc->getConnectionSessionForKey($key); $conn->setCurrentDatastore($post_vals['source']); - $dataClass->persistConnectionSessionForKey($key, $conn); + $connectionFunc->persistConnectionSessionForKey($key, $conn); $this->setConfigParams("source", $post_vals['source']); @@ -593,20 +585,20 @@ private function handleFilterConfig(&$key) { * @return int 1 on error, 0 on success */ private function handleCopyConfig(&$key) { - $dataClass = $this->get('DataModel'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $this->filterForms['copyConfig']->bind($this->getRequest()); if ( $this->filterForms['copyConfig']->isValid() ) { $post_vals = $this->getRequest()->get("form"); - $this->setConfigParams("key", $key); + $this->setConfigParams("connIds", array($key)); $source = $this->getCurrentDatastoreForKey($key); if ($source === null) { $source = 'running'; } $target = $post_vals['target']; - $params = array('key' => $key, 'source' => $source, 'target' => $target); - $dataClass->handle('copyconfig', $params, false); + $params = array('connIds' => array($key), 'source' => $source, 'target' => $target); + $netconfFunc->handle('copyconfig', $params, false); return 0; } else { $this->getRequest()->getSession()->getFlashBag()->add('error', 'Copy config - you have not filled up form correctly.'); diff --git a/src/FIT/NetopeerBundle/EventListener/ModuleListener.php b/src/FIT/NetopeerBundle/EventListener/ModuleListener.php index 6a86730a..79e862b8 100644 --- a/src/FIT/NetopeerBundle/EventListener/ModuleListener.php +++ b/src/FIT/NetopeerBundle/EventListener/ModuleListener.php @@ -56,19 +56,19 @@ class ModuleListener */ private $logger; /** - * @var Data + * @var ConnectionFunctionality */ - private $dataModel; + private $connectionFunc; /** - * @param Data $dataModel + * @param Data $connectionFunc * @param EntityManager $em * @param Logger $logger * @param */ - public function __construct($dataModel = null, $em = null, $logger = null) + public function __construct($connectionFunc = null, $em = null, $logger = null) { - $this->dataModel = $dataModel; + $this->connectionFunc = $connectionFunc; $this->em = $em; $this->logger = $logger; } @@ -86,9 +86,9 @@ public function onKernelController(GetResponseEvent $event) if (in_array($attributes->get("_route"), array("module", "subsection"))) { // get available namespaces for this connection - $namespace = $this->dataModel->getNamespaceForModule($attributes->get('key'), $attributes->get('module')); + $namespace = $this->connectionFunc->getNamespaceForModule($attributes->get('key'), $attributes->get('module')); if ($namespace !== false) { - $record = $this->dataModel->getModuleControllers($attributes->get('module'), $namespace); + $record = $this->connectionFunc->getModuleControllers($attributes->get('module'), $namespace); if ($record) { // get all saved controllers from DB @@ -97,7 +97,7 @@ public function onKernelController(GetResponseEvent $event) /** * @var ConnectionSession $conn */ - $conn = $this->dataModel->getConnectionSessionForKey($attributes->get('key')); + $conn = $this->connectionFunc->getConnectionSessionForKey($attributes->get('key')); $activeController = $conn->getActiveControllersForNS($namespace); // if we don't have any saved (preferred) controller, we will use first from DB diff --git a/src/FIT/NetopeerBundle/Models/Data.php b/src/FIT/NetopeerBundle/Models/Data.php deleted file mode 100755 index a0dc1dd2..00000000 --- a/src/FIT/NetopeerBundle/Models/Data.php +++ /dev/null @@ -1,2116 +0,0 @@ - - * @author Tomas Cejka - * - * Copyright (C) 2012-2015 CESNET - * - * LICENSE TERMS - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of the Company nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * ALTERNATIVELY, provided that this notice is retained in full, this - * product may be distributed under the terms of the GNU General Public - * License (GPL) version 2 or later, in which case the provisions - * of the GPL apply INSTEAD OF those given above. - * - * This software is provided ``as is'', and any express or implied - * warranties, including, but not limited to, the implied warranties of - * merchantability and fitness for a particular purpose are disclaimed. - * In no event shall the company or contributors be liable for any - * direct, indirect, incidental, special, exemplary, or consequential - * damages (including, but not limited to, procurement of substitute - * goods or services; loss of use, data, or profits; or business - * interruption) however caused and on any theory of liability, whether - * in contract, strict liability, or tort (including negligence or - * otherwise) arising in any way out of the use of this software, even - * if advised of the possibility of such damage. - */ -namespace FIT\NetopeerBundle\Models; - -use FIT\Bundle\ModuleDefaultBundle\Controller\ModuleController; -use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Routing\RouterInterface; - -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\Finder\Finder; -use Doctrine\ORM\EntityManager; - -use FIT\NetopeerBundle\Entity\ConnectionSession; - -/** - * Data service, handles all communication between webGUI and mod_netconf. - */ -class Data { - - /* Enumeration of Message type (taken from mod_netconf.c) */ - const REPLY_OK = 0; - const REPLY_DATA = 1; - const REPLY_ERROR = 2; - const REPLY_INFO = 3; - const MSG_CONNECT = 4; - const MSG_DISCONNECT = 5; - const MSG_GET = 6; - const MSG_GETCONFIG = 7; - const MSG_EDITCONFIG = 8; - const MSG_COPYCONFIG = 9; - const MSG_DELETECONFIG = 10; - const MSG_LOCK = 11; - const MSG_UNLOCK = 12; - const MSG_KILL = 13; - const MSG_INFO = 14; - const MSG_GENERIC = 15; - const MSG_GETSCHEMA = 16; - const MSG_RELOADHELLO = 17; - const MSG_NTF_GETHISTORY = 18; - const MSG_VALIDATE = 19; - - /* subscription of notifications */ - const CPBLT_NOTIFICATIONS = "urn:ietf:params:netconf:capability:notification:1.0"; - /* - when this capability is missing, we cannot execute RPCs before - notif subscribe finishes :-/ - */ - const CPBLT_REALTIME_NOTIFICATIONS = "urn:ietf:params:netconf:capability:interleave:1.0"; - /* modifications of running config */ - const CPBLT_WRITABLERUNNING = "urn:ietf:params:netconf:capability:writable-running:1.0"; - /* candidate datastore */ - const CPBLT_CANDIDATE = "urn:ietf:params:netconf:capability:candidate:1.0"; - /* startup datastore */ - const CPBLT_STARTUP = "urn:ietf:params:netconf:capability:startup:1.0"; - const CPBLT_NETOPEER = "urn:cesnet:tmc:netopeer:1.0?module=netopeer-cfgnetopeer"; - const CPBLT_NETCONF_BASE10 = "urn:ietf:params:netconf:base:1.0"; - const CPBLT_NETCONF_BASE11 = "urn:ietf:params:netconf:base:1.1"; - - //"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04" - //"urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&revision=2011-03-08" - - - - /** - * @var ContainerInterface base bundle container - */ - protected $container; - /** - * @var \Symfony\Bridge\Monolog\Logger instance of logging class - */ - protected $logger; - /** - * @var array array of namespaces for module name - */ - private $modelNamespaces; - /** - * @var array|null array with names of models for creating top menu - */ - private $models; - /** - * @var array|null array of hash identifiers (array of connected devices). - */ - private $moduleIdentifiers; - /** - * @var array array of handle* result - * - * no need to call for example more than once - */ - private $handleResultsArr; - /** - * @var array array of submenu structure for every module - */ - private $submenu; - - /** - * Constructor with DependencyInjection params. - * - * @param \Symfony\Component\DependencyInjection\ContainerInterface $container - * @param \Symfony\Bridge\Monolog\Logger $logger logging class - */ - public function __construct(ContainerInterface $container, $logger) { - $this->container = $container; - $this->logger = $logger; - $this->models = null; - $this->modelNamespaces = array(); - } - - /** - * Parse $message formatted by Chunked Framing Mechanism (RFC6242) - * - * @param string $message input message text - * @return string unwrapped message - * - * @throws \ErrorException when message is not formatted correctly - */ - private function unwrapRFC6242($message) { - $response = ""; - if ($message == "") { - return $response; - } - $chunks = explode("\n#", $message); - $numchunks = sizeof($chunks); - $i = 0; - if ($numchunks > 0) { - do { - if ($i == 0 && $chunks[$i++] != "") { - /* something is wrong, message should start by '\n#' - */ - $this->logger->warn("Wrong message format, it is not according to RFC6242 (starting with \\n#).", array("message" => var_export($message, true))); - throw new \ErrorException("Wrong message format, it is not according to RFC6242 (starting with \\n#)."); - } - if ($i >= $numchunks) { - $this->logger->warn("Malformed message (RFC6242) - Bad amount of parts.", array("message" => var_export($message, true))); - throw new \ErrorException("Malformed message (RFC6242) - Bad amount of parts."); } - /* echo "chunk length
      \n"; */ - $len = 0; - sscanf($chunks[$i], "%i", $len); - - /* echo "chunk data
      \n"; */ - $nl = strpos($chunks[$i], "\n"); - if ($nl === false) { - $this->logger->warn("Malformed message (RFC6242) - There is no \\n after chunk-data size.", array("message" => var_export($message, true))); - throw new \ErrorException("Malformed message (RFC6242) - There is no \\n after chunk-data size."); - } - $data = substr($chunks[$i], $nl + 1); - $realsize = strlen($data); - if ($realsize != $len) { - $this->logger->warn("Chunk $i has the length $realsize instead of $len.", array("message" => var_export($message, true))); - throw new \ErrorException("Chunk $i has the length $realsize instead of $len."); - } - $response .= $data; - $i++; - if ($chunks[$i][0] == '#') { - /* ending part */ - break; - } - } while ($i<$numchunks); - } - - return $response; - } - - /** - * Get hash for current connection - * - * @todo: presunout do separatni sluzby - * - * @param int|array $keys array of session keys - * @param bool $associative return array with connId as key - * @return array - */ - private function getHashFromKeys($keys, $associative = false) { - if (is_int($keys)) { - $keys = array($keys); - } - - $res = array(); - foreach ($keys as $key) { - $conn = $this->getConnectionSessionForKey($key); - - if (isset($conn->hash)) { - if ($associative) { - $res[$key] = $conn->hash; - } else { - $res[] = $conn->hash; - } - } - } - - if (!empty($res)) return $res; - - return "NOHASH"; - } - - /** - * Find hash identifiers from DB for key - * - * @param int $key session key - * @return array return array of identifiers on success, false on error - */ - public function getModuleIdentifiersForCurrentDevice($key) { - $conn = $this->getConnectionSessionForKey($key); - if (!$conn) { - return false; - } - $sessionStatus = json_decode($conn->sessionStatus); - $capabilities = $sessionStatus->capabilities; - - $arr = array(); - if (is_array($capabilities) && count($capabilities)) { - foreach ($capabilities as $connKey => $value) { - $regex = "/(.*)\?module=(.*)&revision=([0-9|-]*)/"; - preg_match($regex, $value, $matches); - if ($matches !== null && count($matches) == 4) { - $arr[$matches[1]] = array( - 'hash' => $this->getModelIdentificator($matches[2], $matches[3], $matches[1]), - 'ns' => $matches[1], - 'moduleName' => $matches[2], - 'revision' => $matches[3], - ); - } - } - $this->moduleIdentifiers = $arr; - return $arr; - } - - return false; - } - - /** - * Get names of root element for specified module identifiers - * - * @param $key - * @param array $identifiers - * - * @return array - */ - public function getRootNamesForModuleIdentifiers($key, array $identifiers) { - $newArr = array(); - foreach ($identifiers as $ns => $ident) { - $ident['rootElem'] = $this->getRootNameForNS($key, $ident['ns']); - $newArr[$ns] = $ident; - } - - return $newArr; - } - - /** - * Get name of root element for module NS - * - * @param $key Identifier of connection (connected device ID) - * @param $ns - * - * @return string - */ - public function getRootNameForNS($key, $ns) { - $path = $this->getModelsDir().$this->getModulePathByNS($key, $ns); - $file = $path . '/filter.txt'; - $rootElem = ""; - if ( file_exists($file) ) { - $dom = new \DomDocument; - $dom->load($file); - $rootElem = $dom->documentElement->tagName; - } - - return $rootElem; - } - - /** - * get path for module name, includes identifier - * - * @param int $key session key - * @param string $moduleName name of element - * @param string $ns namespace of module will be used instead of module name - * - * @return string relative path on success, false on error - */ - private function getModulePathByRootModuleName($key, $moduleName, $ns = '') { - if (!is_array($this->moduleIdentifiers) || !count($this->moduleIdentifiers)) { - $this->getModuleIdentifiersForCurrentDevice($key); - } - - $modelNamespaces = $this->getModelNamespaces($key); - if (isset($modelNamespaces[$moduleName])) { - $cnt = count($modelNamespaces[$moduleName]); - if ($cnt == 1) { - $namespace = $modelNamespaces[$moduleName]; - if (isset($this->moduleIdentifiers[$namespace])) { - return $this->getModulePathByNS($key, $namespace); - } - } - } elseif (isset($this->moduleIdentifiers[$ns])) { - return $this->getModulePathByNS($key, $ns); - } - return false; - } - - /** - * get path for module namespace - * - * @param $key Identifier of connection (connected device ID) - * @param $ns - * - * @return bool|string - */ - public function getModulePathByNS($key, $ns) { - if (!is_array($this->moduleIdentifiers) || !count($this->moduleIdentifiers)) { - $this->getModuleIdentifiersForCurrentDevice($key); - } - if (isset($this->moduleIdentifiers[$ns])) { - return $this->moduleIdentifiers[$ns]['hash'] . - "/" . $this->moduleIdentifiers[$ns]['moduleName'] . - "/" . $this->moduleIdentifiers[$ns]['revision']; - } - return false; - } - - /** - * Find instance of SessionConnection.class for key. - * - * @todo: presunout do separatni sluzby - * - * @param int $key session key - * @return bool|ConnectionSession - */ - public function getConnectionSessionForKey($key) { - $session = $this->container->get('request')->getSession(); - $sessionConnections = $session->get('session-connections'); - if (isset($sessionConnections[$key]) && $key !== '') { - return unserialize($sessionConnections[$key]); - } - return false; - } - - /** - * get ModuleControllers instance for given module namespace and ID of connection - * - * @param string $module module name - * @param string $namespace module namespace - * - * @return ModuleController|null - */ - public function getModuleControllers($module, $namespace) { - $em = $this->container->get('doctrine')->getManager(); - $repository = $em->getRepository("FITNetopeerBundle:ModuleController"); - - return $repository->findOneBy(array( - 'moduleName' => $module, - 'moduleNamespace' => $namespace - )); - } - - /** - * Get port of SessionConnection for key. - * - * @param int $key session key - * @return string - */ - public function getPortFromKey($key) { - $session = $this->container->get('request')->getSession(); - $sessionConnections = $session->get('session-connections'); - if (isset($sessionConnections[$key]) && $key !== '') { - $con = unserialize($sessionConnections[$key]); - return $con->port; - } - return ""; - } - - /** - * Get user of SessionConnection for key. - * - * @param int $key session key - * @return string - */ - public function getUserFromKey($key) { - $session = $this->container->get('request')->getSession(); - $sessionConnections = $session->get('session-connections'); - if (isset($sessionConnections[$key]) && $key !== '') { - $con = unserialize($sessionConnections[$key]); - return $con->user; - } - return ""; - } - - /** - * Get host of SessionConnection for key. - * - * @param int $key session key - * @return string - */ - public function getHostFromKey($key) { - $session = $this->container->get('request')->getSession(); - $sessionConnections = $session->get('session-connections'); - if (isset($sessionConnections[$key]) && $key !== '') { - $con = unserialize($sessionConnections[$key]); - return $con->host; - } - return ""; - } - - /** - * Check if capability for feature is available. - * - * @param int $key session key - * @param string $feature name of feature/capability that is checked (constants Data::CPBLT_* can be used) - * @return bool - */ - protected function checkCapabilityForKey($key, $feature) { - $con = $this->getConnectionSessionForKey($key); - if ($con) { - $cpblts = json_decode($con->sessionStatus); - foreach ($cpblts->capabilities as $cpblt) { - if (strpos($cpblt, $feature, 0) === 0) { - return true; - } - } - } - return false; - } - - /** - * Gets array of available capabilities for all features. - * - * @param int $key session key - * @return array array of nc features - */ - public function getCapabilitiesArrForKey($key) { - $ncFeatures = Array(); - if ($this->checkCapabilityForKey($key, $this::CPBLT_NOTIFICATIONS) === true && - $this->checkCapabilityForKey($key, $this::CPBLT_REALTIME_NOTIFICATIONS) === true) { - $ncFeatures["nc_feature_notification"] = true; - } - if ($this->checkCapabilityForKey($key, $this::CPBLT_STARTUP) === true) { - $ncFeatures["nc_feature_startup"] = true; - } - if ($this->checkCapabilityForKey($key, $this::CPBLT_CANDIDATE) === true) { - $ncFeatures["nc_feature_candidate"] = true; - } - if ($this->checkCapabilityForKey($key, $this::CPBLT_WRITABLERUNNING) === true) { - $ncFeatures["nc_feature_writablerunning"] = true; - } - - return $ncFeatures; - } - - /** - * Updates array of SessionConnections. - * - * @todo: presunout do connection functionality - * - * @param int|array $keys session connection keys - * @param string $targetDataStore target datastore identifier - */ - private function updateConnLock($keys, $targetDataStore) { - if (is_int($keys)) { - $keys = array($keys); - } - foreach ($keys as $key) { - $conn = $this->getConnectionSessionForKey($key); - - if ($conn == false) { - continue; - } - - $conn->toggleLockOfDatastore($targetDataStore); - $this->persistConnectionSessionForKey($key, $conn); - } - } - - /** - * serializes ConnectionSession object into session - * - * @param int $key session key - * @param ConnectionSession $conn - */ - public function persistConnectionSessionForKey($key, $conn) { - $session = $this->container->get('request')->getSession(); - $sessionConnections = $session->get('session-connections'); - $sessionConnections[$key] = serialize($conn); - $session->set('session-connections', $sessionConnections); - } - - /** - * Read response from socket - * - * @param resource &$sock socket descriptor - * @return string trimmed string that was read - */ - private function readnetconf2(&$sock) { - $response = ""; - do { - $tmp = ""; - $tmp = fread($sock, 4096); - if ($tmp != "") { - $response .= $tmp; - } - if (strlen($tmp) < 4096) { - break; - } - } while ($tmp != ""); - $status = stream_get_meta_data($sock); - if (!$response && $status["timed_out"] == true) { - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Reached timeout for reading response."); - } - /* "unchunk" frames (RFC6242) */ - try { - $response = $this->unwrapRFC6242($response); - } catch (\ErrorException $e) { - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not read NetConf. Error: ".$e->getMessage()); - return 1; - } - - return trim($response); - } - - /** - * Read response from socket - * - * @param resource &$sock socket descriptor - * @return string trimmed string that was read - */ - private function readnetconf(&$sock) { - $response = ""; - $tmp = ""; - $tmp = fread($sock, 1024); - if ($tmp === false) { - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Reading failure."); - } - - $response = $tmp; - // message is wrapped in "\n#strlen($m)\n$m\n##\n" - // get size: - $size = 0; - $lines = explode("\n", $tmp); - if (count($lines) >= 2) { - $size = strlen($lines[0]) + 1 + strlen($lines[1]) + 1; - $size += intval(substr($lines[1], 1)) + 5; - } - - while (strlen($response) < $size) { - $tmp = ""; - $tmp = fread($sock, $size - strlen($response)); - if ($tmp === false) { - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Reading failure."); - break; - } - $response .= $tmp; - //echo strlen($response) ."/". $size ."\n"; - } - $status = stream_get_meta_data($sock); - if (!$response && $status["timed_out"] == true) { - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Reached timeout for reading response."); - //echo "Reached timeout for reading response."; - } - /* "unchunk" frames (RFC6242) */ - try { - $response = $this->unwrapRFC6242($response); - } catch (\ErrorException $e) { - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not read NetConf. Error: ".$e->getMessage()); - //echo "unwrap exception"; - return 1; - } - //echo "readnetconf time consumed: ". (microtime(true) - $start); - - return trim($response); - } - - /** - * Sets error message based on JSON ERROR CODE. - * - * @return array errorCode and message for this errorCode. - */ - private function getJsonError() { - $res = 0; - switch ($errorCode = json_last_error()) { - case JSON_ERROR_NONE: - $res = 'No errors'; - break; - case JSON_ERROR_DEPTH: - $res = 'Maximum stack depth exceeded'; - break; - case JSON_ERROR_STATE_MISMATCH: - $res = 'Underflow or the modes mismatch'; - break; - case JSON_ERROR_CTRL_CHAR: - $res = 'Unexpected control character found'; - break; - case JSON_ERROR_SYNTAX: - $res = 'Syntax error, malformed JSON'; - break; - case JSON_ERROR_UTF8: - $res = 'Malformed UTF-8 characters, possibly incorrectly encoded'; - break; - default: - $res = 'Unknown error'; - break; - } - return array('errorCode' => $errorCode, 'message' => $res); - } - - /** - * Adds params from sourceArr to targetArr if is defined in optionalParams - * - * @param array $targetArr - * @param array $sourceArr - * @param array $params - * - * @return mixed - */ - private function addOptionalParams(array $targetArr, array $sourceArr, array $optionalParams) { - foreach ($optionalParams as $param) { - if (isset($sourceArr[$param])) { - $targetArr[$param] = $sourceArr[$param]; - } - } - - return $targetArr; - } - - /** - * Request to create NETCONF session (connect) - * key: type (int), value: 4 - * key: user (string) - * - * Optional: - * key: host (string), "localhost" if not specified - * key: port (string), "830" if not specified - * key: pass (string), value: plain text password, mandatory if “privatekey” is not set - * key: privatekey (string), value: filesystem path to the private key, if set, “pass” parameter is optional and changes into the pass for this private key - * - * @param resource &$sock socket descriptor - * @param array &$params connection params for mod_netconf - * @param mixed &$result result of searching of new connection in all connections - * @return int 0 on success - */ - private function handle_connect(&$sock, &$params, &$result = null) { - $session = $this->container->get('request')->getSession(); - - $connectParams = array( - "type" => self::MSG_CONNECT, - "host" => $params["host"], - "port" => $params["port"], - "user" => $params["user"], - "pass" => $params["pass"], - "capabilities" => $params["capabilities"], - ); - $connectParams = $this->addOptionalParams($connectParams, $params, array('host', 'port', 'user', 'pass', 'privatekey')); - - $connect = json_encode($connectParams); - $this->write2socket($sock, $connect); - $response = $this->readnetconf($sock); - $decoded = json_decode($response, true); - - if ($decoded) { - $newConnection = reset($decoded); - } - - if (isset($newConnection["type"]) && ($newConnection["type"] == self::REPLY_OK)) { - $param = array( "sessions" => array($newConnection['session'])); - $status = $this->handle_info($sock, $param); - $newconnection = new ConnectionSession($newConnection['session'], $params["host"], $params["port"], $params["user"]); - $newconnection->sessionStatus = json_encode($status); - $newconnection = serialize($newconnection); - - if ( !$sessionConnections = $session->get("session-connections") ) { - $session->set("session-connections", array($newconnection)); - } else { - $sessionConnections[] = $newconnection; - $session->set("session-connections", $sessionConnections); - } - - $session->getFlashBag()->add('success', "Successfully connected."); - $result = array_search($newconnection, $session->get("session-connections")); - - return 0; - } else { - $this->logger->addError("Could not connect.", array("error" => (isset($newConnection["errors"])?" Error: ".var_export($newConnection["errors"], true) : var_export($this->getJsonError(), true)))); - if (isset($newConnection['errors'])) { - foreach ($newConnection['errors'] as $error) { - $session->getFlashBag()->add('error', $error); - } - } else { - $session->getFlashBag()->add('error', "Could not connect. Unknown error."); - } - return 1; - } - } - - /** - * Request to close NETCONF session (disconnect) - * key: type (int), value: 5 - * key: sessions (array of ints), value: array of SIDs - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return int 0 on success, 1 on error - */ - private function handle_disconnect(&$sock, &$params) { - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $session = $this->container->get('request')->getSession(); - $sessionConnections = $session->get('session-connections'); - $sessionKeys = $this->getHashFromKeys($params['connIds'], true); - - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_DISCONNECT, - "sessions" => array_keys($sessionKeys) - )); - - foreach ($decoded as $sid => $response) { - if ($response["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Session ".$sid." successfully disconnected."); - } else { - $this->logger->addError("Could not disconnect.", array("error" => var_export($response, true))); - $session->getFlashBag()->add('error', "Could not disconnect session ".$sid." from server. "); - } - - $key = array_search($sid, $sessionKeys); - if ($key) { - unset( $sessionConnections[$key] ); - } - } - - $session->set("session-connections", $sessionConnections); - } - - /** - * NETCONF (returns merged data) - * key: type (int), value: 6 - * key: sessions (array of ints), value: array of SIDs - * key: strict (bool), value: whether return error on unknown data - * - * Optional: - * key: filter (string), value: xml subtree filter - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * @return mixed decoded data on success - */ - public function handle_get(&$sock, &$params) { - if ( $this->checkLoggedKeys() != 0) { - return 1; - } - - $getParams = array( - "type" => self::MSG_GET, - "sessions" => $this->getHashFromKeys($params['connIds']), - "source" => "running", - ); - $getParams = $this->addOptionalParams($getParams, $params, array('filters')); - - $decoded = $this->execute_operation($sock, $getParams); - - return $this->checkDecodedData($decoded); - } - - /** - * NETCONF (returns array of responses merged with schema) - * key: type (int), value: 7 - * key: sessions (array of ints), value: array of SIDs - * key: source (string), value: running|startup|candidate - * key: strict (bool), value: whether return error on unknown data - * - * Optional: - * key: filter (string), value: xml subtree filter - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) * - * @return mixed decoded data on success, 1 on error - */ - public function handle_getconfig(&$sock, &$params) { - if ( $this->checkLoggedKeys() != 0) { - return 1; - } - - $getconfigParams = array( - "type" => self::MSG_GETCONFIG, - "sessions" => $this->getHashFromKeys($params['connIds']), - "source" => $params['source'], - ); - $this->addOptionalParams($getconfigParams, $params, array('filters')); - - $decoded = $this->execute_operation($sock, $getconfigParams); - return $this->checkDecodedData($decoded); - } - - /** NETCONF - * key: type (int), value: 8 - * key: sessions (array of ints), value: array of SIDs - * key: target (string), value: running|startup|candidate - * key: configs (array of sJSON, with the same order as sessions), value: array of edit configuration data according to NETCONF RFC for each session - * - * Optional: - * key: source (string), value: config|url, default value: config - * key: default-operation (string), value: merge|replace|none - * key: error-option (string), value: stop-on-error|continue-on-error|rollback-on-error - * key: uri-source (string), required when "source" is "url", value: uri - * key: test-option (string), value: notset|testset|set|test, default value: testset - * - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return mixed decoded data on success, 1 on error - */ - private function handle_editconfig(&$sock, &$params) { - if ( $this->checkLoggedKeys() != 0) { - return 1; - } - - /* edit-config to store new values */ - $editparams = array( - "type" => self::MSG_EDITCONFIG, - "sessions" => $this->getHashFromKeys($params['connIds']), - "target" => $params['target'], - "configs" => $params['configs'], - ); - $editparams = $this->addOptionalParams($editparams, $params, array('source', 'default-operation', 'error-option', 'uri-source', 'test-option')); - - $decoded = $this->execute_operation($sock, $editparams); - return $this->checkDecodedData($decoded); - } - - /** - * NETCONF - * key: type (int), value: 9 - * key: sessions (array of ints), value: array of SIDs - * key: source (string), value: running|startup|candidate|url|config - * key: target (string), value: running|startup|candidate|url - * - * Optional: - * key: uri-source (string), required when "source" is "url", value: uri - * key: uri-target (string), required when "target" is "url", value: uri - * key: configs (array of sJSON, with the same order as sessions), required when “source” is “config”, value: array of new complete configuration data for each session, - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return mixed decoded data on success, 1 on error - */ - private function handle_copyconfig(&$sock, &$params) { - if ( $this->checkLoggedKeys() != 0) { - return 1; - } - - $copyParams = array( - "type" => self::MSG_COPYCONFIG, - "sessions" => $this->getHashFromKeys($params['connIds']), - "source" => $params['source'], - "target" => $params['target'], - ); - $copyParams = $this->addOptionalParams($copyParams, $params, array('uri-source', 'uri-target', 'configs')); - - $decoded = $this->execute_operation($sock, $copyParams); - return $this->checkDecodedData($decoded); - } - - /** - * NETCONF - * key: type (int), value: 10 - * key: sessions (array of ints), value: array of SIDs - * key: target (string), value: running|startup|candidate|url - * Optional: - * key: url (string), value: target URL - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return mixed decoded data on success, 1 on error - */ - private function handle_deleteconfig(&$sock, &$params) { - if ( $this->checkLoggedKeys() != 0) { - return 1; - } - - $deleteParams = array( - "type" => self::MSG_DELETECONFIG, - "sessions" => $this->getHashFromKeys($params['connIds']), - "target" => $params['target'], - ); - $deleteParams = $this->addOptionalParams($deleteParams, $params, array('url')); - - $decoded = $this->execute_operation($sock, $deleteParams); - return $this->checkDecodedData($decoded); - } - - /** - * NETCONF - * key: type (int), value: 11 - * key: sessions (array of ints), value: array of SIDs - * key: target (string), value: running|startup|candidate - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return null|int 1 on error - */ - private function handle_lock(&$sock, &$params) { - - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $session = $this->container->get('request')->getSession(); - $sessionKeys = $this->getHashFromKeys($params['connIds'], true); - - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_LOCK, - "target" => $params['target'], - "session" => array_values($sessionKeys) - )); - - $lockedConnIds = array(); - foreach ($decoded as $sid => $response) { - if ($response["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Session ".$sid." successfully locked."); - $lockedConnIds[] = array_search($sid, $sessionKeys); - } else { - $this->logger->addError("Could not lock.", array("error" => var_export($response, true))); - $session->getFlashBag()->add('error', "Could not lock datastore for session " .$sid. ". "); - } - } - - $this->updateConnLock($lockedConnIds, $params['target']); - } - - /** - * NETCONF - * key: type (int), value: 12 - * key: sessions (array of ints), value: array of SIDs - * key: target (string), value: running|startup|candidate - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return int 0 on success, 1 on error - */ - private function handle_unlock(&$sock, &$params) { - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $session = $this->container->get('request')->getSession(); - $sessionKeys = $this->getHashFromKeys($params['connIds'], true); - - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_UNLOCK, - "target" => $params['target'], - "sessions" => array_values($sessionKeys), - )); - - $lockedConnIds = array(); - foreach ($decoded as $sid => $response) { - if ($response["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Session ".$sid." successfully unlocked."); - $lockedConnIds[] = array_search($sid, $sessionKeys); - } else { - $this->logger->addError("Could not unlock.", array("error" => var_export($response, true))); - $session->getFlashBag()->add('error', "Could not unlock session ".$sid.". "); - } - } - - $this->updateConnLock($lockedConnIds, $params['target']); - } - - /** - * NETCONF - * key: type (int), value: 13 - * key: sessions (array of ints), value: array of SIDs - * key: session-id (int), value: SID of the session to kill - * - * @param resource &$sock socket descriptor - * @param array &$params must contain "session-id" - * @param mixed &$result decoded data from response - * - * @return int 0 on success, 1 on error - */ - private function handle_killsession(&$sock, &$params, &$result) { - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $session = $this->container->get('request')->getSession(); - $sessionKeys = $this->getHashFromKeys($params['connIds'], true); - - $arguments = array( - "type" => self::MSG_KILL, - "sessions" => array_values($sessionKeys), - "session-id" => $params["session-id"], - ); - - $decoded = $this->execute_operation($sock, $arguments); - - foreach ($decoded as $sid => $response) { - if ($response["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Session ".$sid." successfully killed."); - } else { - $this->logger->addError("Could not kill session.", array("error" => var_export($response, true))); - $session->getFlashBag()->add('error', "Could not kill session ".$sid."."); - } - } - } - - /** - * Provide information about NETCONF session - * key: type (int), value: 14 - * key: sessions (array of ints), value: array of SIDs - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return int 0 on success, 1 on error - */ - private function handle_info(&$sock, &$params) { - if (isset($params["sessions"])) { - $sessionKeys = $params['sessions']; - } else { - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $sessionKeys = $this->getHashFromKeys($params['connIds']); - } - - $session = $this->container->get('request')->getSession(); - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_INFO, - "sessions" => $sessionKeys - )); - - if (!$decoded) { - /* error occurred, unexpected response */ - $this->logger->addError("Could get session info.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not get session info."); - } - - return $this->checkDecodedData($decoded); - } - - /** - * Perform generic operation not included in base NETCONF - * key: type (int), value: 15 - * key: sessions (array of ints), value: array of SIDs - * key: contents (array of sJSON with same index order as sessions array), value: array of sJSON data as content of the NETCONF's envelope - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return int 0 on success, 1 on error - */ - private function handle_generic(&$sock, &$params) { - if ( $this->checkLoggedKeys() != 0) { - return 1; - } - - $genericParams = array( - "type" => self::MSG_GENERIC, - "sessions" => $this->getHashFromKeys($params['connIds']), - "contents" => $params['contents'], - ); - - $decoded = $this->execute_operation($sock, $genericParams); - - foreach ($decoded as $sid => $response) { - if ($response["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Successful call of method."); - } else { - $this->logger->addError("User RPC call.", array("error" => var_export($response, true))); - $session->getFlashBag()->add('error', "RPC error: ". - ((isset($response["errors"]) && sizeof($response['errors'])) ? $response["errors"][0] : "")); - } - } - - return $this->checkDecodedData($decoded); - } - - /** - * handle getschema action - * key: type (int), value: 16 - * key: sessions (array of ints), value: array of SIDs - * key: identifiers (array of strings with same index order as sessions array), value: array of schema identifiers - * Optional: - * key: format (string), value: format of the schema (yin or yang) - * - * @param resource &$sock socket descriptor - * @param array &$params must contain "identifier" of schema, can contain "version" and "format" of schema - * @param mixed &$result decoded data from response - * - * @return int 0 on success, 1 on error - */ - private function handle_getschema(&$sock, &$params, &$result) { - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $session = $this->container->get('request')->getSession(); - $sessionKeys = $this->getHashFromKeys($params['connIds'], true); - - $arguments = array( - "type" => self::MSG_GETSCHEMA, - "sessions" => array_values($sessionKeys), - "identifiers" => $params["identifiers"], - ); - $arguments = $this->addOptionalParams($arguments, $params, array('format', 'version')); - - $decoded = $this->execute_operation($sock, $arguments); - return $this->checkDecodedData($decoded); - } - - /** - * Update hello message of NETCONF session - * key: type (int), value: 17 - * key: sessions (array of ints), value: array of SIDs - * - * Result is the same as from handle_info() - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return int 0 on success, 1 on error - */ - private function handle_reloadhello(&$sock, &$params) { - $session = $this->container->get('request')->getSession(); - - if (isset($params["sessions"]) && ($params["sessions"] !== "")) { - $sessionKeys = $params['sessions']; - } else { - if ($this->checkLoggedKeys() != 0) { - return 1; - } - $sessionKeys = $this->getHashFromKeys($params['connIds']); - } - - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_RELOADHELLO, - "sessions" => $sessionKeys - )); - - if (!$decoded) { - /* error occurred, unexpected response */ - $this->logger->addError("Could get reload hello.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not reload device informations."); - return 1; - } - - return $this->checkDecodedData($decoded); - } - - /** - * Provide list of notifications from past. - * key: type (int), value: 18 - * key: sessions (array of ints), value: array of SIDs - * key: from (int64), value: start time in history - * key: to (int64), value: end time - * - * @param resource &$sock socket descriptor - * @param array &$params array of values for mod_netconf (type, params...) - * - * @return int 0 on success, 1 on error - */ - private function handle_notif_history(&$sock, &$params) { - if (isset($params["sessions"]) && ($params["sessions"] !== "")) { - $sessionKeys = $params['sessions']; - } else { - $session = $this->container->get('request')->getSession(); - $sessionKeys = $this->getHashFromKeys($params['connIds']); - } - - $decoded = $this->execute_operation($sock, array( - "type" => self::MSG_NTF_GETHISTORY, - "sessions" => $sessionKeys, - "from" => $params['from'], - "to" => $params['to'] - )); - - if (!$decoded) { - /* error occurred, unexpected response */ - $this->logger->addError("Could get notifications history.", array("error" => var_export($decoded, true))); - $session->getFlashBag()->add('error', "Could not get notifications history."); - return 1; - } - - return $this->checkDecodedData($decoded); - } - - - /** - * Validate datastore or url - * key: type (int), value: 19 - * key: sessions (array of ints), value: array of SIDs - * key: target (string), value: running|startup|candidate|url - * Required when target is "url": - * key: url (string), value: URL of datastore to validate - * - * @param $sock - * @param $params - * - * @return int|mixed - */ - public function handle_validate(&$sock, &$params) { - if ( $this->checkLoggedKeys() != 0) { - return 1; - } - - $validateParams = array( - "type" => self::MSG_VALIDATE, - "session" => $this->getHashFromKeys($params['connIds']), - "target" => $params['target'], - ); - $validateParams = $this->addOptionalParams($validateParams, $params, array('url')); - - $decoded = $this->execute_operation($sock, $validateParams); - return $this->checkDecodedData($decoded); - } - - - - /** - * checks, if logged keys are valid - * - * @return int 0 on success, 1 on error - */ - public function checkLoggedKeys() { - $session = $this->container->get('request')->getSession(); - if ( !count($session->get("session-connections")) ) { - $session->getFlashBag()->add('error', "Not logged in."); - return 1; - } - $req = $this->container->get('request'); - - if ( !in_array( $req->get('key'), array_keys($session->get("session-connections")) ) ) { - $session->getFlashBag()->add('error', "You are not allow to see this connection. Bad Index of key."); - return 1; - } - return 0; - } - - /** - * checks decoded data, if there an error occurs - * - * @param mixed &$decoded decoded data - * @return mixed decoded data on success, 1 on error - */ - private function checkDecodedData(&$decoded) { - $session = $this->container->get('request')->getSession(); - $status = $this->getJsonError(); - - if ( $status['errorCode'] ) { - $this->logger->warn('Checking decoded data:', array('error' => $status['message'])); - $session->getFlashBag()->add('error', $status['message']); - return 1; - //} elseif ( $decoded == null ) { - // $this->logger->addError('Could not decode response from socket', array('error' => "Empty response.")); - // $session->getFlashBag()->add('error', "Could not decode response from socket. Error: Empty response."); - // return 1; - } elseif (($decoded['type'] != self::REPLY_OK) && ($decoded['type'] != self::REPLY_DATA)) { - $this->logger->warn('Error: ', array('errors' => $decoded['errors'])); - if (sizeof($decoded['errors'])) { - foreach ($decoded['errors'] as $error) { - $session->getFlashBag()->add('error', $error); - } - } - // throw new \ErrorException($decoded['error-message']); - return 1; - } - return isset($decoded["data"]) ? $decoded["data"] : -1; - } - - /** - * Wrap message for Chunked Framing Mechanism (RFC6242) and write it into the socket. - * - * @param resource &$sock socket descriptor - * @param string $message message text - */ - private function write2socket(&$sock, $message) { - $final_message = sprintf("\n#%d\n%s\n##\n", strlen($message), $message); - fwrite($sock, $final_message); - } - - /** - * executes operation - sends message into the socket - * - * @param resource &$sock socket descriptor - * @param array $params array of values for mod_netconf (type, params...) - * @return array response from mod_netconf - */ - private function execute_operation(&$sock, $params) { - $operation = json_encode($params); - $this->write2socket($sock, $operation); - $response = $this->readnetconf($sock); - return json_decode($response, true); - } - - /** - * Get path to directory of data models. - * - * @return string path to models folder - */ - public function getModelsDir() { - return __DIR__ . '/../Data/models/'; - } - - /** - * gets model dir name for module - * @param string $moduleName name of module - * @return string dir name on success, false on error - */ - public function getModelDirForName($moduleName) { - $key = $this->container->get('request')->get('key'); - $res = $this->getModulePathByRootModuleName($key, $moduleName); - if ($res) { - return $res; - } - return false; - } - - /** - * checks if model dir for module exists - * @param string $moduleName name of module - * @return bool - */ - public function existsModelDirForName($moduleName) { - $key = $this->container->get('request')->get('key'); - $res = $this->getModulePathByRootModuleName($key, $moduleName); - if ($res) { - return true; - } - return false; - } - - /** - * get path to models in file system - * @param string $moduleName name of the module - * @return string path to wrapped model file - */ - public function getPathToModels($moduleName = "") { - $path = $this->getModelsDir(); - - if ($moduleName == "") { - $moduleName = $this->container->get('request')->get('module'); - } - // add module directory if is set in route - if ($moduleName != "") { - $modelDir = $this->getModelDirForName($moduleName); - if ($modelDir) { - $path .= $modelDir . '/'; - } - } - // add subsection directory if is set in route and wrapped file in subsection directory exists - if ( $this->container->get('request')->get('subsection') != null - && file_exists($path . $this->container->get('request')->get('subsection').'/wrapped.wyin')) { - $path .= $this->container->get('request')->get('subsection').'/'; - } - return $path; - } - - /** - * handles all actions, which are allowed on socket - * this is the only one entry point for calling methods such a , , ... - * - * @param string $command kind of action (command) - * @param array $params parameters for mod_netconf - * @param bool $merge should be action handle with merge with model - * @param mixed $result - * @return int 0 on success, 1 on error - */ - public function handle($command, $params = array(), $merge = true, &$result = null) { - $errno = 0; - $errstr = ""; - - $logParams = $params; - if ( $command == "connect" ) { - // we won't log password - unset($logParams['pass']); - } - $this->logger->info('Handle: '.$command.' with params', array('params' => $logParams)); - - /** - * check, if current command had not been called in the past. If yes, we will - * return previous response (and not ask again for response from server). - */ - $hashedParams = sha1(json_encode($params)); -// if (isset($this->handleResultsArr[$command])) { -// -// if ($merge && isset($this->handleResultsArr[$command][$hashedParams]['merged'])) { -// return $this->handleResultsArr[$command][$hashedParams]['merged']; -// } elseif (isset($this->handleResultsArr[$command][$hashedParams]['unmerged'])) { -// return $this->handleResultsArr[$command][$hashedParams]['unmerged']; -// } -// } - - $socket_path = '/var/run/netopeerguid.sock'; - if (!file_exists($socket_path)) { - $this->logger->addError('Backend is not running or socket file does not exist.', array($socket_path)); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Backend is not running or socket file does not exist: ".$socket_path); - return 1; - } - if (!is_readable($socket_path)) { - $this->logger->addError('Socket is not readable.', array($socket_path)); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Socket is not readable: ".$socket_path); - return 1; - } - if (!is_writable($socket_path)) { - $this->logger->addError('Socket is not writable.', array($socket_path)); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Socket is not writable: ".$socket_path); - return 1; - } - $socket_path = 'unix://'.$socket_path; - try { - $sock = fsockopen($socket_path, NULL, $errno, $errstr); - } catch (\ErrorException $e) { - $this->logger->addError('Could not connect to socket.', array($errstr)); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not connect to socket. Error: $errstr"); - return 1; - } - - if ($errno != 0) { - $this->logger->addError('Could not connect to socket.', array($errstr)); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not connect to socket. Error: $errstr"); - return 1; - } - //stream_set_timeout($sock, 5, 500); - stream_set_blocking($sock, 1); - - switch ($command) { - case "connect": - $res = $this->handle_connect($sock, $params, $result); - break; - case "disconnect": - $res = $this->handle_disconnect($sock, $params); - break; - case "get": - $res = $this->handle_get($sock, $params); - break; - case "getconfig": - $res = $this->handle_getconfig($sock, $params); - break; - case "editconfig": - $this->logger->info("Handle editConfig: ", array('configToSend' => $params['config'])); - $this->container->get('XMLoperations')->validateXml($params['config']); - $res = $this->handle_editconfig($sock, $params); - break; - case "copyconfig": - $res = $this->handle_copyconfig($sock, $params); - break; - case "deleteconfig": - $res = $this->handle_deleteconfig($sock, $params); - break; - case "lock": - $res = $this->handle_lock($sock, $params); - break; - case "unlock": - $res = $this->handle_unlock($sock, $params); - break; - case "killsession": - $res = $this->handle_killsession($sock, $params, $result); - break; - case "info": - $res = $this->handle_info($sock, $params); - break; - case "userrpc": - case "generic": - $res = $this->handle_generic($sock, $params, $result); - break; - case "getschema": - $res = $this->handle_getschema($sock, $params, $result); - break; - case "reloadhello": - $res = $this->handle_reloadhello($sock, $params); - break; - case "notif_history": - // JSON encoded data OR 1 on error, so we can return it now - return $this->handle_notif_history($sock, $params); - break; - case "validate": - $res = $this->handle_validate($sock, $params, $result); - break; - case "backup": - $params["source"] = "startup"; - $res_startup = "".$this->handle_getconfig($sock, $params).""; - $params["source"] = "running"; - $res_running = "".$this->handle_getconfig($sock, $params).""; - $params["source"] = "candidate"; - $res_candidate = "".$this->handle_getconfig($sock, $params).""; - $res = "".$res_startup.$res_running.$res_candidate.""; - return $res; - default: - $this->container->get('request')->getSession()->getFlashBag()->add('info', printf("Command not implemented yet. (%s)", $command)); - return 1; - } - - fclose($sock); - $this->logger->info("Handle result: ".$command, array('response' => $res)); - - if ($command === "info") { - $this->handleResultsArr['info'] = $res; - } - - if ( isset($res) && $res !== 1 && $res !== -1) { - if (!$this->container->get('XMLoperations')->isResponseValidXML($res)) { - $this->container->get('request')->getSession()->getFlashBag()->add( 'error', "Requested XML from server is not valid."); - return 0; - } - - if ($merge) { - $res = $this->container->get('XMLoperations')->mergeXMLWithModel($res); - if ($res !== -1) { - $this->handleResultsArr[$command][$hashedParams]['merged'] = $res; - } else { - return $res; - } - } else { - $this->handleResultsArr[$command][$hashedParams]['unmerged'] = $res; - } - - return $res; - } else if ($res !== -1) { - return 1; - } - return 0; - } - - - /** - * Prepares top menu - gets items from server response - * - * @param int $key session key of current connection - * @param string $path - */ - public function buildMenuStructure($key, $path = "") { - - // we will build menu structure only if we have not build it before - if ( !$this->getModels($key) || !$this->getModelNamespaces($key) ) { - $finder = new Finder(); - - $params = array( - 'key' => $key, - 'source' => 'running', - 'filter' => "", - ); - - $allowedModels = array(); - $allowedSubmenu = array(); - $namespaces = array(); - - try { - // load GET XML from server - if ( ($xml = $this->handle('get', $params, false)) != 1 ) { - $xml = simplexml_load_string($xml, 'SimpleXMLIterator'); - - $xmlNameSpaces = $xml->getNamespaces(); - - if ( isset($xmlNameSpaces[""]) ) { - $xml->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - $nodes = $xml->xpath('/xmlns:*'); - } else { - $nodes = $xml->xpath('/*'); - } - - // get first level nodes (so without root) as items for top menu - foreach ($nodes as $node) { - foreach ($node as $nodeKey => $submenu) { - $ns = $submenu->getNameSpaces(); - $i = 0; - if (isset($namespaces[$nodeKey])) { - $i = 1; - while(isset($namespaces[$nodeKey.$i])) { - $i++; - } - $namespaces[$nodeKey.$i] = $ns[""]; - } else { - $namespaces[$nodeKey] = $ns[""]; - } - - if (!in_array(array("name" => $nodeKey, 'index' => $i), $allowedModels) ) { - $allowedModels[] = array("name" => $nodeKey, 'index' => $i); - } - - foreach ($submenu as $subKey => $tmp) { - if ( !in_array(array("name" => $subKey, 'index' => 0), $allowedSubmenu) ) { - $allowedSubmenu[] = array("name" => $subKey, 'index' => 0); - } - } - } - } - } - } catch (\ErrorException $e) { - $this->logger->addError("Could not build MenuStructure", array('key' => $key, 'path' => $path, 'error' => $e->getMessage())); - // nothing - } - $this->setModelNamespaces($key, $namespaces); - - - // we will check, if nodes from GET are same as models structure - // if not, they won't be displayed - $folders = array(); - sort($allowedModels); - foreach ($allowedModels as $module) { - $moduleWithIndex = $module['name']; - if ($module['index'] !== 0) { - $moduleWithIndex .= $module['index']; - } - if ($this->existsModelDirForName($moduleWithIndex)) { - $folders[$moduleWithIndex] = array( - 'path' => "module", - "params" => array( - 'key' => $key, - 'module' => $moduleWithIndex, - ), - "title" => "detail of ".$this->getSectionName($module['name']), - "name" => $this->getSectionName($module['name']), - "children" => $this->buildSubmenu($key, $module, $allowedSubmenu), - "namespace" => $namespaces[$moduleWithIndex], - ); - } - } - $this->setModels($key, $folders); - } - } - - /** - * prepares left submenu - modules of current top menu item - * - * @param int $key session key of current connection - * @param array $module array with indexes: name and index - * @param $allowedSubmenu - * @param string $path - * @return array - */ - private function buildSubmenu($key, $module, $allowedSubmenu, $path = "") { - $finder = new Finder(); - - $moduleWithIndex = $module['name']; - if ($module['index'] !== 0) { - $moduleWithIndex .= $module['index']; - } - - // we will check, if nodes from GET are same as models structure - // if not, they won't be displayed - $dir = $this->getPathToModels($moduleWithIndex); - if ( !file_exists($dir) ) { - $folders = array(); - } else { - $iterator = $finder - ->directories() - ->sortByName() - ->depth(0) - ->in($dir); - - $folders = array(); - foreach ($iterator as $folder) { - $subsection = $folder->getRelativePathname(); - if ( in_array(array("name" => $subsection, "index" => 0), $allowedSubmenu) ) { - $folders[] = array( - 'path' => "subsection", - "params" => array( - 'key' => $key, - 'module' => $moduleWithIndex, - 'subsection' => $subsection, - ), - "title" => "detail of ".$this->getSubsectionName($subsection), - "name" => $this->getSubsectionName($subsection), - // "children" => $this->getSubmenu($key, $completePath), - ); - } - } - } - return $folders; - } - - /** - * loading file with filter specification for current module or subsection - * - * @param string $module module name - * @param string $subsection subsection name - * @return array array with config and state filter - */ - public function loadFilters(&$module, &$subsection) { - // if file filter.txt exists in models, we will use it - $filterState = $filterConfig = ""; - - $namespaces = $this->getModelNamespaces($this->container->get('request')->get('key')); - if (isset($namespaces[$module])) { $namespace = $namespaces[$module]; - $filter = new \SimpleXMLElement("<".$module.">"); - $filter->addAttribute('xmlns', $namespace); - if ( $subsection ) { - $filter->addChild($subsection); - } - - $filterState = $filterConfig = str_replace('', '', $filter->asXml()); - } - - return array( - 'config' => $filterConfig, - 'state' => $filterState - ); - } - - /** - * loading file with RPCs for current module or subsection - * - * @param string $module module name - * @param string $subsection subsection name - * @return array array with config and state filter - */ - public function loadRPCsModel($module, $subsection) { - $path = $this->getPathToModels($module); - $file = $path.'rpc.wyin'; - - $rpcs_model = ""; - if ( file_exists($file) ) { - $rpcs_model = file_get_contents($file); - } - - return array( - 'rpcs' => $rpcs_model, - ); - } - - /** - * Get models. - * - * @param int $key session key of current connection - * @return array|null - */ - public function getModels($key = -1) { - /** - * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache - */ - $cache = $this->container->get('winzou_cache'); - - if ($key === -1) { - $key = $this->container->get('request')->get('key'); - } - $hashedKey = $this->getHashFromKeys($key); - if ($hashedKey && $cache->contains('menuStructure_'.$hashedKey)) { -// $this->logger->addInfo("Cached file for menuStructure found.", array('key' => 'menuStructure_'.$hashedKey)); - return $cache->fetch('menuStructure_'.$hashedKey); - } - return $this->models; - } - - /** - * save model folder structure - * - * @param int $key session key of current connection - * @param array $folders array to persist - * @param int $lifetime cache lifetime in seconds - */ - public function setModels($key, $folders, $lifetime = 6000) { - /** - * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache - */ - $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKeys($key); - $this->models = $folders; - $cache->save('menuStructure_'.$hashedKey, $folders, $lifetime); - } - - /** - * Get model namespaces. - * - * @param int $key session key of current connection - * @return array|null - */ - public function getModelNamespaces($key) { - /** - * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache - */ - $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKeys($key); - if ($hashedKey && $cache->contains('modelNamespaces_'.$hashedKey)) { -// $this->logger->addInfo("Cached file for modelNamespaces found.", array('key' => 'modelNamespaces_'.$hashedKey)); - return $cache->fetch('modelNamespaces_'.$hashedKey); - } - return $this->modelNamespaces; - } - - /** - * get namespace for given module name - * - * @param int $key ID of connection - * @param string $module name of module - * - * @return bool - */ - public function getNamespaceForModule($key, $module) { - $namespaces = $this->getModelNamespaces($key); - if (isset($namespaces[$module])) { - return $namespaces[$module]; - } else { - return false; - } - } - - /** - * save model folder structure - * - * @param int $key session key of current connection - * @param array $namespaces array of namespaces to persist - * @param int $lifetime cache lifetime in seconds - */ - public function setModelNamespaces($key, $namespaces, $lifetime = 6000) { - /** - * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache - */ - $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKeys($key); - $this->modelNamespaces = $namespaces; - $cache->save('modelNamespaces_'.$hashedKey, $namespaces, $lifetime); - } - - /** - * Invalidates and rebuild menu structure - * - * @param $key Identifier of connection (connected device ID) - */ - public function invalidateAndRebuildMenuStructureForKey($key) { - $this->invalidateMenuStructureForKey($key); - $this->buildMenuStructure($key); - } - - /** - * Invalidates cached files for menu structure - * - * @param int $key session key of current connection - */ - public function invalidateMenuStructureForKey($key) { - /** - * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache - */ - $cache = $this->container->get('winzou_cache'); - $hashedKey = $this->getHashFromKeys($key); - if ($hashedKey && $cache->contains('modelNamespaces_'.$hashedKey)) { - $this->logger->addInfo("Invalidate cached file", array('key' => 'modelNamespaces_'.$hashedKey)); - $cache->delete('modelNamespaces_'.$hashedKey); - } - if ($hashedKey && $cache->contains('menuStructure_'.$hashedKey)) { - $this->logger->addInfo("Invalidate cached file", array('key' => 'menuStructure_'.$hashedKey)); - $cache->delete('menuStructure_'.$hashedKey); - } - $cache->deleteDeads(); - } - - /** - * Get model tree file from models dir. - * - * @param string $moduleName - * - * @return string|int - */ - public function getModelTreeDump($moduleName = '') - { - $path = $this->getPathToModels($moduleName).'tree.txt'; - - if (file_exists($path)) { - return file_get_contents($path); - } - - return 0; - } - - /** - * Loads file with identities for identity refs and loads content of this file with json_decode - * - * @return array|int 0 on error, json decoded array on success - */ - public function loadIdentityRefs() { - $path = $this->getModelsDir(); - - // identites.json is located in tmp dir - $path .= 'tmp/identities.json'; - - if ($content = file_get_contents($path)) { - return json_decode($content, true); - } - - return 0; - } - - /** - * Loads only identity refs for given module - * - * @param $key - * @param $module - * - * @return array|int - */ - public function loadIdentityRefsForModule($key, $module) { - $idrefs = $this->loadIdentityRefs(); - $identities = array(); - - if ($idrefs) { - $ns = $this->getNamespaceForModule($key, $module); - $prefix = array_search($ns, $idrefs['prefixes']); - if ($prefix) { - foreach ($idrefs['identities'] as $key => $values) { - if (strpos($key, $prefix.":") === 0) { - asort($values); - $identities[str_replace($prefix.":", '', $key)] = $values; - } - } - } - - return $identities; - } - - return 0; - } - - /** - * Get one model and process it. - * - * @param array &$schparams key, identifier, version, format for get-schema - * @param string $identifier identifier of folder in modelsDir directory - * @return int 0 on success, 1 on error - */ - private function getschema(&$schparams, $identifier) - { - $data = ""; - $path = $this->getModelsDir()."/tmp/"; - @mkdir($path, 0700, true); - $path .= "/$identifier"; - - if (file_exists($path)) { - /* already exists */ - $schparams["path"] = $path; - return -1; - } - - if ($this->handle("getschema", $schparams, false, $data) == 0) { - $schparams["user"] = $this->getUserFromKey($schparams["key"]); - file_put_contents($path, $data); - $schparams["path"] = $path; - return 0; - } else { - $this->container->get('request')->getSession()->getFlashBag()->add('error', 'Getting models failed.'); - return 1; - } - return 0; - } - - /** - * Process action based on schparams. - * - * @param array &$schparams get-schema parameters - * @return int 0 on success, 1 on error - */ - private function processSchema(&$schparams) - { - $path = $schparams["path"]; - - $res = @system(__DIR__."/../bin/nmp.sh -i \"$path\" -o \"".$this->getModelsDir()."\""); - ob_clean(); - $this->logger->addInfo("Process schema result (Pyang console): ", array('path' => $path, 'modelDir' => $this->getModelsDir(), 'res' => $res)); - return 1; - } - - /** - * Get available configuration data models, - * store them and transform them. - * - * @param int $key index of session-connection - * @return void - */ - public function updateLocalModels($key) - { - $ns = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"; - $params = array( - 'key' => $key, - 'filter' => 'yinNETCONF', - ); - - $xml = $this->handle('get', $params, false); - // TODO: try/catch na simplexml_load_string - if (($xml !== 1) && ($xml !== "")) { - $xml = simplexml_load_string($xml, 'SimpleXMLIterator'); - if ($xml === false) { - /* invalid message received */ - $this->container->get('request')->getSession()->getFlashBag()->add('error', 'Getting the list of schemas failed.'); - return; - } - $xml->registerXPathNamespace("xmlns", $ns); - $schemas = $xml->xpath("//xmlns:schema"); - - $this->logger->addInfo("Trying to find models for namespaces: ", array('namespaces' => var_export($schemas, true))); - - $list = array(); - $lock = sem_get(12345678, 1, 0666, 1); - sem_acquire($lock); /* critical section */ - foreach ($schemas as $sch) { - $schparams = array("key" => $params["key"], - "identifier" => (string)$sch->identifier, - "version" => (string)$sch->version, - "format" => (string)$sch->format); - $ident = $schparams["identifier"]."@".$schparams["version"].".".$schparams["format"]; - if (file_exists($this->getModelsDir()."/$ident")) { - $this->addLog("Model found, skipping: ", array('ident', $ident)); - continue; - } else if ($this->getschema($schparams, $ident) == -1) { - $this->logger->addInfo("Get schema file found, but no models.", array("ident" => $ident)); - $list[] = $schparams; - } else if ($this->getschema($schparams, $ident) == 1) { - continue; // get schema failed, skipping - } else { - $list[] = $schparams; - } - } - sem_release($lock); - - - $res = @system(__DIR__."/../bin/find-identities.sh '".$this->getModelsDir()."/tmp/'"); - ob_clean(); - /* non-critical - only models, that I downloaded will be processed, others already exist */ - foreach ($list as $schema) { - $this->processSchema($schema); - } - $this->container->get('request')->getSession()->getFlashBag()->add('success', 'Configuration data models were updated.'); - } else { - $this->container->get('request')->getSession()->getFlashBag()->add('error', 'Getting the list of schemas failed.'); - } - } - - /** - * Get submenu for key. - * - * @param string $index index in array of submenu structure - * @param int $key session key of current connection - * @return array - */ - public function getSubmenu($index, $key) { - $models = $this->getModels($key); - return isset($models[$index]['children']) ? $models[$index]['children'] : array(); - } - - /** - * Get name for section. - * - * @param $section - * @return string - */ - public function getSectionName($section) { - return ucfirst( str_replace(array('-', '_'), ' ', $section) ); - } - - /** - * Get name for subsection. - * - * @param $subsection - * @return string - */ - public function getSubsectionName($subsection) { - return $this->getSectionName($subsection); - } - - /** - * Get identificator (hash) of model - it is used as directory name of model - * - * @param string $name module name from conf. model - * @param string $version version of conf. model - * @param string $ns namespace - * @return string hashed identificator - */ - public function getModelIdentificator($name, $version, $ns) - { -// $ident = "$name|$version|$ns"; - $ident = $ns; - return sha1($ident); - } - - /** - * Add text to info log. - * - * @param $str - */ - private function addLog($str) { - $this->logger->addInfo($str); - } - -} diff --git a/src/FIT/NetopeerBundle/Resources/config/functionality.yml b/src/FIT/NetopeerBundle/Resources/config/functionality.yml new file mode 100644 index 00000000..eb24e86f --- /dev/null +++ b/src/FIT/NetopeerBundle/Resources/config/functionality.yml @@ -0,0 +1,51 @@ +# @author David Alexa +# +# Copyright (C) 2012-2015 CESNET +# +# LICENSE TERMS +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of the Company nor the names of its contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# ALTERNATIVELY, provided that this notice is retained in full, this +# product may be distributed under the terms of the GNU General Public +# License (GPL) version 2 or later, in which case the provisions +# of the GPL apply INSTEAD OF those given above. +# +# This software is provided ``as is'', and any express or implied +# warranties, including, but not limited to, the implied warranties of +# merchantability and fitness for a particular purpose are disclaimed. +# In no event shall the company or contributors be liable for any +# direct, indirect, incidental, special, exemplary, or consequential +# damages (including, but not limited to, procurement of substitute +# goods or services; loss of use, data, or profits; or business +# interruption) however caused and on any theory of liability, whether +# in contract, strict liability, or tort (including negligence or +# otherwise) arising in any way out of the use of this software, even +# if advised of the possibility of such damage. + +services: + fitnetopeerbundle.service.connection.functionality: + class: FIT\NetopeerBundle\Services\Functionality\ConnectionFunctionality + calls: + - [setLogger, [@data_logger]] + - [setCache, [@winzou_cache]] + - [setSession, [@session]] + - [setContainer, [@service_container]] + - [setEntityManager, [@doctrine.orm.entity_manager]] + fitnetopeerbundle.service.netconf.functionality: + class: %netopeer.netconf.functionality% + calls: + - [setLogger, [@data_logger]] + - [setSession, [@session]] + - [setConnectionFunctionality, [@fitnetopeerbundle.service.connection.functionality]] \ No newline at end of file diff --git a/src/FIT/NetopeerBundle/Resources/config/services.yml b/src/FIT/NetopeerBundle/Resources/config/services.yml index ebdf66f8..1124030d 100644 --- a/src/FIT/NetopeerBundle/Resources/config/services.yml +++ b/src/FIT/NetopeerBundle/Resources/config/services.yml @@ -33,7 +33,10 @@ # in contract, strict liability, or tort (including negligence or # otherwise) arising in any way out of the use of this software, even # if advised of the possibility of such damage. - + +imports: + - { resource: "functionality.yml" } + services: data_logger: class: Symfony\Bridge\Monolog\Logger @@ -42,20 +45,16 @@ services: - [pushHandler, [@data_handler]] data_handler: - class: Monolog\Handler\StreamHandler + class: Monolog\Handler\StreamHandler arguments: [%kernel.logs_dir%/%kernel.environment%.data.log] authentication_handler: class: FIT\NetopeerBundle\Handler\AuthenticationHandler - arguments: [@service_container, @data_logger, @DataModel] - - DataModel: - class: %netopeer.data.class% - arguments: [@service_container, @data_logger] + arguments: [@service_container] - XMLoperations: - class: FIT\NetopeerBundle\Models\XMLoperations - arguments: [@service_container, @data_logger, @DataModel] +# XMLoperations: +# class: FIT\NetopeerBundle\Models\XMLoperations +# arguments: [@service_container, @data_logger, @fitnetopeerbundle.service.netconf.functionality] BaseConnection: class: FIT\NetopeerBundle\Entity\BaseConnection @@ -72,7 +71,7 @@ services: moduleListener: class: FIT\NetopeerBundle\EventListener\ModuleListener - arguments: [@DataModel, @doctrine.orm.entity_manager, @data_logger] + arguments: [@fitnetopeerbundle.service.connection.functionality, @doctrine.orm.entity_manager, @data_logger] tags: - { name: kernel.event_listener, event: kernel.request, method: onKernelController } @@ -82,14 +81,4 @@ services: class: %winzou_cache.driver.abstract% arguments: - file # just modify this value to use another cache - #- {'cache_dir': /tmp/cache } # you can omit this if you don't use FileCache or if the default value is ok for you - - ajaxController: - class: FIT\NetopeerBundle\Controller\AjaxController - arguments: - container: "@service_container" - - securityController: - class: FIT\NetopeerBundle\Controller\SecurityController - arguments: - container: "@service_container" + #- {'cache_dir': /tmp/cache } # you can omit this if you don't use FileCache or if the default value is ok for you \ No newline at end of file diff --git a/src/FIT/NetopeerBundle/Resources/views/Default/connections.html.twig b/src/FIT/NetopeerBundle/Resources/views/Default/connections.html.twig index e20e84f2..5288ae85 100644 --- a/src/FIT/NetopeerBundle/Resources/views/Default/connections.html.twig +++ b/src/FIT/NetopeerBundle/Resources/views/Default/connections.html.twig @@ -39,33 +39,6 @@ if advised of the possibility of such damage. {% extends 'FITNetopeerBundle::layout.html.twig' %} {% block javascripts %} - {% if (getSchemaWithAjax is defined and getSchemaWithAjax == true) %} - {#% set idForAjaxGetSchema = 0 %#} - - {% endif %} #} + + + + + + + + + {#'@FITModuleDefaultBundle/Resources/public/js/tooltip/gips.js'#} + {#'@FITModuleDefaultBundle/Resources/public/js/*'#} {% javascripts - '@FITModuleDefaultBundle/Resources/public/js/tooltip/gips.js' - '@FITModuleDefaultBundle/Resources/public/js/*' + '@FITModuleDefaultBundle/Resources/public/netopeerangular/js/directives2.js' + '@FITModuleDefaultBundle/Resources/public/netopeerangular/js/directives/*' + '@FITModuleDefaultBundle/Resources/public/netopeerangular/js/*' + '@FITModuleDefaultBundle/Resources/public/netopeerangular/public/*' output='js/compiled/module-default.js' %} {% endjavascripts %} + + {% endblock %} {% block moduleStylesheet %} {% stylesheets - 'bundles/fitmoduledefault/style/*' + 'bundles/fitmoduledefault/netopeerangular/css/stylesheets/screen.css' filter='cssrewrite' output='css/module-default.css' %} diff --git a/src/FIT/NetopeerBundle/Resources/views/layout.html.twig b/src/FIT/NetopeerBundle/Resources/views/layout.html.twig index 786839bf..a66ab72f 100644 --- a/src/FIT/NetopeerBundle/Resources/views/layout.html.twig +++ b/src/FIT/NetopeerBundle/Resources/views/layout.html.twig @@ -38,7 +38,7 @@ if advised of the possibility of such damage. - + diff --git a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php index 73b02b5c..98593443 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php @@ -420,17 +420,24 @@ private function handle_disconnect(&$sock, &$params) { "sessions" => array_keys($sessionKeys) )); - foreach ($decoded as $sid => $response) { - if ($response["type"] === self::REPLY_OK) { - $session->getFlashBag()->add('success', "Session ".$sid." successfully disconnected."); - } else { - $this->getLogger()->addError("Could not disconnect.", array("error" => var_export($response, true))); - $session->getFlashBag()->add('error', "Could not disconnect session ".$sid." from server. "); - } + if (sizeof($decoded)) { + foreach ( $decoded as $sid => $response ) { + if ( $response["type"] === self::REPLY_OK ) { + $session->getFlashBag()->add( 'success', "Session " . $sid . " successfully disconnected." ); + } else { + $this->getLogger()->addError( "Could not disconnect.", + array( "error" => var_export( $response, true ) ) ); + $session->getFlashBag()->add( 'error', "Could not disconnect session " . $sid . " from server. " ); + } - $key = array_search($sid, $sessionKeys); - if ($key) { - unset( $sessionConnections[$key] ); + $key = array_search( $sid, $sessionKeys ); + if ( $key ) { + unset( $sessionConnections[ $key ] ); + } + } + } else { + foreach ($params['connIds'] as $key) { + unset( $sessionConnections[ $key ] ); } } @@ -941,6 +948,11 @@ private function checkDecodedData(&$decoded) { return 1; } + if (!sizeof($decoded)) { + $session->getFlashBag()->add('error', 'Empty response'); + return 1; + } + foreach ($decoded as $sid => $response) { if (($response['type'] != self::REPLY_OK) && ($response['type'] != self::REPLY_DATA)) { $this->getLogger()->addWarning('Error: ', array('errors' => $response['errors'])); From 00422f0eb729b8bf1592a15d904da7122fafb947 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 26 Jan 2016 11:05:51 +0100 Subject: [PATCH 017/113] removes unnecessary classes form XML operations --- .../Controller/AjaxController.php | 161 +- .../Controller/DefaultController.php | 9 +- src/FIT/NetopeerBundle/Data/models/.gitignore | 1 - .../NetopeerBundle/Data/models/tmp/.gitignore | 1 - .../NetopeerBundle/Models/AjaxSharedData.php | 105 - src/FIT/NetopeerBundle/Models/Array2XML.php | 225 --- src/FIT/NetopeerBundle/Models/MergeXML.php | 391 ---- .../NetopeerBundle/Models/XMLoperations.php | 1721 ----------------- 8 files changed, 10 insertions(+), 2604 deletions(-) delete mode 100644 src/FIT/NetopeerBundle/Data/models/.gitignore delete mode 100644 src/FIT/NetopeerBundle/Data/models/tmp/.gitignore delete mode 100644 src/FIT/NetopeerBundle/Models/AjaxSharedData.php delete mode 100644 src/FIT/NetopeerBundle/Models/Array2XML.php delete mode 100644 src/FIT/NetopeerBundle/Models/MergeXML.php delete mode 100644 src/FIT/NetopeerBundle/Models/XMLoperations.php diff --git a/src/FIT/NetopeerBundle/Controller/AjaxController.php b/src/FIT/NetopeerBundle/Controller/AjaxController.php index 134fa389..e6f2ecc0 100644 --- a/src/FIT/NetopeerBundle/Controller/AjaxController.php +++ b/src/FIT/NetopeerBundle/Controller/AjaxController.php @@ -43,8 +43,6 @@ namespace FIT\NetopeerBundle\Controller; use FIT\NetopeerBundle\Controller\BaseController; -use FIT\NetopeerBundle\Models\AjaxSharedData; -use FIT\NetopeerBundle\Models\XMLoperations; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -55,59 +53,6 @@ */ class AjaxController extends BaseController { - /** - * Change session value for showing single or double column layout - * - * @Route("/ajax/get-schema/{key}", name="getSchema") - * - * @param int $key session key of current connection - * @return \Symfony\Component\HttpFoundation\Response - */ - public function getSchemaAction($key) - { - /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass - */ - $dataClass = $this->get('DataModel'); - $schemaData = AjaxSharedData::getInstance(); - - ob_start(); - $data = $schemaData->getDataForKey($key); - if (!(isset($data['isInProgress']) && $data['isInProgress'] === true)) { - $dataClass->updateLocalModels($key); - } - $output = ob_get_clean(); - $result['output'] = $output; - - return $this->getSchemaStatusAction($key, $result); - } - - /** - * Get status of get-schema operation - * - * @Route("/ajax/get-schema-status/{key}", name="getSchemaStatus") - * - * @param int $key session key of current connection - * @param array $result - * @return \Symfony\Component\HttpFoundation\Response - */ - public function getSchemaStatusAction($key, $result = array()) - { - $schemaData = AjaxSharedData::getInstance(); - - $data = $schemaData->getDataForKey($key); - if (isset($data['isInProgress']) && $data['isInProgress'] === true) { - $schemaData->setDataForKey($key, 'status', "in progress"); - } - - $data = $schemaData->getDataForKey($key); - $flashes = $this->getRequest()->getSession()->getFlashBag()->all(); - $result['message'] = $flashes; - $result['key'] = $key; - - return new Response(json_encode($result)); - } - /** * Get history of connected devices * @@ -238,96 +183,6 @@ public function connectedDeviceAttrAction($connectedDeviceId) } } - /** - * Get available values for label name from model based on xPath selector. - * - * @Route("/ajax/get-values-for-label/{formId}/{key}/{xPath}/", name="getValuesForLabel") - * @Route("/ajax/get-values-for-label/{formId}/{key}/{module}/{xPath}/", name="getValuesForLabelWithModule") - * @Route("/ajax/get-values-for-label/{formId}/{key}/{module}/{subsection}/{xPath}/", name="getValuesForLabelWithSubsection") - * @Template() - * - * @param int $key - * @param string $formId unique identifier of form - * @param null|string $module name of the module - * @param null|string $subsection name of the subsection - * @param string $xPath encoded xPath selector - * @return Response $result - */ - public function getValuesForLabelAction($key, $formId, $xPath = "", $module = null, $subsection = null) - { - $this->setActiveSectionKey($key); - $this->get('DataModel')->buildMenuStructure($key); - - /** - * @var XMLoperations $xmlOp - */ - $xmlOp = $this->get('XMLoperations'); - $formParams = $this->get('DataModel')->loadFilters($module, $subsection); - - $res = $xmlOp->getAvailableLabelValuesForXPath($formId, $xPath); - - // path for creating node typeahead - $typeaheadParams = array( - 'formId' => "FORMID", - 'key' => $key, - 'xPath' => "XPATH" - ); - $valuesTypeaheadPath = $this->generateUrl('getValuesForLabel', $typeaheadParams); - if (!is_null($module)) { - $typeaheadParams['module'] = $module; - $valuesTypeaheadPath = $this->generateUrl('getValuesForLabelWithModule', $typeaheadParams); - } - if (!is_null($subsection)) { - $typeaheadParams['subsection'] = $subsection; - $valuesTypeaheadPath = $this->generateUrl('getValuesForLabelWithSubsection', $typeaheadParams); - } - - if (is_array($res)) { - if (isset($_GET['command']) && isset($_GET['label'])) { - if ($_GET['command'] == 'attributesAndValueElem') { - $retArr = array(); - if (isset($res['labelsAttributes'][$_GET['label']])) { - $retArr['labelAttributes'] = $res['labelsAttributes'][$_GET['label']]; - } - - if (isset($res['elems'][$_GET['label']])) { - $template = $this->get('twig')->loadTemplate('FITModuleDefaultBundle:Config:leaf.html.twig'); - $twigArr = array(); - - $twigArr['key'] = ""; - $twigArr['xpath'] = ""; - $twigArr['valuesTypeaheadPath'] = $valuesTypeaheadPath; - $twigArr['element'] = $res['elems'][$_GET['label']]; - $twigArr['useHiddenInput'] = true; - - // load identity refs array - $identities = $this->get('DataModel')->loadIdentityRefsForModule($key, $module); - if ($identities) { - $twigArr['moduleIdentityRefs'] = $identities; - } - - $html = $xmlOp->removeMultipleWhitespaces($template->renderBlock('configInputElem', $twigArr)); - $retArr['valueElem'] = $html; - - $html = $xmlOp->removeMultipleWhitespaces($template->renderBlock('editBar', $twigArr)); - $retArr['editBar'] = $html; - - $children = $xmlOp->getChildrenValues($twigArr['element'], $template, $formId, $xPath, "", $identities); - $retArr['children'] = $children; - } - - return new Response(json_encode($retArr)); - } else { - return new Response(false); - } - } else { - return new Response(json_encode($res['labels'])); - } - } else { - return new Response(false); - } - } - /** * Process getting history of notifications * @@ -345,19 +200,14 @@ public function getValuesForLabelAction($key, $formId, $xPath = "", $module = nu */ public function getNotificationsHistoryAction($connectedDeviceId, $from = null, $to = 0, $max = 50) { - //return $this->getTwigArr(); // TODO: remove, when will be working fine - - /** - * @var \FIT\NetopeerBundle\Models\Data $dataClass - */ - $dataClass = $this->get('DataModel'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $params['key'] = $connectedDeviceId; $params['from'] = ($from ? $from : time() - 12 * 60 * 60); $params['to'] = $to; $params['max'] = $max; - $history = $dataClass->handle("notificationsHistory", $params); + $history = $netconfFunc->handle("notificationsHistory", $params); // $history is 1 on error (we will show flash message) or array on success if ($history !== 1) { @@ -379,10 +229,11 @@ public function getNotificationsHistoryAction($connectedDeviceId, $from = null, */ public function validateSource($key, $target, $module) { - $dataClass = $this->get('DataModel'); + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); $subsection = null; - $filters = $dataClass->loadFilters($module, $subsection); + $filters = $connectionFunc->loadFilters($module, $subsection); $params = array( 'key' => $key, @@ -390,7 +241,7 @@ public function validateSource($key, $target, $module) 'target' => $target ); - $res = $dataClass->handle('validate', $params, false); + $res = $netconfFunc->handle('validate', $params, false); $this->getRequest()->getSession()->getFlashBag()->add('state '.(!$res ? 'success' : 'error'), 'Datastore '.$target.' is '.($res ? 'in' : '').'valid.'); $this->addAjaxBlock('FITModuleDefaultBundle:Module:section.html.twig', 'alerts'); $this->assign('dataStore', $target); diff --git a/src/FIT/NetopeerBundle/Controller/DefaultController.php b/src/FIT/NetopeerBundle/Controller/DefaultController.php index 0d7eabf9..8aaeda86 100644 --- a/src/FIT/NetopeerBundle/Controller/DefaultController.php +++ b/src/FIT/NetopeerBundle/Controller/DefaultController.php @@ -44,9 +44,6 @@ namespace FIT\NetopeerBundle\Controller; -use FIT\NetopeerBundle\Models\Array2XML; - -// these import the "@Route" and "@Template" annotations use FIT\NetopeerBundle\Services\Functionality\NetconfFunctionality; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; @@ -388,6 +385,8 @@ public function sessionInfoAction($key, $action) $this->addAjaxBlock('FITModuleDefaultBundle:Module:section.html.twig', 'topMenu'); $this->addAjaxBlock('FITModuleDefaultBundle:Module:section.html.twig', 'leftColumn'); + // TODO + if ( $action == "session" ) { /** * @var Session $session @@ -432,8 +431,8 @@ public function sessionInfoAction($key, $action) unset($sessionArr['_security_secured_area']); unset($sessionArr['_security_commont_context']); - $xml = Array2XML::createXML("session", $sessionArr); - $xml = simplexml_load_string($xml->saveXml(), 'SimpleXMLIterator'); +// $xml = Array2XML::createXML("session", $sessionArr); +// $xml = simplexml_load_string($xml->saveXml(), 'SimpleXMLIterator'); $this->assign("stateArr", $xml); $this->assign('hideStateSubmitButton', true); diff --git a/src/FIT/NetopeerBundle/Data/models/.gitignore b/src/FIT/NetopeerBundle/Data/models/.gitignore deleted file mode 100644 index 13e4d83e..00000000 --- a/src/FIT/NetopeerBundle/Data/models/.gitignore +++ /dev/null @@ -1 +0,0 @@ -[^.]* diff --git a/src/FIT/NetopeerBundle/Data/models/tmp/.gitignore b/src/FIT/NetopeerBundle/Data/models/tmp/.gitignore deleted file mode 100644 index 13e4d83e..00000000 --- a/src/FIT/NetopeerBundle/Data/models/tmp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -[^.]* diff --git a/src/FIT/NetopeerBundle/Models/AjaxSharedData.php b/src/FIT/NetopeerBundle/Models/AjaxSharedData.php deleted file mode 100644 index f3bd58c4..00000000 --- a/src/FIT/NetopeerBundle/Models/AjaxSharedData.php +++ /dev/null @@ -1,105 +0,0 @@ - - * - * Copyright (C) 2012-2015 CESNET - * - * LICENSE TERMS - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of the Company nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * ALTERNATIVELY, provided that this notice is retained in full, this - * product may be distributed under the terms of the GNU General Public - * License (GPL) version 2 or later, in which case the provisions - * of the GPL apply INSTEAD OF those given above. - * - * This software is provided ``as is'', and any express or implied - * warranties, including, but not limited to, the implied warranties of - * merchantability and fitness for a particular purpose are disclaimed. - * In no event shall the company or contributors be liable for any - * direct, indirect, incidental, special, exemplary, or consequential - * damages (including, but not limited to, procurement of substitute - * goods or services; loss of use, data, or profits; or business - * interruption) however caused and on any theory of liability, whether - * in contract, strict liability, or tort (including negligence or - * otherwise) arising in any way out of the use of this software, even - * if advised of the possibility of such damage. - */ -namespace FIT\NetopeerBundle\Models; - -/** - * This class holds shared data for Ajax operations - */ -class AjaxSharedData { - /** - * @var array shared data - */ - protected $data; - - /** - * @var AjaxSharedData instance for singleton - */ - protected static $instance; - - /** - * Constructor - */ - protected function __construct() { - - } - - /** - * Get instance of this class - * - * @todo Is not working correctly, creates new instance every time. - * @return AjaxSharedData - */ - public static function getInstance() { - if (!isset(static::$instance)) { - static::$instance = new static; - } - return static::$instance; - } - - /** - * Set keys and values of shared data array - * - * @param mixed $key - * @param mixed $arrayKey - * @param mixed $value - */ - public function setDataForKey($key, $arrayKey, $value) { - if (!isset($this->data[$key])) { - $this->data[$key] = array(); - } - $this->data[$key][$arrayKey] = $value; - } - - /** - * Get value from shared data array - * - * @param mixed $key key of shared array - * @return mixed - */ - public function getDataForKey($key) { - return $this->data[$key]; - } -} diff --git a/src/FIT/NetopeerBundle/Models/Array2XML.php b/src/FIT/NetopeerBundle/Models/Array2XML.php deleted file mode 100644 index cbd7f4ef..00000000 --- a/src/FIT/NetopeerBundle/Models/Array2XML.php +++ /dev/null @@ -1,225 +0,0 @@ -saveXML(); - * - * - * - * Additional functions: - * mergeXml - */ - -namespace FIT\NetopeerBundle\Models; - -class Array2XML { - - private static $xml = null; - private static $encoding = 'UTF-8'; - - /** - * Initialize the root XML node [optional] - * @param $version - * @param $encoding - * @param $format_output - */ - public static function init($version = '1.0', $encoding = 'UTF-8', $format_output = true) { - self::$xml = new \DomDocument($version, $encoding); - self::$xml->formatOutput = $format_output; - self::$encoding = $encoding; - } - - /** - * Convert an Array to XML - * @param string $node_name - name of the root node to be converted - * @param array $arr - aray to be converterd - * @return DomDocument - */ - public static function &createXML($node_name, $arr=array()) { - $xml = self::getXMLRoot(); - $xml->appendChild(self::convert($node_name, $arr)); - - self::$xml = null; // clear the xml node in the class for 2nd time use. - return $xml; - } - - /** - * Convert an Array to XML - * @param string $node_name - name of the root node to be converted - * @param array $arr - aray to be converterd - * @return DOMNode - */ - private static function &convert($node_name, $arr=array()) { - - //print_arr($node_name); - $xml = self::getXMLRoot(); - $node = $xml->createElement($node_name); - - if(is_array($arr)){ - // get the attributes first.; - if(isset($arr['@attributes'])) { - foreach($arr['@attributes'] as $key => $value) { - if(!self::isValidTagName($key)) { - throw new \Exception('[Array2XML] Illegal character in attribute name. attribute: '.$key.' in node: '.$node_name); - } - $node->setAttribute($key, self::bool2str($value)); - } - unset($arr['@attributes']); //remove the key from the array once done. - } - - // check if it has a value stored in @value, if yes store the value and return - // else check if its directly stored as string - if(isset($arr['@value'])) { - $node->appendChild($xml->createTextNode(self::bool2str($arr['@value']))); - unset($arr['@value']); //remove the key from the array once done. - //return from recursion, as a note with value cannot have child nodes. - return $node; - } else if(isset($arr['@cdata'])) { - $node->appendChild($xml->createCDATASection(self::bool2str($arr['@cdata']))); - unset($arr['@cdata']); //remove the key from the array once done. - //return from recursion, as a note with cdata cannot have child nodes. - return $node; - } - } - - //create subnodes using recursion - if(is_array($arr)){ - // recurse to get the node for that key - foreach($arr as $key=>$value){ - if(!self::isValidTagName($key)) { - throw new \Exception('[Array2XML] Illegal character in tag name. tag: '.$key.' in node: '.$node_name); - } - if(is_array($value) && is_numeric(key($value))) { - // MORE THAN ONE NODE OF ITS KIND; - // if the new array is numeric index, means it is array of nodes of the same kind - // it should follow the parent key name - foreach($value as $k=>$v){ - $node->appendChild(self::convert($key, $v)); - } - } else { - // ONLY ONE NODE OF ITS KIND - $node->appendChild(self::convert($key, $value)); - } - unset($arr[$key]); //remove the key from the array once done. - } - } - - // after we are done with all the keys in the array (if it is one) - // we check if it has any text value, if yes, append it. - if(!is_array($arr)) { - $node->appendChild($xml->createTextNode(self::bool2str($arr))); - } - - return $node; - } - - /* - * Get the root XML node, if there isn't one, create it. - */ - private static function getXMLRoot(){ - if(empty(self::$xml)) { - self::init(); - } - return self::$xml; - } - - /* - * Get string representation of boolean value - */ - private static function bool2str($v){ - //convert boolean to text value. - $v = $v === true ? 'true' : $v; - $v = $v === false ? 'false' : $v; - return $v; - } - - /* - * Check if the tag name or attribute name contains illegal characters - * Ref: http://www.w3.org/TR/xml/#sec-common-syn - */ - private static function isValidTagName($tag){ - $pattern = '/^[a-z_]+[a-z0-9\:\-\.\_]*[^:]*$/i'; - return preg_match($pattern, $tag, $matches) && $matches[0] == $tag; - } - - /** - * Pumps all child elements of second SimpleXML object into first one. - * - * @param object $xml1 SimpleXML object - * @param object $xml2 SimpleXML object - * @return xml - */ - public static function mergeXML (\SimpleXMLIterator &$xml1, \SimpleXMLIterator $xml2) - { - $output = array_merge_recursive(json_decode(json_encode($xml1), true), json_decode(json_encode($xml2), true)); - $output = self::createXML('comet-testers', $output); - return $output->saveXML(); - } - - /** - * array_merge_recursive does indeed merge arrays, but it converts values with duplicate - * keys to arrays rather than overwriting the value in the first array with the duplicate - * value in the second array, as array_merge does. I.e., with array_merge_recursive, - * this happens (documented behavior): - * - * array_merge_recursive(array('key' => 'org value'), array('key' => 'new value')); - * => array('key' => array('org value', 'new value')); - * - * array_merge_recursive_distinct does not change the datatypes of the values in the arrays. - * Matching keys' values in the second array overwrite those in the first array, as is the - * case with array_merge, i.e.: - * - * array_merge_recursive_distinct(array('key' => 'org value'), array('key' => 'new value')); - * => array('key' => array('new value')); - * - * Parameters are passed by reference, though only for performance reasons. They're not - * altered by this function. - * - * @param array $array1 - * @param array $array2 - * @return array - * @author Daniel - * @author Gabriel Sobrinho - */ - private static function array_merge_recursive_distinct ( array &$array1, array &$array2 ) { - $merged = $array1; - - foreach ( $array2 as $key => &$value ) { - if ( is_array ( $value ) && isset ( $merged [$key] ) && is_array ( $merged [$key] ) ) { - $merged [$key] = self::array_merge_recursive_distinct ( $merged [$key], $value ); - } else { - $merged [$key] = $value; - } - } - - return $merged; - } -} diff --git a/src/FIT/NetopeerBundle/Models/MergeXML.php b/src/FIT/NetopeerBundle/Models/MergeXML.php deleted file mode 100644 index 77ecdcad..00000000 --- a/src/FIT/NetopeerBundle/Models/MergeXML.php +++ /dev/null @@ -1,391 +0,0 @@ -stay = array('all'); - } else if (is_array($opts['stay'])) { - $this->stay = $opts['stay']; - } else { - $this->stay = (array) $opts['stay']; - } - if (!isset($opts['clone'])) { - $this->clon = array(); - } else if (is_array($opts['clone'])) { - $this->clon = $opts['clone']; - } else { - $this->clon = (array) $opts['clone']; - } - $this->join = !isset($opts['join']) ? 'root' : (string) $opts['join']; - $this->updn = !isset($opts['updn']) ? true : (bool) $opts['updn']; - $this->error = (object) array('code' => '', 'text' => ''); - if (class_exists($this->cln)) { - $this->dom = new $this->cln(); - $this->dom->preserveWhiteSpace = false; - $this->dom->formatOutput = true; - } else { - $this->Error('nod'); - } - } - - /** - * add XML file - * @param string $file -- pathed filename - * @param string|array $stay - * @return object|false - */ - public function AddFile($file, $stay = null, $clone = null) { - if (is_array($stay)) { - $this->stay = array_merge($this->stay, $stay); - } else if (!empty($stay)) { - $this->stay[] = $stay; - } - if (is_array($clone)) { - $this->clon = array_merge($this->clon, $clone); - } else if (!empty($clone)) { - $this->clon[] = $clone; - } - $data = @file_get_contents($file); - if ($data === false) { - $rlt = $this->Error('nof'); - } else if (empty($data)) { - $rlt = $this->Error('emf'); - } else { - $rlt = $this->AddSource($data); - } - return $rlt; - } - - /** - * add XML to result object - * @param string|object $xml - * @param string|array $stay - * @return mixed -- false - bad content - * object - result - */ - public function AddSource($xml, $stay = null, $clone = null) { - if (is_array($stay)) { - $this->stay = array_merge($this->stay, $stay); - } else if (!empty($stay)) { - $this->stay[] = $stay; - } - if (is_array($clone)) { - $this->clon = array_merge($this->clon, $clone); - } else if (!empty($clone)) { - $this->clon[] = $clone; - } - if (is_object($xml)) { - if (get_class($xml) != $this->cln) { - $dom = false; - } else if ($this->dom->hasChildNodes()) { - $dom = $xml; - } else { - $this->dom = $xml; - $this->dom->formatOutput = true; - $dom = true; - } - } else if ($this->dom->hasChildNodes()) { /* not first */ - $dom = new $this->cln(); - $dom->preserveWhiteSpace = false; - if (!@$dom->loadXML($xml)) { - $dom = false; - } - } else { /* first slot */ - $dom = @$this->dom->loadXML($xml) ? true : false; - } - if ($dom === false) { - $rlt = $this->Error('inv'); - } else if ($dom === true && $this->NameSpaces()) { - $this->count = 1; - $rlt = $this->dom; - } else if (is_object($dom) && $this->CheckSource($dom)) { - $this->Merge($dom, '/'); /* add to existing */ - $this->count++; - $rlt = $this->dom; - } else { - $rlt = false; - } - return $rlt; - } - - /** - * check/modify root and namespaces, - * @param object $dom source - * @return {bool} - */ - private function CheckSource(&$dom) { - $rlt = true; - if ($dom->encoding != $this->dom->encoding) { - $rlt = $this->Error('enc'); - } else if ($dom->documentElement->namespaceURI != $this->dom->documentElement->namespaceURI) { /* $dom->documentElement->lookupnamespaceURI(NULL) */ - $rlt = $this->Error('nse'); - } else if ($dom->documentElement->nodeName != $this->dom->documentElement->nodeName) { - if (!$this->join) { - $rlt = $this->Error('dif'); - } else if (is_string($this->join)) { - $doc = new \DOMDocument(); - $doc->encoding = $this->dom->encoding; - $doc->preserveWhiteSpace = false; - $doc->formatOutput = true; - $xml = "dom->xmlVersion}\" encoding=\"{$this->dom->encoding}\"?><$this->join>join>"; - if (@$doc->loadXML($xml)) { - $tmp = $doc->importNode($this->dom->documentElement, true); - $doc->documentElement->appendChild($tmp); - $this->dom = $doc; - $this->join = true; - } else { - $rlt = $this->Error('jne'); - $this->join = null; - } - } - } - if ($rlt) { - $doc = simplexml_import_dom($dom); - $rlt = $this->NameSpaces($doc->getDocNamespaces(true)); - } - return $rlt; - } - - /** - * register namespaces - * @param array $nsp -- additional namespaces - * @return bool - */ - private function NameSpaces($nsp = array()) { - $doc = simplexml_import_dom($this->dom); - $nsps = $doc->getDocNamespaces(true); - foreach ($nsp as $pfx => $url) { - if (!isset($nsps[$pfx])) { - $this->dom->createAttributeNS($url, "$pfx:attr"); - $nsps[$pfx] = $url; - } - } - $this->dxp = new \DOMXPath($this->dom); - $this->nsp = array(); - $rlt = true; - foreach ($nsps as $pfx => $url) { - if ($pfx == $this->nsd) { - $rlt = $this->Error('nse'); - break; - } else if (empty($pfx)) { - $pfx = $this->nsd; - } - $this->nsp[$pfx] = $url; - $this->dxp->registerNamespace($pfx, $url); - } - return $rlt; - } - - /** - * join 2 dom objects - * @param object $src -- current source node - * @param object $pth -- current source path - */ - private function Merge($src, $pth) { - $i = 0; - foreach ($src->childNodes as $node) { - $path = $this->GetNodePath($src->childNodes, $node, $pth, $i); - $obj = $this->Query($path); - if ($node->nodeType === XML_ELEMENT_NODE) { - /* replace existing node by default */ - $flg = (array_search($obj->item(0)->tagName, $this->stay) !== false) ? false : true; - /* not clone existing node by default */ - $cln = (array_search($obj->item(0)->tagName, $this->clon) === false) ? false : true; - if ($obj->length == 0 || $obj->item(0)->namespaceURI != $node->namespaceURI || $cln) { /* add node */ - $tmp = $this->dom->importNode($node, true); - $this->Query($pth)->item(0)->appendChild($tmp); - } else if ($flg && !$cln){ - if ($node->hasAttributes()) { /* add/replace attributes */ - foreach ($node->attributes as $attr) { - $obj->item(0)->setAttribute($attr->nodeName, $attr->nodeValue); - } - } - if ($node->hasChildNodes()) { - $this->Merge($node, $path); /* recurse to subnodes */ - } - } - } else if ($node->nodeType === XML_TEXT_NODE || $node->nodeType === XML_COMMENT_NODE) { /* leaf node */ - if ($obj->length == 0) { - if ($node->nodeType === XML_TEXT_NODE) { - $tmp = $this->dom->createTextNode($node->nodeValue); - } else { - $tmp = $this->dom->createComment($node->nodeValue); - } - $this->Query($pth)->item(0)->appendChild($tmp); - } else { - $obj->item(0)->nodeValue = $node->nodeValue; - } - } - $i++; - } - } - - /** - * form the node xPath expression - * @param {object} $nodes -- child nodes - * @param {object} $node -- current child - * @param {string} $pth -- parent path - * @param {int} $eln -- element sequence number - * @return {string} query path - */ - private function GetNodePath($nodes, $node, $pth, $eln) { - $j = 0; - if ($node->nodeType === XML_ELEMENT_NODE) { - $i = 0; - foreach ($nodes as $nde) { - if ($i > $eln) { - break; - } else if (($this->updn && $nde->nodeType === $node->nodeType && $nde->nodeName === $node->nodeName && $nde->namespaceURI === $node->namespaceURI) || - (!$this->updn && $nde->nodeType !== XML_PI_NODE)) { - $j++; - } - $i++; - } - if ($this->updn) { - if ($node->prefix) { - $p = $node->prefix . ':'; - } else if (isset($this->nsp[$this->nsd])) { - $p = $this->nsd . ':'; - } else { - $p = ''; - } - $p .= $node->localName; - } else { - $p = 'node()'; - } - } else if ($node->nodeType === XML_TEXT_NODE || $node->nodeType === XML_COMMENT_NODE) { - $i = 0; - foreach ($nodes as $nde) { - if ($i > $eln) { - break; - } else if ($nde->nodeType === $node->nodeType) { - $j++; - } - $i++; - } - $p = $node->nodeType === XML_TEXT_NODE ? 'text()' : 'comment()'; - } else { - $p = $pth; - } - if ($j > 0) { - $p = $pth . ($pth === '/' ? '' : '/') . $p . '[' . $j . ']'; - } - return $p; - } - - /** - * xPath query - * @param string $qry -- query statement - * @return object - */ - public function Query($qry) { - if ($this->join === true) { - $qry = "/{$this->dom->documentElement->nodeName}" . ($qry === '/' ? '' : $qry); - } - $rlt = $this->dxp->query($qry); - return $rlt; - } - - /** - * get result - * @param {int} flg -- 0 - object - * 1 - xml - * 2 - html - * @return {mixed} - */ - public function Get($flg = 0) { - if ($flg == 0) { - $rlt = $this->dom; - } else { - $rlt = $this->dom->saveXML(); - if ($flg == 2) { - $r = str_replace(' ', ' ', htmlspecialchars($rlt)); - $rlt = str_replace(array("\r\n", "\n", "\r"), '
      ', $r); - } - } - return $rlt; - } - - /** - * set error message - * @param string $err token - * @return false - */ - private function Error($err = 'und') { - $errs = array( - 'nod' => "$this->cln is not supported", - 'nof' => 'File not found', - 'emf' => 'File is empty', /* possible delivery fault */ - 'inv' => 'Invalid XML source', - 'enc' => 'Different encoding', - 'dif' => 'Different root nodes', - 'jne' => 'Invalid join parameter', - 'nse' => 'Namespace incompatibility', - 'und' => 'Undefined error'); - $this->error->code = isset($errs[$err]) ? $err : 'und'; - $this->error->text = $errs[$this->error->code]; - return false; - } - - /** - * get property value - * @param string $name - * @return mixed -- null - missing - */ - public function __get($name) { - return isset($this->$name) ? $this->$name : null; - } - -} - -?> diff --git a/src/FIT/NetopeerBundle/Models/XMLoperations.php b/src/FIT/NetopeerBundle/Models/XMLoperations.php deleted file mode 100644 index ed78605c..00000000 --- a/src/FIT/NetopeerBundle/Models/XMLoperations.php +++ /dev/null @@ -1,1721 +0,0 @@ - - * @author Tomas Cejka - * - * Copyright (C) 2012-2015 CESNET - * - * LICENSE TERMS - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of the Company nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * ALTERNATIVELY, provided that this notice is retained in full, this - * product may be distributed under the terms of the GNU General Public - * License (GPL) version 2 or later, in which case the provisions - * of the GPL apply INSTEAD OF those given above. - * - * This software is provided ``as is'', and any express or implied - * warranties, including, but not limited to, the implied warranties of - * merchantability and fitness for a particular purpose are disclaimed. - * In no event shall the company or contributors be liable for any - * direct, indirect, incidental, special, exemplary, or consequential - * damages (including, but not limited to, procurement of substitute - * goods or services; loss of use, data, or profits; or business - * interruption) however caused and on any theory of liability, whether - * in contract, strict liability, or tort (including negligence or - * otherwise) arising in any way out of the use of this software, even - * if advised of the possibility of such damage. - * - */ -namespace FIT\NetopeerBundle\Models; - -use Symfony\Component\Config\Definition\Exception\Exception; -use Symfony\Component\Debug\Exception\ContextErrorException; -use Symfony\Component\DependencyInjection\ContainerInterface; -use FIT\NetopeerBundle\Models\Data as Data; -use Symfony\Component\DependencyInjection\SimpleXMLElement; -use Symfony\Component\Finder\Finder; -use FIT\NetopeerBundle\Models\MergeXML; - -class XMLoperations { - /** - * @var ContainerInterface base bundle container - */ - public $container; - /** - * @var \Symfony\Bridge\Monolog\Logger instance of logging class - */ - public $logger; - /** - * @var \FIT\NetopeerBundle\Models\Data instance of data class - */ - public $dataModel; - - public static $customRootElement = 'netopeer-root'; - - /** - * Constructor with DependencyInjection params. - * - * @param \Symfony\Component\DependencyInjection\ContainerInterface $container - * @param \Symfony\Bridge\Monolog\Logger $logger logging class - * @param Data $dataModel data class - */ - public function __construct(ContainerInterface $container, $logger, Data $dataModel) { - $this->container = $container; - $this->logger = $logger; - $this->dataModel = $dataModel; - } - - - - /** - * divides string into the array (name, value) (according to the XML tree node => value) - * - * @param string $postKey post value - * @return array in format ('name', 'value') - */ - public function divideInputName($postKey) - { - $values = explode('_', $postKey); - $cnt = count($values); - if ($cnt > 2) { - $last = $values[$cnt-1]; - $values = array(implode("_", array_slice($values, 0, $cnt-1)), $last); - } elseif ($cnt == 2) { - - } elseif ($cnt == 1) { - $values = array('name', $values[0]); - } else { - $values = array('name', 'value'); - } - return $values; - } - - /** - * decodes XPath value (custom coding from JS) - * - * @param string $value encoded XPath string from JS form - * @return string decoded XPath string - */ - public function decodeXPath($value) { - return str_replace( - array('--', '?', '!'), - array('/', '[', ']'), - $value - ); - } - - /** - * Completes request tree (XML) with necessary parent nodes. - * Tree must be valid for edit-config action. - * - * @param \SimpleXMLElement $parent current parent of new content to be completed (add all his parents) - * @param string $newConfigString - * @param null $wrappedPath - * - * @return \SimpleXMLElement - */ - public function completeRequestTree(&$parent, $newConfigString, $wrappedPath = null) { - if (is_null($wrappedPath)) { - $wrappedPath = $this->dataModel->getPathToModels() . 'wrapped.wyin'; - } - $subroot = simplexml_load_file($wrappedPath); - $xmlNameSpaces = $subroot->getNamespaces(); - - if ( isset($xmlNameSpaces[""]) ) { - $subroot->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - } - $ns = $subroot->xpath("//xmlns:namespace"); - $namespace = ""; - if (sizeof($ns)>0) { - $namespace = $ns[0]->attributes()->uri; - } - - $parent = $parent->xpath("parent::*"); - while ($parent) { - $pos_subroot[] = $parent[0]; - $parent = $parent[0]->xpath("parent::*"); - } - $config = $newConfigString; - - if (isset($pos_subroot)) { - for ($i = 0; $i < sizeof($pos_subroot); $i++) { - /** - * @var SimpleXMLElement $subroot - */ - $subroot = $pos_subroot[$i]; - $domNode = dom_import_simplexml($subroot); - - - // key elements must be added into config XML - $newdoc = new \DOMDocument; - $node = $newdoc->importNode($domNode, true); - $newdoc->appendChild($node); - $keyElems = $this->removeChildrenExceptOfKeyElements($node, $node->childNodes, true); - - $childrenConfig = ""; - if ($keyElems > 0) { - $simpleSubRoot = simplexml_import_dom($node); - foreach ($simpleSubRoot->children() as $child) { - $childrenConfig .= $child->asXml(); - } - } - - $tmp = $subroot->getName(); - $config .= "getName().">\n"; - - if ($i == sizeof($pos_subroot) - 1) { - $config = "<".$subroot->getName(). - ($namespace!==""?" xmlns=\"$namespace\"":""). - " xmlns:xc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"". - ">\n".$childrenConfig.$config; - } else { - $config = "<".$subroot->getName(). - ">\n".$childrenConfig.$config; - } - } - } - $result = simplexml_load_string($config); - $result->registerXPathNamespace('xmlns', $namespace); - - return $result; - } - - /** - * @param string $sourceXml - * @param string $newXml - * @param array $params parametrs for MergeXML constructor - * @param int $output kind of output of MergeXML - * - * @return \DOMDocument|false - */ - public function mergeXml ($sourceXml, $newXml, $params = array(), $output = 0) { - $defaultParams = array( - 'join' => false, // common root name if any source has different root name (default is *root*, specifying *false* denies different names) - 'updn' => true, // traverse the nodes by name sequence (*true*, default) or overall sequence (*false*), - 'stay' => 'all', // use the *stay* attribute value to deny overwriting of specific node (default is *all*, can be array of values, string or empty) - 'clone' => '', // use the *clone* attribute value to clone specific nodes if they already exists (empty by default, can be array of values, string or empty) - ); - $params = array_merge($defaultParams, $params); - - $sourceDoc = new \DOMDocument(); - $sourceDoc->loadXML($sourceXml); - - $newDoc = new \DOMDocument(); - $newDoc->loadXML($newXml); - - try { - $mergeXml = new MergeXML(); - @$mergeXml->AddSource($sourceXml); - @$mergeXml->AddSource($newDoc); - - if (@$mergeXml->error->code != "") { - return false; - } - } catch (Exception $e) { - return false; - } - return $mergeXml->Get($output); - } - - /** - * updates (modifies) value of XML node - * - * @param \SimpleXMLElement $configXml xml file - * @param string $elementName name of the element - * @param string $xpath XPath to the element (without trailing '/', which is added automatically) - * @param string $val new value - * @param string $xPathPrefix - * @param int $newIndex new index of elem in parent cover (selectable plugin) - * - * @return \SimpleXMLElement|array modified node, empty array if element was not found - */ - public function elementValReplace(&$configXml, $elementName, $xpath, $val, $xPathPrefix = "xmlns:", $newIndex = -1) - { - $isAttribute = false; - - // if element is an attribute, it will have prefix at- - if ( strrpos($elementName, 'at-') === 0 ) { - $elementName = substr($elementName, 3); - $isAttribute = true; - } - - // get node according to xPath query - $node = $configXml->xpath('/'.$xPathPrefix.$xpath); - - if (isset($node[0])) { - $node = $node[0]; - } - - // set new value for node - if ( $isAttribute === true ) { - $elem = $node[0]; - $elem[$elementName] = $val; - } else { - if (isset($node[0])) { - $elem = $node[0]; - } else { - $elem = $node; - } - - if (isset($elem->$elementName) && (sizeof($elem->$elementName) > 0)) { - $e = $elem->$elementName; - if ($val != "") { - $e[0] = str_replace("\r", '', $val); // removes \r from value - } - if ($newIndex !== -1) { - $elem->addAttribute($xPathPrefix."index", $newIndex); - } - } else { - if ( !is_array($elem) ) { - if ($val != "") { - $elem[0] = str_replace("\r", '', $val); - } - if ($newIndex !== -1) { - $elem[0]->addAttribute($xPathPrefix."index", $newIndex); - } - } - } - } - - return $elem; - } - - - /** - * handles edit config form - changes config values into the $_POST values - * and sends them to editConfig process - * - * @param int $key session key of current connection - * @param array $configParams array of config params - * @return int result code - */ - public function handleEditConfigForm(&$key, $configParams) { - $post_vals = $this->container->get('request')->get('configDataForm'); - $res = 0; - - try { - - if ( ($originalXml = $this->dataModel->handle('getconfig', $configParams, false)) != 1 ) { - - $configXml = simplexml_load_string($originalXml, 'SimpleXMLIterator'); - - // save to temp file - for debugging - if ($this->container->getParameter('kernel.environment') == 'dev') { - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/original.yin', $configXml->asXml()); - } - - // we will get namespaces from original getconfig and set them to simpleXml object, 'cause we need it for XPath queries - $xmlNameSpaces = $configXml->getNamespaces(); - - if ( isset($xmlNameSpaces[""]) ) { - $configXml->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - $xmlNamespace = $xmlNameSpaces[""]; - $xPathPrefix = "xmlns:"; - } else { - // we will use this xmlns as backup for XPath request - $configXml->registerXPathNamespace("xmlns", "urn:cesnet:tmc:hanicprobe:1.0"); - $xmlNamespace = "urn:cesnet:tmc:hanicprobe:1.0"; - $xPathPrefix = ""; - } - - // foreach over all post values - $parentNodesForSorting = array(); - $processSorting = false; - foreach ( $post_vals as $postKey => $val ) { - if ($postKey == 'commit_all_button') continue; - - $index = -1; - - // divide string, if index is set - if (strpos($postKey, "|") !== false) { - $arr = explode("|", $postKey); - - if (sizeof($arr) == 2 && strpos($postKey, "index") !== false) { - $postKey = $arr[1]; - $index = str_replace("index", "", $arr[0]); - - $processSorting = true; - } - } - - $values = $this->divideInputName($postKey); - $elementName = $values[0]; - $xpath = $this->decodeXPath($values[1]); - $xpath = substr($xpath, 1); // removes slash at the begining - - $modifiedElem = $this->elementValReplace($configXml, $elementName, $xpath, $val, $xPathPrefix, $index); - if ($index != -1 && $modifiedElem instanceof \SimpleXMLIterator) { - array_push($parentNodesForSorting, $modifiedElem); - } - } - - if (sizeof($parentNodesForSorting)) { - $items = array(); - $parent = false; - foreach ($parentNodesForSorting as $child) { - $childDOM = dom_import_simplexml($child[0]); - $items[] = $childDOM; - $par = $child->xpath("parent::*"); - $parent = dom_import_simplexml($par[0]); - } - - // deleting must be separated - foreach ($items as $child) { - if ($parent) $parent->removeChild($child); - } - - usort($items, function($a, $b) { - $indA = 0; - $indB = 0; - - foreach($a->attributes as $name => $node) { - if ($name == "index") { - $indA = $node->nodeValue; - break; - } - } - - foreach($b->attributes as $name => $node) { - if ($name == "index") { - $indB = $node->nodeValue; - break; - } - } - - - return $indA - $indB; - }); - - foreach ($items as $child) { - $child->removeAttribute('index'); - if ($parent) $parent->appendChild($child); - } - - if ($parent) { - $parentSimple = simplexml_import_dom($parent); - $parentSimple->addAttribute("xc:operation", "replace", "urn:ietf:params:xml:ns:netconf:base:1.0"); - } - } - - // for debugging, edited configXml will be saved into temp file - if ($this->container->getParameter('kernel.environment') == 'dev') { - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/edited.yin', $configXml->asXml()); - } - - // check, if newNodeForm was send too - if (sizeof($this->container->get('request')->get('newNodeForm'))) { - $newNodeForms = $this->container->get('request')->get('newNodeForm'); - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/testing.yin', var_export($newNodeForms, true)); - - // create empty simpleXmlObject for adding all newNodeForms - $currentRoot = $configXml->xpath("/xmlns:*"); - $newNodesXML = new SimpleXMLElement("<".$currentRoot[0]->getName()." xmlns='".$xmlNamespace."'>getName().">"); - - foreach ($newNodeForms as $newNodeFormVals) { - $newNodeConfigXML = simplexml_load_string($originalXml, 'SimpleXMLIterator'); - - // we will get namespaces from original getconfig and set them to simpleXml object, 'cause we need it for XPath queries - $xmlNameSpaces = $newNodeConfigXML->getNamespaces(); - - if ( isset($xmlNameSpaces[""]) ) { - $newNodeConfigXML->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - $newNodesXML->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - } else { - // we will use this xmlns as backup for XPath request - $newNodeConfigXML->registerXPathNamespace("xmlns", "urn:cesnet:tmc:hanicprobe:1.0"); - $newNodesXML->registerXPathNamespace("xmlns", "urn:cesnet:tmc:hanicprobe:1.0"); - } - $toAdd = $this->processNewNodeForm($newNodeConfigXML, $newNodeFormVals); - - // merge new node XML with previous one - if (($out = $this->mergeXml($newNodesXML->asXML(), $toAdd)) !== false) { - $newNodesXML = simplexml_load_string($out->saveXML()); - } - } - - // finally merge the request with edited values - if (($out = $this->mergeXml($configXml->asXML(), $newNodesXML->asXML())) !== false) { - $configXml = simplexml_load_string($out->saveXML()); - } - } - - // sort final config xml - $params['attributesWhiteList'] = array('model-level-index'); - $xmlString = $configXml->asXML(); - $xmlString = $this->mergeXMLWithModel($xmlString, $params); - $sortedXml = $this->sortXMLByModelLevelIndex($xmlString, true); - - $res = $this->executeEditConfig($key, $sortedXml, $configParams['source']); - if ($res !== 1) { - $this->container->get('session')->getFlashBag()->add('success', "Config has been edited successfully."); - } - } else { - throw new \ErrorException("Could not load config."); - } - - } catch (\ErrorException $e) { - $this->logger->warn('Could not save config correctly.', array('error' => $e->getMessage())); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not save config correctly. Error: ".$e->getMessage()); - } - - - return $res; - } - - /** - * handles form for creating empty module - * - * @param $key Identifier of connection (connected device ID) - * @param $configParams - * @param $postVals - * - * @return int - */ - public function handleCreateEmptyModuleForm($key, $configParams, $postVals) { - $name = $postVals['name']; - $namespace = $postVals['namespace']; - $res = 0; - - $xmlTree = new \SimpleXMLElement('<'.$name.'>'); - $xmlTree->addAttribute('xmlns', $namespace); - $xmlTree->registerXPathNamespace('xc', 'urn:ietf:params:xml:ns:netconf:base:1.0'); - - $xmlTree->addAttribute("xc:operation", "create", "urn:ietf:params:xml:ns:netconf:base:1.0"); - - $createString = "\n".str_replace('', '', $xmlTree->asXML()); - - try { - $res = $this->executeEditConfig($key, $createString, $configParams['source']); - - if ($res == 0) { - $this->container->get('request')->getSession()->getFlashBag()->add('success', "New module was created."); - } - } catch (\ErrorException $e) { - $this->logger->warn('Could not create empty module.', array('error' => $e->getMessage(), 'xml' => $createString)); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not create empty module. Error: ".$e->getMessage()); - } - - return $res; - } - - /** - * Handles form for RPC method call - * - * @param $key Identifier of connection (connected device ID) - * @param $configParams - * @param $postVals - * - * @return int - * @throws \ErrorException - */ - public function handleRPCMethodForm($key, $configParams, $postVals) { - $name = $postVals['rootElemName']; - $namespace = $postVals['rootElemNamespace']; - $res = 0; - - $xmlTree = new \SimpleXMLElement('<'.$name.'>'); - $xmlTree->registerXPathNamespace('xc', 'urn:ietf:params:xml:ns:netconf:base:1.0'); - - if ($namespace !== 'false' && $namespace !== '') { - $xmlTree->registerXPathNamespace('rpcMod', $namespace); - $xmlTree->addAttribute('xmlns', $namespace); - } - - // we will go through all post values - $skipArray = array('rootElemName', 'rootElemNamespace'); - foreach ( $postVals as $labelKey => $labelVal ) { - if (in_array($labelKey, $skipArray)) continue; - $label = $this->divideInputName($labelKey); - // values[0] - label - // values[1] - encoded xPath - - if ( count($label) != 2 ) { - $this->logger->err('RPCMethodForm must contain exactly 2 params, example container_-*-*?1!-*?2!-*?1!', array('values' => $label, 'postKey' => $labelKey)); - throw new \ErrorException("Could not proccess all form fields."); - - } else { - $xpath = $this->decodeXPath($label[1]); - $xpath = substr($xpath, 1); - - $node = $this->insertNewElemIntoXMLTree($xmlTree, $xpath, $label[0], $labelVal, '', $addCreateNS = false); - - array_push($skipArray, $labelKey); - } - } - - $createString = "\n".str_replace('', '', $xmlTree->asXML()); - - try { - $res = $this->dataModel->handle("userrpc", array( - 'key' => $key, - 'content' => $createString, - ), false, $result); - /* RPC can return output data in $result */ - - if ($res == 0) { - $this->container->get('request')->getSession()->getFlashBag()->add('success', "RPC method invocation was successful."); - } - } catch (\ErrorException $e) { - $this->logger->warn('Could not invocate RPC method.', array('error' => $e->getMessage(), 'xml' => $createString)); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not invocate RPC method. Error: ".$e->getMessage()); - } - - return $res; - } - - /** - * duplicates node in config - values of duplicated nodes (elements) - * - * could be changed by user - * - * @param int $key session key of current connection - * @param array $configParams array of config params - * @throws \ErrorException - * @return int result code - */ - public function handleDuplicateNodeForm(&$key, $configParams) { - $post_vals = $this->container->get('request')->get('duplicatedNodeForm'); - $res = 0; - - try { - // load original (not modified) getconfig - if ( ($originalXml = $this->dataModel->handle('getconfig', $configParams, false)) != 1 ) { - $tmpConfigXml = simplexml_load_string($originalXml); - - // save to temp file - for debugging - if ($this->container->getParameter('kernel.environment') == 'dev') { - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/original.yin', $tmpConfigXml->asXml()); - } - - // we will get namespaces from original getconfig and set them to simpleXml object, 'cause we need it for XPath queries - $xmlNameSpaces = $tmpConfigXml->getNamespaces(); - if ( isset($xmlNameSpaces[""]) ) { - $tmpConfigXml->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - } - } - - // if we have XML configuration - if (isset($tmpConfigXml)) { - - // we will go through all posted values - $newLeafs = array(); - -// $tmpConfigXml = $this->completeRequestTree($tmpConfigXml, $tmpConfigXml->asXml()); - - /* fill values */ - $i = 0; - $createString = ""; - - foreach ( $post_vals as $postKey => $val ) { - $values = $this->divideInputName($postKey); - // values[0] - label - // values[1] - encoded xPath - - if ($postKey == "parent") { - $xpath = $this->decodeXPath($val); - // get node according to xPath query - $parentNode = $tmpConfigXml->xpath($xpath); - } else if ( count($values) != 2 ) { - $this->logger->err('newNodeForm must contain exactly 2 params, example container_-*-*?1!-*?2!-*?1!', array('values' => $values, 'postKey' => $postKey)); - throw new \ErrorException("newNodeForm must contain exactly 2 params, example container_-*-*?1!-*?2!-*?1! ". var_export(array('values' => $values, 'postKey' => $postKey), true)); - } else { - $xpath = $this->decodeXPath($values[1]); - $xpath = substr($xpath, 1, strripos($xpath, "/") - 1); - - $node = $this->elementValReplace($tmpConfigXml, $values[0], $xpath, $val); - try { - if ( is_object($node) ) { - @$node->addAttribute("xc:operation", "create", "urn:ietf:params:xml:ns:netconf:base:1.0"); - } - } catch (\ContextErrorException $e) { - // nothing happened - attribute is already there - } - } - } - - $createString = "\n".str_replace('', '', $parentNode[0]->asXml()); - $createTree = $this->completeRequestTree($parentNode[0], $createString); - - // for debugging, edited configXml will be saved into temp file - if ($this->container->getParameter('kernel.environment') == 'dev') { - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/newElem.yin', $createTree->asXml()); - } - $res = $this->executeEditConfig($key, $createTree->asXml(), $configParams['source']); - - if ($res == 0) { - $this->container->get('request')->getSession()->getFlashBag()->add('success', "Record has been added."); - } - } else { - throw new \ErrorException("Could not load config."); - } - - } catch (\ErrorException $e) { - $this->logger->warn('Could not save new node correctly.', array('error' => $e->getMessage())); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not save new node correctly. Error: ".$e->getMessage()); - } - - return $res; - } - - /** - * create new node - * - * @param int $key session key of current connection - * @param array $configParams array of config params - * @return int result code - */ - public function handleNewNodeForm(&$key, $configParams) { - $post_vals = $this->container->get('request')->get('newNodeForm'); - $res = 0; - - try { - // load original (not modified) getconfig - if ( ($originalXml = $this->dataModel->handle('getconfig', $configParams, true)) != 1 ) { - /** @var \SimpleXMLElement $configXml */ - $configXml = simplexml_load_string($originalXml); - - // we will get namespaces from original getconfig and set them to simpleXml object, 'cause we need it for XPath queries - $xmlNameSpaces = $configXml->getNamespaces(); - if ( isset($xmlNameSpaces[""]) ) { - $namespace = $xmlNameSpaces[""]; - $configXml->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - } elseif (sizeof($xmlNameSpaces) == 0) { - $namespace = 'urn:ietf:params:xml:ns:yang:yin:1'; - $configXml->registerXPathNamespace("xmlns", 'urn:ietf:params:xml:ns:yang:yin:1'); - } - } - - // if we have XML configuration - if (isset($configXml)) { - $createTreeXML = $this->processNewNodeForm($configXml, $post_vals); - - $res = $this->executeEditConfig($key, $createTreeXML, $configParams['source']); - - if ($res == 0) { - $this->container->get('request')->getSession()->getFlashBag()->add('success', "Record has been added."); - } - } else { - throw new \ErrorException("Could not load config."); - } - - } catch (\ErrorException $e) { - $this->logger->warn('Could not save new node correctly.', array('error' => $e->getMessage())); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not save new node correctly. Error: ".$e->getMessage()); - } - - return $res; - } - - /** - * @param \SimpleXMLElement $configXml - * @param array $post_vals - * - * @return mixed|string - * @throws \ErrorException - */ - private function processNewNodeForm(&$configXml, $post_vals) { - $keyElemsCnt = 0; - $dom = new \DOMDocument(); - $skipArray = array(); - - // load parent value - if (array_key_exists('parent', $post_vals)) { - $parentPath = $post_vals['parent']; - - $xpath = $this->decodeXPath($parentPath); - // get node according to xPath query - /** @var \SimpleXMLElement $tmpParentNode */ - $parentNode = $configXml->xpath($xpath); - - array_push($skipArray, 'parent'); - - // we have to delete all children from parent node (because of xpath selector for new nodes), except from key nodes - $domNode = dom_import_simplexml($parentNode[0]); - $keyElemsCnt = $this->removeChildrenExceptOfKeyElements($domNode, $domNode->childNodes); - - } else { - throw new \ErrorException("Could not set parent node for new elements."); - } - - // we will go through all post values - $speciallyAddedNodes = array(); - foreach ( $post_vals as $labelKey => $labelVal ) { - if (in_array($labelKey, $skipArray)) continue; - $label = $this->divideInputName($labelKey); - // values[0] - label - // values[1] - encoded xPath - - // load parent node - - - if ( count($label) != 2 ) { - $this->logger->err('newNodeForm must contain exactly 2 params, example container_-*-*?1!-*?2!-*?1!', array('values' => $label, 'postKey' => $labelKey)); - throw new \ErrorException("Could not proccess all form fields."); - - } else { - $valueKey = str_replace('label', 'value', $labelKey); - $value = $post_vals[$valueKey]; - - array_push($skipArray, $labelKey); - array_push($skipArray, $valueKey); - - $xpath = $this->decodeXPath($label[1]); - $xpath = substr($xpath, 1, strripos($xpath, "/") - 1); - - $addedNodes = $this->insertNewElemIntoXMLTree($configXml, $xpath, $labelVal, $value); - // we have created some other element - if (sizeof($addedNodes) >= 2) { - for ($i = 1; $i < sizeof($addedNodes); $i++) { - array_push($speciallyAddedNodes, $addedNodes[$i]); - } - } - } - } - - if ($keyElemsCnt > 0 && isset($domNode)) { - $dom->importNode($domNode, true); - $this->moveCustomKeyAttributesIntoElements($dom, $domNode, $keyElemsCnt); - } - - $createString = "\n".str_replace('', '', $parentNode[0]->asXml()); - $createTree = $this->completeRequestTree($parentNode[0], $createString); - $createTreeXML = $createTree->asXML(); - - // add all "specially added nodes" - mainly leafrefs and so - if (sizeof($speciallyAddedNodes)) { - // append special nodes into empty root element - foreach ($speciallyAddedNodes as $node) { - $nodeCreateString = "\n".str_replace('', '', $node[0]->asXml()); - $nodeCreateTree = $this->completeRequestTree($node[0], $nodeCreateString); - - // finally merge the request - if (($out = $this->mergeXml($createTreeXML, $nodeCreateTree->asXML())) !== false) { - $createTree = simplexml_load_string($out->saveXML()); - } - } - - $createTreeXML = $createTree->asXML(); - } - - return $createTreeXML; - } - - /** - * @param \DOMDocument $dom - * @param \DOMElement $domNode - * @param $keyElementsCnt - * - * @return int number of moved items - */ - public function moveCustomKeyAttributesIntoElements($dom, $domNode, $keyElementsCnt) { - $attributesArr = array(); - $totalMoved = 0; - - if ($domNode->hasAttributes()) { - foreach ($domNode->attributes as $attr) { - if (strpos($attr->nodeName, "GUIcustom_") === 0) { - $elemName = str_replace("GUIcustom_", "", $attr->nodeName); - $elemValue = $attr->nodeValue; - - if ($domNode->hasChildNodes()) { - $domNode->insertBefore(new \DOMElement($elemName, $elemValue), $domNode->childNodes->item(0)); - } else { - $domNode->appendChild(new \DOMElement($elemName, $elemValue)); - } - - $attributesArr[] = $attr->nodeName; - $totalMoved++; - } - } - // remove must be in new foreach, previous deletes only first one - foreach ($attributesArr as $attrName) { - $domNode->removeAttribute($attrName); - } - } - - if ($totalMoved < $keyElementsCnt && $domNode->hasChildNodes()) { - foreach($domNode->childNodes as $child) { - $totalMoved += $this->moveCustomKeyAttributesIntoElements($dom, $child, $keyElementsCnt); - } - } - - return $totalMoved; - } - - /** - * Sorts given XML file by attribute model-level-number recursively - * - * @param $xml - * @param bool $removeIndexAttr - * - * @return string - */ - public function sortXMLByModelLevelIndex($xml, $removeIndexAttr = true) { - $xslt = ' - - - - - - - - - - '; - - $xsldoc = new \DOMDocument(); - $xsldoc->loadXML($xslt); - - $xmldoc = new \DOMDocument(); - $xmldoc->loadXML($xml); - - $xsl = new \XSLTProcessor(); - $xsl->importStyleSheet($xsldoc); - - $res = $xsl->transformToXML($xmldoc); - - // remove attribute model-level-index - if ($removeIndexAttr) { - $res = preg_replace('/ model-level-index="\d+"/', '', $res); - } - - return $res; - } - - /** - * removes all children of element except of key elements, which has to remain - * - * @param \DOMElement $domNode - * @param \DOMNodeList $domNodeChildren - * @param bool $leaveKey - * @param bool $recursive - * - * @return int number of key elements, that remains - */ - public function removeChildrenExceptOfKeyElements($domNode, $domNodeChildren, $leaveKey = false, $recursive = false) - { - $keyElemIndex = $keyElemsCnt = 0; - - while ($domNodeChildren->length > $keyElemIndex) { - $isKey = $isCreated = false; - $child = $domNodeChildren->item($keyElemIndex); - - if ($child->hasAttributes()) { - foreach ($child->attributes as $attr) { - if ($attr->nodeName == "iskey" && $attr->nodeValue == "true") { - if ($child->hasAttributes()) { - foreach ($child->attributes as $attr) { - if ($attr->nodeName !== 'xc:operation') { - $attributesArr[] = $attr->nodeName; - } - } - // remove must be in new foreach, previous deletes only first one - foreach ($attributesArr as $attrName) { - $child->removeAttribute($attrName); - } - } - if ($leaveKey == true) { - $keyElemIndex++; - $isKey = true; - } else if (isset($child)) { - $nodeName = $child->nodeName; - $nodeValue = $child->nodeValue; - $domNode->setAttribute("GUIcustom_".$nodeName, $nodeValue); - } - $keyElemsCnt++; - } elseif ($attr->nodeName == "xc:operation" && $attr->nodeValue == "create") { - $keyElemIndex++; - $isCreated = true; - } - } - } - - if ((!$isKey && !$isCreated) || $leaveKey == false) { - try { - $childrenRemains = 0; - - // recursively check all children for their key elements - if (sizeof($child->childNodes) && $recursive) { - foreach ($child->childNodes as $chnode) { - if (sizeof($chnode->childNodes)) { - $childrenRemains += $this->removeChildrenExceptOfKeyElements($chnode, $chnode->childNodes, $leaveKey, $recursive); - } - } - } - - if ($childrenRemains == 0) { - $domNode->removeChild($child); - } else { - $keyElemIndex++; - } - - } catch (\DOMException $e) { - - } - } - } - - if ($domNode->hasAttributes()) { - foreach ($domNode->attributes as $attr) { - if (strpos($attr->nodeName, "GUIcustom_") !== 0) { - $attributesArr[] = $attr->nodeName; - } - } - // remove must be in new foreach, previous deletes only first one - foreach ($attributesArr as $attrName) { - $domNode->removeAttribute($attrName); - } - } - return $keyElemsCnt; - } - - /** - * inserts new element into given XML tree - * - * @param \SimpleXMLElement $configXml xml file - * @param string $xpath XPath to the element (without initial /) - * @param string $label label value - * @param string $value new value - * @param string $xPathPrefix - * @param bool $addCreateNS - * - * @return array array of \SimpleXMLElement modified node, which is always first response - */ - public function insertNewElemIntoXMLTree(&$configXml, $xpath, $label, $value, $xPathPrefix = "xmlns:", $addCreateNS = true) - { - /** - * get node according to xPath query - * @var \SimpleXMLElement $node - * @var \SimpleXMLElement $elem - * @var \SimpleXMLElement $elemModel - */ - $node = $configXml->xpath('/'.$xPathPrefix.$xpath); - $retArr = array(); - - if ($value === "" || $value === false) { - $elem = $node[0]->addChild($label); - } else { - $elem = $node[0]->addChild($label, $value); - } - $elemIndex = sizeof($node[0]->children()); - - if ($addCreateNS) { - $elem->addAttribute("xc:operation", "create", "urn:ietf:params:xml:ns:netconf:base:1.0"); - } - - array_push($retArr, $elem); - - // we have to check new insterted element model (load model to XML) - $xml = $configXml->asXML(); - $xml = $this->mergeXMLWithModel($xml); - $tmpXml = simplexml_load_string($xml); - if (isset($configXml->getNamespaces()[""])) { - $tmpXml->registerXPathNamespace(str_replace(":", "", $xPathPrefix), $configXml->getNamespaces()[""]); - } - $elemWithModel = $tmpXml->xpath('/'.$xPathPrefix.$xpath.'/*['.$elemIndex.']'); - - /* We don't want to auto generate leaf-ref now - if ($elemWithModel[0]) { - $elemModel = $elemWithModel[0]; - $leafRefPath = ""; - $isLeafRef = false; - foreach ($elemModel->attributes() as $key => $val) { - if ($key == 'type' && $val[0] == 'leafref') { - $isLeafRef = true; - } elseif ($key == 'leafref-path') { - $leafRefPath = $val[0]; - } - - if ($isLeafRef && $leafRefPath != "") { - $refElem = $this->addElementRefOnXPath($configXml, (string)$elem[0], $leafRefPath, $xPathPrefix); - if ($refElem instanceof \SimpleXMLElement) { - array_push($retArr, $refElem); - } - break; - } - } - } - */ - - return $retArr; - } - - /** - * @param \SimpleXMLElement $configXml - * @param $refValue value to add - * @param $leafRefPath xpath to target ref - * @param string $xPathPrefix - * @param bool $addCreateNS - * - * @return \SimpleXMLElement|bool first added element (root of possible subtree) - */ - public function addElementRefOnXPath(&$configXml, $refValue, $leafRefPath, $xPathPrefix = "xmlns:", $addCreateNS = true) { - - // check if target leaf ref does not exists already (we don't have to add add) - $xpath = str_replace("/", "/xmlns:", $leafRefPath); - $targets = $configXml->xpath($xpath); - if (sizeof($targets)) { - foreach ($targets as $target) { - $val = (string)$target; - if ($val == $refValue) { - return true; - } - } - } - - // start with first part of xpath - $pathLevels = explode('/', $leafRefPath); - $xpath = ""; - - $currentRoot = $configXml->xpath("/xmlns:*"); - - // go throug all xpath parts and check, if element already exists - for ($i = 0; $i < sizeof($pathLevels); $i++) { - $path = $pathLevels[$i]; - if ($path == '') continue; - - $xpath .= "/".$xPathPrefix.$path; - $elem = $configXml->xpath($xpath); - - // remove all children from root element - $isLastElement = ($i == sizeof($pathLevels) - 1); - if (sizeof($elem) && ($i == sizeof($pathLevels) - 2)) { - $domNode = dom_import_simplexml($elem[0]); - $newdoc = new \DOMDocument; - $node = $newdoc->importNode($domNode, true); - $newdoc->appendChild($node); - $this->removeChildrenExceptOfKeyElements($node, $node->childNodes, $leaveKey = false); - - $newConfigXml = simplexml_import_dom($node); - $newConfigXml->registerXPathNamespace(str_replace(":", "", $xPathPrefix), $configXml->getNamespaces()[""]); - $configXml = $newConfigXml; - $elem = $configXml->xpath($xpath); - } - - // if element does not exists, create one - if (!sizeof($elem)) { - - // last elem does not exists, create new one - $elem = $currentRoot[0]->addChild($path); - - if ($addCreateNS) { - $elem->addAttribute("xc:operation", "create", "urn:ietf:params:xml:ns:netconf:base:1.0"); - } - - if (!isset($firstAddedElement)) { - $firstAddedElement = $elem; - } - - $currentRoot = $elem; - } - - // set correct ref value to last element - if ($isLastElement) { - $elem[0] = $refValue; - } - - $currentRoot = $elem; - - } - - if (!isset($firstAddedElement)) { - $firstAddedElement = $currentRoot; - } - - return ($firstAddedElement[0] instanceof \SimpleXMLElement) ? $firstAddedElement[0] : $firstAddedElement; - } - - /** - * removes node from config XML tree - * - * @param int $key session key of current connection - * @param array $configParams array of config params - * @throws \ErrorException when get-config could not be loaded - * @return int result code - */ - public function handleRemoveNodeForm(&$key, $configParams) { - $post_vals = $this->container->get('request')->get('removeNodeForm'); - $res = 0; - - try { - if ( ($originalXml = $this->dataModel->handle('getconfig', $configParams, true)) != 1 ) { - $tmpConfigXml = simplexml_load_string($originalXml); - - // save to temp file - for debugging - if ($this->container->getParameter('kernel.environment') == 'dev') { - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/original.yin', $tmpConfigXml->asXml()); - } - - // we will get namespaces from original getconfig and set them to simpleXml object, 'cause we need it for XPath queries - $xmlNameSpaces = $tmpConfigXml->getNamespaces(); - if ( isset($xmlNameSpaces[""]) ) { - $tmpConfigXml->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - } - - $xpath = $this->decodeXPath($post_vals["parent"]); - $toDelete = $tmpConfigXml->xpath($xpath); - $deletestring = ""; - - foreach ($toDelete as $td) { - //$td->registerXPathNamespace("xc", "urn:ietf:params:xml:ns:netconf:base:1.0"); - $td->addAttribute("xc:operation", "remove", "urn:ietf:params:xml:ns:netconf:base:1.0"); - $deletestring .= "\n".str_replace('', '', $td->asXml()); - } - - $deleteTree = $this->completeRequestTree($toDelete[0], $deletestring); - - // for debugging, edited configXml will be saved into temp file - if ($this->container->getParameter('kernel.environment') == 'dev') { - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/removeNode.yin', $tmpConfigXml->asXml()); - } - $res = $this->executeEditConfig($key, $deleteTree->asXml(), $configParams['source']); - if ($res == 0) { - $this->container->get('request')->getSession()->getFlashBag()->add('success', "Record has been removed."); - } - } else { - throw new \ErrorException("Could not load config."); - } - } catch (\ErrorException $e) { - $this->logger->warn('Could not remove node correctly.', array('error' => $e->getMessage())); - $this->container->get('request')->getSession()->getFlashBag()->add('error', "Could not remove node correctly. ".$e->getMessage()); - } - - return $res; - - } - - /** - * sends modified XML to server - * - * @param int $key session key of current connection - * @param string $config XML document which will be send - * @param string $target = "running" target source - * - * @param array $additionalParams - * - * @return int return 0 on success, 1 on error - */ - private function executeEditConfig($key, $config, $target = "running", $additionalParams = array()) { - $res = 0; - $editConfigParams = array( - 'key' => $key, - 'target' => $target, - 'config' => str_replace('', '', $config) - ); - $editConfigParams = array_merge($editConfigParams, $additionalParams); - - // edit-cofig - if ( ($merged = $this->dataModel->handle('editconfig', $editConfigParams)) != 1 ) { - // for debugging purposes, we will save result into the temp file - if ($this->container->getParameter('kernel.environment') == 'dev') { - @file_put_contents($this->container->get('kernel')->getRootDir().'/logs/tmp-files/merged.yin', $merged); - } - } else { - $this->logger->err('Edit-config failed.', array('params', $editConfigParams)); - // throw new \ErrorException('Edit-config failed.'); - $res = 1; - } - return $res; - } - - /** - * Removes header from text. - * - * @param string &$text string to remove XML header in - * @return mixed returns an array if the subject parameter - * is an array, or a string otherwise. If matches - * are found, the new subject will be returned, - * otherwise subject will be returned unchanged - * or null if an error occurred. - */ - public function removeXmlHeader(&$text) { - return preg_replace("/<\?xml .*\?".">/i", "", $text); - } - - /** - * @return \SimpleXMLElement|false - */ - public function loadModel() { - $notEditedPath = $this->dataModel->getModelsDir(); - $path = $this->dataModel->getPathToModels(); - $modelFile = $path . 'wrapped.wyin'; - $res = false; - - $this->logger->info("Trying to find model in ", array('pathToFile' => $modelFile)); - if ( file_exists($modelFile) ) { - $this->logger->info("Model found in ", array('pathToFile' => $modelFile)); - if ( $path != $notEditedPath ) { - try { - $res = simplexml_load_file($modelFile); - } catch (\ErrorException $e) { - $this->logger->err("Could not load model"); - } - } - } else { - // TODO: if is not set module direcotory, we have to set model to merge with, maybe custom model? - $this->logger->warn("Could not find model in ", array('pathToFile' => $modelFile)); - } - return $res; - } - - /** - * Merge given XML with data model - * - * @param string $xml XML string - * @return array|false false on error, merged array on success - * @param array $params modification parameters for merge - */ - public function mergeXMLWithModel(&$xml, $params = array()) { - // load model - $model = $this->loadModel(); - $res = false; - - if ($model !== false) { - try { - $res = $this->mergeWithModel($model, $xml, $params); - } catch (\ErrorException $e) { - // TODO - $this->logger->err("Could not merge with model:", array('error' => $e->getMessage())); - } - } - return $res; - } - - -/** - * Check, if XML response is valid. - * - * @param string &$xmlString xml response - * @return bool - */ -public function isResponseValidXML(&$xmlString) { - $e = false; - try { - @$simpleXMLRes = simplexml_load_string($xmlString); - } catch (\ErrorException $e) { - // Exception will be handled bellow - } - if ( (isset($simpleXMLRes) && $simpleXMLRes === false) || $e !== false) { - // sometimes is exactly one root node missing - // we will check, if is not XML valid with root node - $xmlString = "<".self::$customRootElement.">".$xmlString.""; - try { - @$simpleXMLRes = simplexml_load_string($xmlString); - if (!($simpleXMLRes instanceof \SimpleXMLElement)) { - return false; - } - } catch (\ErrorException $e) { - return false; - } - } - return true; -} - -/** - * Get parent for element. - * - * @param $element - * @return bool|\SimpleXMLElement - */ -public function getElementParent($element) { - - $parentsChoice = $element->xpath("parent::*[@eltype='case']/parent::*[@eltype='choice']/parent::*"); - if (sizeof($parentsChoice)) { - return $parentsChoice[0]; - } - - $parents = $element->xpath("parent::*"); - if ($parents) { - return $parents[0]; - } - return false; -} - -/** - * Check if two elements match. - * - * @param $model_el element from model - * @param $possible_el element to match the model - * @return bool - */ -public function checkElemMatch($model_el, $possible_el) { - $mel = $this->getElementParent($model_el); - $pel = $this->getElementParent($possible_el); - - if ($mel instanceof \SimpleXMLElement && $pel instanceof \SimpleXMLElement) { - while ($pel && $mel) { - if ($pel->getName() !== $mel->getName()) { - return false; - } - $pel = $this->getElementParent($pel); - $mel = $this->getElementParent($mel); - } - return true; - } else { - return false; - } -} - - /** - * Completes tree structure for target element. - * - * $params['attributesWhiteList'] = set array of white listed attributes to add - * default empty array() - add all - * - * @param \SimpleXMLElement $source - * @param \SimpleXMLElement $target - * @param array $params modification parameters for merge - */ -public function completeAttributes(&$source, &$target, $params = array()) { - if (isset($params['attributesWhiteList']) && sizeof($params['attributesWhiteList'])) { - $filterAttributes = $params['attributesWhiteList']; - } - if ($source->attributes()) { - $attrs = $source->attributes(); -// var_dump($source->getName()); - if (in_array($attrs["eltype"], array("leaf","list","leaf-list", "container", "choice", "case"))) { - foreach ($source->attributes() as $key => $val) { - - // skip attributes which are not in whitelist - if (isset($filterAttributes) && !in_array($key, $filterAttributes)) continue; - - try { - @$target->addAttribute($key, $val); - } catch (\ErrorException $e) { -// $this->logger->addWarning('Error in adding attributes: ', array('error' => $e->getMessage())); - } - - } - } - } -} - -/** - * Find corresponding $el in configuration model $model and complete attributes from $model. - * - * @param \SimpleXMLElement &$model with data model - * @param \SimpleXMLElement $el with element of response - * @param array $params modification parameters for merge - */ -public function findAndComplete(&$model, $el, $params = array()) { - $modelns = $model->getNamespaces(); - $model->registerXPathNamespace("c", $modelns[""]); - $found = $model->xpath("//c:". $el->getName()); - - if (sizeof($found) == 1) { - $this->completeAttributes($found[0], $el, $params); - } else { -// echo "Not found unique
      "; - foreach ($found as $found_el) { - if ($this->checkElemMatch($found_el, $el)) { - $this->completeAttributes($found_el, $el, $params); - break; - } - } - } -} - -/** - * Go through $root_el tree that represents the response from Netconf server. - * - * @param \SimpleXMLElement &$model with data model - * @param \SimpleXMLElement $root_el with element of response - * @param array $params modification parameters for merge - */ -public function mergeRecursive(&$model, $root_el, $params = array()) { - if ($root_el->count() == 0) { - $this->findAndComplete($model, $root_el, $params); - // TODO: repair merge with root element (no parents) - } - - foreach ($root_el as $ch) { - $this->findAndComplete($model, $ch, $params); - $this->mergeRecursive($model, $ch, $params); - } - - foreach ($root_el->children as $ch) { - $this->findAndComplete($model, $ch, $params); - $this->mergeRecursive($model, $ch, $params); - } - } - - /** - * Add attributes from configuration model to response such as config, mandatory, type. - * - * @param \SimpleXMLElement $model data configuration model - * @param string $result data from netconf server - * @return string the result of merge - * @param array $params modification parameters for merge - */ - public function mergeWithModel($model, $result, $params = array()) { - if ($result) { - $resxml = simplexml_load_string($result); - - $this->mergeRecursive($model, $resxml, $params); - - return $resxml->asXML(); - } else { - return $result; - } - } - - /** - * Validates input string against validation files saved in models directory. - * For now, only two validation step are set up - RelaxNG (*.rng) and Schema (*.xsd) - * - * @param string $xml xml string to validate with RelaxNG and Schema, if available - * @return bool - */ - public function validateXml($xml) { - $finder = new Finder(); - $domDoc = new \DOMDocument(); - $xml = "".$xml.""; - $domDoc->loadXML($xml); - - $iterator = $finder - ->files() - ->name("/.*data\.(rng|xsd)$/") - ->in($this->dataModel->getPathToModels()); - - try { - foreach ($iterator as $file) { - $path = $file->getRealPath(); - if (strpos($path, "rng")) { - try { - if (!@$domDoc->relaxNGValidate($path)) { - return false; - } - } catch (\ContextErrorException $e) { - $this->logger->addWarning($e->getMessage()); - return false; - } - } else if (strpos($path, "xsd")) { - try { - if (!@$domDoc->schemaValidate($path)) { - return false; - } - } catch (\ContextErrorException $e) { - $this->logger->addWarning($e->getMessage()); - return false; - } - } - } - } catch (\ErrorException $e) { - $this->logger->addWarning("XML is not valid.", array('error' => $e->getMessage(), 'xml' => $xml, 'RNGfile' => $path)); - return false; - } - - return true; - - } - - /** - * loads available values for element from model - * - * @param $formId unique form identifier (for caching response) - * @param $xPath - * - * @return array - */ - public function getAvailableLabelValuesForXPath($formId, $xPath) { - - /** - * @var \winzou\CacheBundle\Cache\LifetimeFileCache $cache - */ - $cache = $this->container->get('winzou_cache'); - - if ($cache->contains('getResponseForFormId_'.$formId)) { - $xml = $cache->fetch('getResponseForFormId_'.$formId); - } else { - $xml = $this->loadModel()->asXML(); - $cache->save('getResponseForFormId_'.$formId, $xml, 1000); - } - - $labelsArr = array(); - $attributesArr = array(); - $elemsArr= array(); - if ($xml !== false) { - $dom = new \DOMDocument(); - $dom->loadXML($xml); - - $decodedXPath = str_replace("/", "/xmlns:", $this->decodeXPath($xPath))."/*"; - if (strpos($xPath, '----') !== false) { - // we have to correct xpath selector if xpath start with '//' - $decodedXPath = str_replace('xmlns:/', '/', $decodedXPath); - } else { - // we have to remove all array selectors [D] - $decodedXPath = preg_replace('/\[[0-9]+\]/', '', $decodedXPath); - // we have to add one level for "module" (root) element, which in model in addition to getconfig response - $decodedXPath = '/xmlns:*'.$decodedXPath; - } - $domXpath = new \DOMXPath($dom); - - $context = $dom->documentElement; - foreach( $domXpath->query('namespace::*', $context) as $node ) { - $domXpath->registerNamespace($node->nodeName, $node->nodeValue); - } - - $elements = $domXpath->query($decodedXPath); - - if (!is_null($elements)) { - foreach ($elements as $element) { - $isChoice = $isConfig = false; - $elemsArr[$element->nodeName] = simplexml_import_dom($element, 'SimpleXMLIterator'); - if ($element->hasAttributes()) { - foreach ($element->attributes as $attr) { - // if element is choice, we should load case statements bellow - if ($attr->nodeName == "eltype" && $attr->nodeValue == "choice") { - $isChoice = true; - } else if ($attr->nodeName == "config" && $attr->nodeValue == "true") { - $isConfig = true; - } - $attributesArr[$element->nodeName][$attr->nodeName] = $attr->nodeValue; - } - } - - if (!$isConfig) { - continue; - } - - // load case statement (children of element choice) - if ($isChoice) { - if ($element->hasChildNodes()) { - foreach ($element->childNodes as $child) { - $isAllowedEltype = $isConfig = false; - - if ($child->hasAttributes()) { - foreach ($child->attributes as $attr) { - $isSubCase = false; - - // check if is confing - if ($attr->nodeName == "config" && $attr->nodeValue == "true") { - $isConfig = true; - } - - // load only available elementtypes - if ($attr->nodeName == "eltype" && in_array($attr->nodeValue, array('case', 'container', 'leaf', 'leaf-list', 'list'))) { - $isAllowedEltype = true; - - // if its case statement, try to load child with same name and complete its attributes - if ($attr->nodeValue == "case" && $child->hasChildNodes()) { - foreach ($child->childNodes as $subchild) { - if ($subchild->nodeName == $child->nodeName && $subchild->hasAttributes()) { - $isSubCase = true; - foreach ($subchild->attributes as $attr) { - $attributesArr[$child->nodeName][$attr->nodeName] = $attr->nodeValue; - } - } - } - } - } - if (!$isSubCase) { - $attributesArr[$child->nodeName][$attr->nodeName] = $attr->nodeValue; - } - if ($isAllowedEltype && $isConfig) { - array_push($labelsArr, $child->nodeName); - break; - } - } - } - } - } - } else { - array_push($labelsArr, $element->nodeName); - } - - } - } - } - $labelsArr = array_values(array_unique($labelsArr)); - - $retArr['labels'] = $labelsArr; - $retArr['labelsAttributes'] = $attributesArr; - $retArr['elems'] = $elemsArr; - return $retArr; - } - - /** - * @param \SimpleXMLIterator $element - * @param \Twig_Template $template - * - * @param string $formId - * @param string $xPath - * @param string $requiredChildren - * @param array $identityRefs - * - * @return array|bool - */ - public function getChildrenValues($element, $template, $formId, $xPath = "", $requiredChildren = "", $identityRefs = array()) { - $retArr = array(); - $targetAttributes = array('key', 'iskey', 'mandatory'); - - foreach ($element as $label => $el) { - $attributesArr = array_fill_keys($targetAttributes, false); - - foreach ($element->attributes() as $name => $attr) { - if ($name == "key") { - $attributesArr[$name] = (string)$attr[0]; - } - } - - foreach ($el->attributes() as $name => $attr) { - if (in_array($name, array('iskey', 'mandatory'))) { - $attributesArr[$name] = (string)$attr[0]; - } - } - - if ( (($attributesArr['iskey'] !== "true" && $attributesArr['key'] == false) - || - ($requiredChildren !== "" && $label != $requiredChildren)) - && $attributesArr['mandatory'] == false - ) { - continue; - } - - if ($attributesArr['key'] !== false) { - $requiredChildren = $attributesArr['key']; - } else { - $requiredChildren = ""; - } - - $twigArr = array(); - $twigArr['key'] = ""; - $twigArr['xpath'] = ""; - $twigArr['element'] = $el; - $twigArr['useHiddenInput'] = true; - $twigArr['moduleIdentityRefs'] = $identityRefs; - - $newXPath = $xPath . "/*"; - $res = $this->getAvailableLabelValuesForXPath($formId, $newXPath); - - $retArr[$label] = array(); - if (isset($res['labelsAttributes'][$label])) { - $retArr[$label]['labelAttributes'] = $res['labelsAttributes'][$label]; - } - $retArr[$label]['valueElem'] = $this->removeMultipleWhitespaces($template->renderBlock('configInputElem', $twigArr)); - $retArr[$label]['children'] = $this->getChildrenValues($el, $template, $formId, $newXPath, $requiredChildren); - } - - return sizeof($retArr) ? $retArr : false; - } - - public function removeMultipleWhitespaces($str) { - return preg_replace( "/\s+/", " ", $str ); - } -} From 974c65dbe06a412f2c7520942d4a49caefbc56d0 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 26 Jan 2016 11:11:07 +0100 Subject: [PATCH 018/113] moves samlToState under Services/Managers namespace --- src/FIT/NetopeerBundle/Resources/config/services.yml | 2 +- .../{Models => Services/Managers}/SamlToState.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/FIT/NetopeerBundle/{Models => Services/Managers}/SamlToState.php (99%) diff --git a/src/FIT/NetopeerBundle/Resources/config/services.yml b/src/FIT/NetopeerBundle/Resources/config/services.yml index 1124030d..8217b37f 100644 --- a/src/FIT/NetopeerBundle/Resources/config/services.yml +++ b/src/FIT/NetopeerBundle/Resources/config/services.yml @@ -61,7 +61,7 @@ services: arguments: [@doctrine.orm.entity_manager, @security.context, @data_logger] SamlToState: - class: FIT\NetopeerBundle\Models\SamlToState + class: FIT\NetopeerBundle\Services\Managers\SamlToState arguments: [@service_container, @data_logger] netopeer.twig.netopeer_twig_extension: diff --git a/src/FIT/NetopeerBundle/Models/SamlToState.php b/src/FIT/NetopeerBundle/Services/Managers/SamlToState.php similarity index 99% rename from src/FIT/NetopeerBundle/Models/SamlToState.php rename to src/FIT/NetopeerBundle/Services/Managers/SamlToState.php index e7a9cc9f..ef6c76b8 100644 --- a/src/FIT/NetopeerBundle/Models/SamlToState.php +++ b/src/FIT/NetopeerBundle/Services/Managers/SamlToState.php @@ -36,7 +36,7 @@ * otherwise) arising in any way out of the use of this software, even * if advised of the possibility of such damage. */ -namespace FIT\NetopeerBundle\Models; +namespace FIT\NetopeerBundle\Services\Managers; use FIT\NetopeerBundle\Entity\SamlUser; use Symfony\Component\DependencyInjection\ContainerInterface; From 7c37e91930f364d15b56fa5280620cf0e0bd13f3 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 26 Jan 2016 13:23:45 +0100 Subject: [PATCH 019/113] build menu structure based on capabilities --- .../Controller/ModuleController.php | 17 +- .../Controller/ModuleController.php | 2 +- .../Controller/BaseController.php | 8 +- .../Controller/DefaultController.php | 2 +- .../Controller/ModuleController.php | 36 +-- .../Functionality/ConnectionFunctionality.php | 232 ++++++++---------- .../Functionality/NetconfFunctionality.php | 4 +- 7 files changed, 143 insertions(+), 158 deletions(-) diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php b/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php index 1821da78..1f0179a1 100644 --- a/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php +++ b/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php @@ -24,16 +24,17 @@ class ModuleController extends \FIT\NetopeerBundle\Controller\ModuleController i public function moduleAction($key, $module = null, $subsection = null) { $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); - if ($this->getRequest()->isXmlHttpRequest() || $this->getRequest()->get('angular') == "true") { // TODO - $res = $this->prepareDataForModuleAction("FITModuleDefaultBundle", $key, $module, $subsection); + $res = $this->prepareVariablesForModuleAction("FITModuleDefaultBundle", $key, $module, $subsection); - /* parent module did not prepares data, but returns redirect response, - * so we will follow this redirect - */ - if ($res instanceof RedirectResponse) { - return $res; - } + /* parent module did not prepares data, but returns redirect response, + * so we will follow this redirect + */ + if ($res instanceof RedirectResponse) { + return $res; + } + if ($this->getRequest()->isXmlHttpRequest() || $this->getRequest()->get('angular') == "true") { + $res = $this->loadDataForModuleAction("FITModuleDefaultBundle", $key, $module, $subsection); return new JsonResponse(json_decode($res)); } else { $this->assign('singleColumnLayout', true); diff --git a/src/FIT/Bundle/ModuleXmlBundle/Controller/ModuleController.php b/src/FIT/Bundle/ModuleXmlBundle/Controller/ModuleController.php index b45344e1..be62497e 100644 --- a/src/FIT/Bundle/ModuleXmlBundle/Controller/ModuleController.php +++ b/src/FIT/Bundle/ModuleXmlBundle/Controller/ModuleController.php @@ -17,7 +17,7 @@ class ModuleController extends \FIT\NetopeerBundle\Controller\ModuleController i */ public function moduleAction($key, $module = null, $subsection = null) { - $res = $this->prepareDataForModuleAction("FITModuleXmlBundle", $key, $module, $subsection); + $res = $this->prepareVariablesForModuleAction("FITModuleXmlBundle", $key, $module, $subsection); /* parent module did not prepares data, but returns redirect response, * so we will follow this redirect diff --git a/src/FIT/NetopeerBundle/Controller/BaseController.php b/src/FIT/NetopeerBundle/Controller/BaseController.php index 3cd57af0..b397f5ca 100644 --- a/src/FIT/NetopeerBundle/Controller/BaseController.php +++ b/src/FIT/NetopeerBundle/Controller/BaseController.php @@ -163,9 +163,9 @@ protected function prepareGlobalTwigVariables() { if (!in_array($this->getRequest()->get('_route'), array('connections', '_login')) && !strpos($this->getRequest()->get('_controller'), 'AjaxController')) { if (!in_array($this->getRequest()->get('_route'), array('createEmptyModule'))) { - $connectionFunc->buildMenuStructure($this->activeSectionKey); + $connectionFunc->buildMenuStructure($this->getActiveSectionKey()); } - $this->assign('topmenu', $connectionFunc->getModels()); + $this->assign('topmenu', $connectionFunc->getModels($this->getActiveSectionKey())); $this->assign('submenu', $connectionFunc->getSubmenu($this->submenuUrl, $this->getRequest()->get('key'))); } @@ -406,6 +406,10 @@ public function setActiveSectionKey($key) { * @return int|null section key */ public function getActiveSectionKey() { + $requestKey = intval($this->getRequest()->get('key')); + if (is_null($this->activeSectionKey) && isset($requestKey)) { + return $requestKey; + } return $this->activeSectionKey; } diff --git a/src/FIT/NetopeerBundle/Controller/DefaultController.php b/src/FIT/NetopeerBundle/Controller/DefaultController.php index 8aaeda86..228feae5 100644 --- a/src/FIT/NetopeerBundle/Controller/DefaultController.php +++ b/src/FIT/NetopeerBundle/Controller/DefaultController.php @@ -373,7 +373,7 @@ public function sessionInfoAction($key, $action) { $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); - parent::setActiveSectionKey($key); + $this->setActiveSectionKey($key); $connectionFunc->buildMenuStructure($key); $this->addAjaxBlock('FITModuleDefaultBundle:Module:section.html.twig', 'moduleJavascripts'); diff --git a/src/FIT/NetopeerBundle/Controller/ModuleController.php b/src/FIT/NetopeerBundle/Controller/ModuleController.php index c91f0f64..4ea16a51 100644 --- a/src/FIT/NetopeerBundle/Controller/ModuleController.php +++ b/src/FIT/NetopeerBundle/Controller/ModuleController.php @@ -65,19 +65,18 @@ class ModuleController extends BaseController { static protected $defaultModuleAction = "FIT\Bundle\ModuleDefaultBundle\Controller\ModuleController::moduleAction"; /** - * base method for getting data for module action + * base method for preparing variables for module action * * @param $bundleName * @param $key * @param null $module * @param null $subsection * - * @return \SimpleXMLIterator|RedirectResponse|null SimpleXMLIterator with state XML, redirectResponse when current page is not correct, null on some failure + * * @return RedirectResponse|null redirectResponse when current page is not correct, null on some failure */ - protected function prepareDataForModuleAction($bundleName, $key, $module = null, $subsection = null) + protected function prepareVariablesForModuleAction($bundleName, $key, $module = null, $subsection = null) { $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); - $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $this->bundleName = $bundleName; if ($this->getRequest()->getSession()->get('isLocking') !== true) { @@ -142,17 +141,26 @@ protected function prepareDataForModuleAction($bundleName, $key, $module = null, $this->assign('modelTreeDump', $modelTree); } + return null; + } + + /** + * base method for getting data for module action + * + * @param $bundleName + * @param $key + * @param null $module + * @param null $subsection + * + * @return json|null JSON with state data + */ + protected function loadDataForModuleAction($bundleName, $key, $module = null, $subsection = null) { + $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); + // loading state part = get Action // we will load it every time, because state column will we show everytime try { - - if ($module === 'all') { - $merge = false; - } else { - $merge = true; - } - - if ( ($json = $netconfFunc->handle('get', $this->getStateParams(), $merge)) != 1 ) { + if ( ($json = $netconfFunc->handle('get', $this->getStateParams())) != 1 ) { $this->assign("stateJson", $json); return $json; } @@ -500,7 +508,7 @@ protected function loadConfigArr($addConfigSection = true, $merge = true, $bundl * Checks if we have empty module in XML * * @param int $key - * @param string $xml result of prepareDataForModuleAction() + * @param string $xml result of prepareVariablesForModuleAction() */ protected function checkEmptyRootModule($key, $xml) { if ($xml instanceof \SimpleXMLIterator && $xml->count() == 0) { @@ -605,4 +613,4 @@ private function handleCopyConfig(&$key) { return 1; } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php index f86da8dc..9130cef0 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php @@ -72,6 +72,7 @@ class ConnectionFunctionality { protected $container; protected $modelNamespaces; + protected $models; /** * @return \Symfony\Bridge\Monolog\Logger @@ -143,11 +144,35 @@ public function setContainer( $container ) { $this->container = $container; } - public function getModels() { - // TODO + /** + * Get models. + * + * @param int $key session key of current connection + * @return array|null + */ + public function getModels($key) { + $hashedKey = $this->getHashFromKeys($key); + $hashedKey = array_pop($hashedKey); + if ($hashedKey && $this->getCache()->contains('menuStructure_'.$hashedKey)) { +// $this->logger->addInfo("Cached file for menuStructure found.", array('key' => 'menuStructure_'.$hashedKey)); + return $this->getCache()->fetch('menuStructure_'.$hashedKey); + } + return $this->models; } - + /** + * save model folder structure + * + * @param int $key session key of current connection + * @param array $models array to persist + * @param int $lifetime cache lifetime in seconds + */ + public function setModels($key, $models, $lifetime = 6000) { + $hashedKey = $this->getHashFromKeys($key); + $hashedKey = array_pop($hashedKey); + $this->models = $models; + $this->getCache()->save('menuStructure_'.$hashedKey, $models, $lifetime); + } /** @@ -194,7 +219,8 @@ public function getModuleIdentifiersForCurrentDevice($key) { return false; } $sessionStatus = json_decode($conn->sessionStatus); - $capabilities = $sessionStatus->capabilities; + $sid = $this->getHashFromKeys($key)[0]; + $capabilities = $sessionStatus->$sid->capabilities; $arr = array(); if (is_array($capabilities) && count($capabilities)) { @@ -443,94 +469,53 @@ public function checkLoggedKeys() { * @param string $path */ public function buildMenuStructure($key, $path = "") { -// TODO - return; + // we will build menu structure only if we have not build it before - if ( !$this->getModels($key) || !$this->getModelNamespaces($key) ) { - $finder = new Finder(); + if ( 1 || !$this->getModels($key) || !$this->getModelNamespaces($key) ) { + $models = array(); + $namespaces = array(); - $params = array( - 'key' => $key, - 'source' => 'running', - 'filter' => "", - ); + $netconfFunc = $this->getContainer()->get('fitnetopeerbundle.service.netconf.functionality'); + $json = json_decode($netconfFunc->handle('get', array('connIds' => array($key))), true); - $allowedModels = array(); - $allowedSubmenu = array(); - $namespaces = array(); + $modifiedJson = array(); + foreach ($json as $name => $val) { + $newKey = substr($name, 0, strpos($name, ':')); + $modifiedJson[$newKey] = array($name => $val); + } - try { - // load GET XML from server - if ( ($xml = $this->handle('get', $params, false)) != 1 ) { - $xml = simplexml_load_string($xml, 'SimpleXMLIterator'); + if ($this->getModuleIdentifiersForCurrentDevice($key)) { + foreach ( $this->getModuleIdentifiersForCurrentDevice( $key ) as $ns => $values ) { - $xmlNameSpaces = $xml->getNamespaces(); + $i = 0; + $moduleName = $values['moduleName']; - if ( isset($xmlNameSpaces[""]) ) { - $xml->registerXPathNamespace("xmlns", $xmlNameSpaces[""]); - $nodes = $xml->xpath('/xmlns:*'); + if (isset($modifiedJson[$moduleName])) { + $configuration = $modifiedJson[$moduleName]; } else { - $nodes = $xml->xpath('/*'); + $configuration = array(); } - // get first level nodes (so without root) as items for top menu - foreach ($nodes as $node) { - foreach ($node as $nodeKey => $submenu) { - $ns = $submenu->getNameSpaces(); - $i = 0; - if (isset($namespaces[$nodeKey])) { - $i = 1; - while(isset($namespaces[$nodeKey.$i])) { - $i++; - } - $namespaces[$nodeKey.$i] = $ns[""]; - } else { - $namespaces[$nodeKey] = $ns[""]; - } - - if (!in_array(array("name" => $nodeKey, 'index' => $i), $allowedModels) ) { - $allowedModels[] = array("name" => $nodeKey, 'index' => $i); - } - - foreach ($submenu as $subKey => $tmp) { - if ( !in_array(array("name" => $subKey, 'index' => 0), $allowedSubmenu) ) { - $allowedSubmenu[] = array("name" => $subKey, 'index' => 0); - } - } - } - } - } - } catch (\ErrorException $e) { - $this->logger->addError("Could not build MenuStructure", array('key' => $key, 'path' => $path, 'error' => $e->getMessage())); - // nothing - } - $this->setModelNamespaces($key, $namespaces); - - - // we will check, if nodes from GET are same as models structure - // if not, they won't be displayed - $folders = array(); - sort($allowedModels); - foreach ($allowedModels as $module) { - $moduleWithIndex = $module['name']; - if ($module['index'] !== 0) { - $moduleWithIndex .= $module['index']; - } - if ($this->existsModelDirForName($moduleWithIndex)) { - $folders[$moduleWithIndex] = array( - 'path' => "module", - "params" => array( - 'key' => $key, - 'module' => $moduleWithIndex, + $models[ $moduleName ] = array( + 'path' => "module", + "params" => array( + 'key' => $key, + 'module' => $moduleName, ), - "title" => "detail of ".$this->getSectionName($module['name']), - "name" => $this->getSectionName($module['name']), - "children" => $this->buildSubmenu($key, $module, $allowedSubmenu), - "namespace" => $namespaces[$moduleWithIndex], + "title" => "detail of " . $this->getSectionName( $moduleName ), + "name" => $this->getSectionName( $moduleName ), + "children" => $this->buildSubmenu( $key, $moduleName, $configuration ), + "namespace" => $ns, + "version" => $values['revision'], ); + $namespaces[ $moduleName ] = $ns; } + } else { + $this->getLogger()->addError("Could not build MenuStructure", array('key' => $key)); + // nothing } - $this->setModels($key, $folders); + $this->setModelNamespaces($key, $namespaces); + $this->setModels($key, $models); } } @@ -539,51 +524,37 @@ public function buildMenuStructure($key, $path = "") { * * @param int $key session key of current connection * @param array $module array with indexes: name and index - * @param $allowedSubmenu * @param string $path * @return array */ - private function buildSubmenu($key, $module, $allowedSubmenu, $path = "") { - $finder = new Finder(); - - // TODO - - $moduleWithIndex = $module['name']; - if ($module['index'] !== 0) { - $moduleWithIndex .= $module['index']; - } - - // we will check, if nodes from GET are same as models structure - // if not, they won't be displayed -// $dir = $this->getPathToModels($moduleWithIndex); - if ( !file_exists($dir) ) { - $folders = array(); - } else { - $iterator = $finder - ->directories() - ->sortByName() - ->depth(0) - ->in($dir); - - $folders = array(); - foreach ($iterator as $folder) { - $subsection = $folder->getRelativePathname(); - if ( in_array(array("name" => $subsection, "index" => 0), $allowedSubmenu) ) { - $folders[] = array( - 'path' => "subsection", - "params" => array( - 'key' => $key, - 'module' => $moduleWithIndex, - 'subsection' => $subsection, - ), - "title" => "detail of ".$this->getSubsectionName($subsection), - "name" => $this->getSubsectionName($subsection), - // "children" => $this->getSubmenu($key, $completePath), - ); + private function buildSubmenu($key, $module, $configuration) { + $submodule = array(); + + if (sizeof($configuration)) { + $configuration = array_pop($configuration); + foreach ($configuration as $subsection => $val) { + if (strpos($subsection, '$@') !== false) continue; + + if (isset($configuration['$@'.$subsection])) { + $schema = $configuration['$@'.$subsection]; + if (isset($schema['eltype']) && $schema['eltype'] === "container") { + $submodule[] = array( + 'path' => "subsection", + "params" => array( + 'key' => $key, + 'module' => $module, + 'subsection' => $subsection, + ), + "title" => "detail of ".$this->getSubsectionName($subsection), + "name" => $this->getSubsectionName($subsection), + // "children" => $this->getSubmenu($key, $completePath), + ); + } } } } - return $folders; + + return $submodule; } /** @@ -594,13 +565,11 @@ private function buildSubmenu($key, $module, $allowedSubmenu, $path = "") { * @return array array with config and state filter */ public function loadFilters(&$module, &$subsection) { - // if file filter.txt exists in models, we will use it $filterState = $filterConfig = ""; - // TODO - $namespaces = $this->getModelNamespaces($this->getContainer()->get('request')->get('key')); - if (isset($namespaces[$module])) { $namespace = $namespaces[$module]; + if (isset($namespaces[$module])) { + $namespace = $namespaces[$module]; $filter = new \SimpleXMLElement("<".$module.">"); $filter->addAttribute('xmlns', $namespace); if ( $subsection ) { @@ -646,12 +615,14 @@ public function loadRPCsModel($module, $subsection) { * @return array|null */ public function getModelNamespaces($key) { - // TODO -// $hashedKey = $this->getHashFromKeys($key); -// if ($hashedKey && $this->getCache()->contains('modelNamespaces_'.$hashedKey)) { -//// $this->logger->addInfo("Cached file for modelNamespaces found.", array('key' => 'modelNamespaces_'.$hashedKey)); -// return $this->getCache()->fetch('modelNamespaces_'.$hashedKey); -// } + if (!$this->modelNamespaces) { + $hashedKey = $this->getHashFromKeys($key); + $hashedKey = array_pop($hashedKey); + if ($hashedKey && $this->getCache()->contains('modelNamespaces_'.$hashedKey)) { +// $this->getLogger()->addInfo("Cached file for modelNamespaces found.", array('key' => 'modelNamespaces_'.$hashedKey)); + return $this->getCache()->fetch('modelNamespaces_'.$hashedKey); + } + } return $this->modelNamespaces; } @@ -681,6 +652,7 @@ public function getNamespaceForModule($key, $module) { */ public function setModelNamespaces($key, $namespaces, $lifetime = 6000) { $hashedKey = $this->getHashFromKeys($key); + $hashedKey = array_pop($hashedKey); $this->modelNamespaces = $namespaces; $this->getCache()->save('modelNamespaces_'.$hashedKey, $namespaces, $lifetime); } @@ -703,11 +675,11 @@ public function invalidateAndRebuildMenuStructureForKey($key) { public function invalidateMenuStructureForKey($key) { $hashedKey = $this->getHashFromKeys($key); if ($hashedKey && $this->getCache()->contains('modelNamespaces_'.$hashedKey)) { - $this->logger->addInfo("Invalidate cached file", array('key' => 'modelNamespaces_'.$hashedKey)); + $this->getLogger()->addInfo("Invalidate cached file", array('key' => 'modelNamespaces_'.$hashedKey)); $this->getCache()->delete('modelNamespaces_'.$hashedKey); } if ($hashedKey && $this->getCache()->contains('menuStructure_'.$hashedKey)) { - $this->logger->addInfo("Invalidate cached file", array('key' => 'menuStructure_'.$hashedKey)); + $this->getLogger()->addInfo("Invalidate cached file", array('key' => 'menuStructure_'.$hashedKey)); $this->getCache()->delete('menuStructure_'.$hashedKey); } $this->getCache()->deleteDeads(); diff --git a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php index 98593443..f12f44eb 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php @@ -468,7 +468,7 @@ public function handle_get(&$sock, &$params) { "source" => "running", "strict" => isset($params['strict']) ? $params['strict'] : false, ); - $getParams = $this->addOptionalParams($getParams, $params, array('filters')); + $getParams = $this->addOptionalParams($getParams, $params, array('filter')); $decoded = $this->execute_operation($sock, $getParams); @@ -500,7 +500,7 @@ public function handle_getconfig(&$sock, &$params) { "source" => $params['source'], "strict" => isset($params['strict']) ? $params['strict'] : false, ); - $this->addOptionalParams($getconfigParams, $params, array('filters')); + $this->addOptionalParams($getconfigParams, $params, array('filter')); $decoded = $this->execute_operation($sock, $getconfigParams); return $this->checkDecodedData($decoded); From 5169b323b7e6a2ea5b167aa21cf2bb8ae1b1e7ef Mon Sep 17 00:00:00 2001 From: david alexa Date: Wed, 3 Feb 2016 09:28:29 +0100 Subject: [PATCH 020/113] oprava vkladani a mazani polozek --- css/sass/screen.scss | 5 ++-- css/stylesheets/screen.css | 4 +-- gulpfile.js | 16 +++++++++-- js/JSONedit.js | 2 +- js/directives2.js | 47 ++++++++++++++++--------------- public/templates.js | 4 +-- templates/directives/addItem.html | 9 ++++-- templates/types/object.html | 2 +- 8 files changed, 52 insertions(+), 37 deletions(-) diff --git a/css/sass/screen.scss b/css/sass/screen.scss index 1ec338b8..8bef99e4 100644 --- a/css/sass/screen.scss +++ b/css/sass/screen.scss @@ -1,4 +1,5 @@ //@import "compass/reset"; +@import "compass/css3"; .red { color: red; } @@ -20,7 +21,7 @@ } } .addItemKeyInput { font-weight: bold; } - .glyphicon-menu-right, .glyphicon-menu-down { float: left; cursor: pointer; position: relative; top: -22px; right: 22px; margin-right: -15px; } + .glyphicon-menu-right, .glyphicon-menu-down { float: left; cursor: pointer; position: relative; top: -16px; right: 22px; margin-right: -15px; } > json > .glyphicon-menu-down { display: none; } .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; height: 30px; display: block; i { display: block; } @@ -42,7 +43,7 @@ li .jsonContents { margin-left: 0px; } .jsonView { - .block { display: block; } + .block { clear: both; display: block; } .jsonItemDesc { font-family: Georgia, serif; color: grey; font-style: italic; cursor: default; line-height: 30px; } .objectDesc { cursor: default; } > json > .jsonItemDesc { display: block; float: left; position: relative; bottom: 25px; height: 0; width: 0; } diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css index f51e4923..652ef922 100644 --- a/css/stylesheets/screen.css +++ b/css/stylesheets/screen.css @@ -11,7 +11,7 @@ .jsonView input.keyinput { font-weight: bold; } .jsonView input[type="text"].addItemKeyInput, .jsonView input[type="text"].addItemValueInput { border: 1px solid #ccc; background: white; margin-left: 0; } .jsonView .addItemKeyInput { font-weight: bold; } -.jsonView .glyphicon-menu-right, .jsonView .glyphicon-menu-down { float: left; cursor: pointer; position: relative; top: -22px; right: 22px; margin-right: -15px; } +.jsonView .glyphicon-menu-right, .jsonView .glyphicon-menu-down { float: left; cursor: pointer; position: relative; top: -16px; right: 22px; margin-right: -15px; } .jsonView > json > .glyphicon-menu-down { display: none; } .jsonView .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; height: 30px; display: block; } .jsonView .addObjectItemBtn i { display: block; } @@ -26,7 +26,7 @@ li .jsonContents { margin-left: 0px; } -.jsonView .block { display: block; } +.jsonView .block { clear: both; display: block; } .jsonView .jsonItemDesc { font-family: Georgia, serif; color: grey; font-style: italic; cursor: default; line-height: 30px; } .jsonView .objectDesc { cursor: default; } .jsonView > json > .jsonItemDesc { display: block; float: left; position: relative; bottom: 25px; height: 0; width: 0; } diff --git a/gulpfile.js b/gulpfile.js index 0e1e6272..a51708e5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,5 +1,6 @@ -var gulp = require('gulp'); -var templateCache = require('gulp-angular-templatecache'); +var gulp = require('gulp') + watch = require('gulp-watch') + templateCache = require('gulp-angular-templatecache'); gulp.task('default', function () { return gulp.src('templates/**/*.html') @@ -8,4 +9,13 @@ gulp.task('default', function () { module: 'configurationTemplates' })) .pipe(gulp.dest('public')); -}); \ No newline at end of file +}); + +gulp.task('watch', function () { + gulp.watch('templates/**/*.html', ['default']) + .on('change', function(evt) { + console.log( + '[watcher] File ' + evt.path + ' was ' + evt.type + ', compiling...' + ); + }); +}); diff --git a/js/JSONedit.js b/js/JSONedit.js index 527922d4..ce3c4ef5 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -1,4 +1,4 @@ -var storage = Rhaboo.perishable("Some unique name"); +var storage = Rhaboo.perishable(window.location.href); var historyIndex = 0, historyUndo = 0; diff --git a/js/directives2.js b/js/directives2.js index 64ea32e2..287c19ac 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -52,8 +52,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { var boolName = "Boolean"; var literalName = "Literal"; - //scope.valueTypes = [stringName, objectName, arrayName, numberName, urlName, refName, boolName, literalName]; - scope.valueTypes = [stringName, objectName, arrayName, refName, boolName]; + scope.valueTypes = [stringName, objectName, arrayName, numberName, urlName, refName, boolName, literalName]; + scope.stringName = stringName; + //scope.valueTypes = [stringName, objectName, arrayName, refName, boolName]; scope.sortableOptions = { axis: 'y' }; @@ -148,12 +149,12 @@ NetopeerGUI.directive('ngModelOnblur', function() { delete obj[key]; } }; - scope.deleteKey = function(obj, key) { - if (getType(obj) == "Object") { + scope.deleteKey = function(key, obj, parent) { + if (getType(key, obj, parent) == "Object") { if( confirm('Delete "'+key+'" and all it contains?') ) { delete obj[key]; } - } else if (getType(obj) == "Array") { + } else if (getType(key, obj, parent) == "Array") { if( confirm('Delete "'+obj[key]+'"?') ) { obj.splice(key, 1); } @@ -165,41 +166,41 @@ NetopeerGUI.directive('ngModelOnblur', function() { var type = getType(key, obj, parent); if (type == "Object") { // check input for key - if (scope.keyName == undefined || scope.keyName.length == 0){ + if (parent.keyName == undefined || parent.keyName.length == 0){ alert("Please fill in a name"); - } else if (scope.keyName.indexOf("$") == 0){ + } else if (parent.keyName.indexOf("$") == 0){ alert("The name may not start with $ (the dollar sign)"); - } else if (scope.keyName.indexOf("_") == 0){ + } else if (parent.keyName.indexOf("_") == 0){ alert("The name may not start with _ (the underscore)"); } else { - if (obj[scope.keyName]) { - if( !confirm('An item with the name "'+scope.keyName + if (obj[parent.keyName]) { + if( !confirm('An item with the name "'+parent.keyName +'" exists already. Do you really want to replace it?') ) { return; } } // add item to object - switch(scope.valueType) { - case stringName: obj[scope.keyName] = scope.valueName ? scope.possibleNumber(scope.valueName) : ""; + switch(parent.valueType) { + case stringName: obj[parent.keyName] = parent.valueName ? parent.possibleNumber(parent.valueName) : ""; break; - case objectName: obj[scope.keyName] = {}; + case objectName: obj[parent.keyName] = {}; break; - case arrayName: obj[scope.keyName] = []; + case arrayName: obj[parent.keyName] = []; break; - case refName: obj[scope.keyName] = {"Reference!!!!": "todo"}; + case refName: obj[parent.keyName] = {"Reference!!!!": "todo"}; break; - case boolName: obj[scope.keyName] = false; + case boolName: obj[parent.keyName] = false; break; } //clean-up - scope.keyName = ""; - scope.valueName = ""; - scope.showAddKey = false; + parent.keyName = ""; + parent.valueName = ""; + parent.showAddKey = false; } } else if (type == "Array") { // add item to array - switch(scope.valueType) { - case stringName: obj.push(scope.valueName ? scope.valueName : ""); + switch(parent.valueType) { + case stringName: obj.push(parent.valueName ? parent.valueName : ""); break; case objectName: obj.push({}); break; @@ -210,8 +211,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { case refName: obj.push({"Reference!!!!": "todo"}); break; } - scope.valueName = ""; - scope.showAddKey = false; + parent.valueName = ""; + parent.showAddKey = false; } else { console.error("object to add to was " + obj); } diff --git a/public/templates.js b/public/templates.js index da485289..b9d88f2b 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ -angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n\n \n\n : \n\n \n \n \n \n \n \n
      "); +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n :\n \n\n\n \n\n \n\n \n \n \n \n \n \n
      "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
      \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); -$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file +$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index e292e02d..da847027 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -1,11 +1,14 @@
      - + + : + + - : + \n \n \n \n \n \n
      "); +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n :\n \n\n\n \n\n \n\n \n \n \n \n \n \n
      "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); -$templateCache.put("types/array.html","\n
      \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); -$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file +$templateCache.put("types/array.html","\n
      \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); +$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index da847027..b526bf61 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -19,7 +19,7 @@
      \ No newline at end of file diff --git a/templates/types/array.html b/templates/types/array.html index f1214a96..dd87f5f9 100644 --- a/templates/types/array.html +++ b/templates/types/array.html @@ -1,4 +1,4 @@ - +
      1. diff --git a/templates/types/object.html b/templates/types/object.html index 1752e446..e7f7840d 100644 --- a/templates/types/object.html +++ b/templates/types/object.html @@ -1,12 +1,12 @@ - +
        {{ key }} - + - + From 9f8ed81d3a0c82346d8d02ff2975486b35958b0a Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 9 Feb 2016 11:21:31 +0100 Subject: [PATCH 022/113] pridani atributu xc-operation: create pri zmene, oprava prekresleni konfigurace pri vytazeni z historie (zmena hodnoty inputu) --- js/JSONedit.js | 25 ++++++++++++++++++------- js/directives2.js | 10 ++++++++-- public/templates.js | 2 +- templates/directives/switchItem.html | 6 +++--- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/js/JSONedit.js b/js/JSONedit.js index ce3c4ef5..eb928fa6 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -28,9 +28,7 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) $scope.reload(); $scope.$watch('jsonData', function (newValue, oldValue) { - $timeout(function() { - $scope.jsonString = JSON.stringify(newValue); - }, 100); + $scope.jsonString = JSON.stringify(newValue); if ( !isUndo && !isRedo && newValue !== oldValue ) { historyIndex = historyIndex - historyUndo; historyUndo = 0; @@ -44,6 +42,7 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) isUndo = false; isRedo = false; }, true); + $scope.$watch('jsonString', function (json) { try { $scope.jsonData = JSON.parse(json); @@ -73,15 +72,27 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) $scope.undo = function() { var json = storage.revisions[historyIndex - historyUndo - 2]; isUndo = true; - $scope.jsonData = JSON.parse(json); - historyUndo++; + $scope.jsonString = '{}'; + + $timeout(function() { + isUndo = true; + $scope.jsonString = json; + //$scope.jsonData = JSON.parse(json); + historyUndo++; + }, 1); }; $scope.redo = function() { var json = storage.revisions[historyIndex - historyUndo]; isRedo = true; - $scope.jsonData = JSON.parse(json); - historyUndo--; + $scope.jsonString = '{}'; + + $timeout(function() { + isRedo = true; + $scope.jsonString = json; + //$scope.jsonData = JSON.parse(json); + historyUndo--; + }, 1); }; } ); \ No newline at end of file diff --git a/js/directives2.js b/js/directives2.js index 1ed2616a..a0e066b8 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -217,8 +217,14 @@ NetopeerGUI.directive('ngModelOnblur', function() { console.error("object to add to was " + obj); } }; - scope.possibleNumber = function(val) { - return isNumber(val) ? parseFloat(val) : val; + scope.changeValue = function(child, key, val) { + child[key] = val; + if (typeof child['@'+key] === "undefined") { + child['@'+key] = { + 'xc-operation': '' + } + } + child['@'+key]['xc-operation'] = 'create'; }; ////// diff --git a/public/templates.js b/public/templates.js index ca9c2cc7..661ca781 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
        \n \n \n :\n \n\n\n \n\n \n\n \n \n \n \n \n \n
        "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
        \n
          \n
        1. \n \n
        2. \n
        \n \n
        "); $templateCache.put("types/object.html","\n
        \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
        ");}]); \ No newline at end of file diff --git a/templates/directives/switchItem.html b/templates/directives/switchItem.html index 8fd40763..7be2a847 100644 --- a/templates/directives/switchItem.html +++ b/templates/directives/switchItem.html @@ -3,15 +3,15 @@ - + {{ val }} - + {{ val }} - + {{ val }} \ No newline at end of file From fac6bf795c45fe76c63dc5c16d2a8e8be5712fa5 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 3 Feb 2016 12:57:24 +0100 Subject: [PATCH 023/113] upravy zarovanni ikonek a odstraneni font-family --- css/sass/screen.scss | 16 ++++++++-------- css/stylesheets/screen.css | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/css/sass/screen.scss b/css/sass/screen.scss index 6794ef49..25325821 100644 --- a/css/sass/screen.scss +++ b/css/sass/screen.scss @@ -26,12 +26,12 @@ $fa-font-path: "../netopeer-gui/bundles/fitmoduledefault/netopeerangular/css/fon } } .addItemKeyInput { font-weight: bold; } - .fa-plus-square-o, .fa-minus-square-o { float: left; cursor: pointer; position: relative; top: -16px; right: 22px; margin-right: -15px; } + .fa-plus-square-o, .fa-minus-square-o { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } > json > .fa-minus-square-o { display: none; } - .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; height: 30px; display: block; + .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0;display: block; i { display: block; } } - .iconButton { float: right; margin-right: 10px; position: relative; top: 7px; z-index: 99999999999999; cursor: pointer; } + .iconButton { float: right; margin-right: 10px; position: relative; top: -1px; z-index: 99999999999999; cursor: pointer; } .jsonObjectKey { font-weight: bold; margin-right: 25px; } } @@ -48,8 +48,8 @@ $fa-font-path: "../netopeer-gui/bundles/fitmoduledefault/netopeerangular/css/fon li .jsonContents { margin-left: 0px; } .jsonView { - .block { clear: both; display: block; } - .jsonItemDesc { font-family: Georgia, serif; color: grey; font-style: italic; cursor: default; line-height: 30px; } + .block { clear: both; display: block; margin-bottom: 0.5em; } + .jsonItemDesc { color: grey; font-style: italic; cursor: default; line-height: 30px; } .objectDesc { cursor: default; } > json > .jsonItemDesc { display: block; float: left; position: relative; bottom: 25px; height: 0; width: 0; } ol.arrayOl { margin: 0; padding-left: 20px; } @@ -61,12 +61,12 @@ li .jsonContents { margin-left: 0px; } > li > span > span > json > { .fa-minus-square-o, .fa-plus-square-o { left: -40px; } } - li { color: grey; font-style: italic; font-family: Georgia, serif; list-style-type: decimal; - input { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal; } + li { color: grey; font-style: italic; list-style-type: decimal; + input { font-style: normal; } } } li { - select, button { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal;} + select, button { font-style: normal;} } ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { color: black; } li li { diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css index 953cbf38..9e120af9 100644 --- a/css/stylesheets/screen.css +++ b/css/stylesheets/screen.css @@ -1297,11 +1297,11 @@ .jsonView input.keyinput { font-weight: bold; } .jsonView input[type="text"].addItemKeyInput, .jsonView input[type="text"].addItemValueInput { border: 1px solid #ccc; background: white; margin-left: 0; } .jsonView .addItemKeyInput { font-weight: bold; } -.jsonView .fa-plus-square-o, .jsonView .fa-minus-square-o { float: left; cursor: pointer; position: relative; top: -16px; right: 22px; margin-right: -15px; } +.jsonView .fa-plus-square-o, .jsonView .fa-minus-square-o { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } .jsonView > json > .fa-minus-square-o { display: none; } -.jsonView .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; height: 30px; display: block; } +.jsonView .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; display: block; } .jsonView .addObjectItemBtn i { display: block; } -.jsonView .iconButton { float: right; margin-right: 10px; position: relative; top: 7px; z-index: 99999999999999; cursor: pointer; } +.jsonView .iconButton { float: right; margin-right: 10px; position: relative; top: -1px; z-index: 99999999999999; cursor: pointer; } .jsonView .jsonObjectKey { font-weight: bold; margin-right: 25px; } /* inputs */ @@ -1312,8 +1312,8 @@ li .jsonContents { margin-left: 0px; } -.jsonView .block { clear: both; display: block; } -.jsonView .jsonItemDesc { font-family: Georgia, serif; color: grey; font-style: italic; cursor: default; line-height: 30px; } +.jsonView .block { clear: both; display: block; margin-bottom: 0.5em; } +.jsonView .jsonItemDesc { color: grey; font-style: italic; cursor: default; line-height: 30px; } .jsonView .objectDesc { cursor: default; } .jsonView > json > .jsonItemDesc { display: block; float: left; position: relative; bottom: 25px; height: 0; width: 0; } .jsonView ol.arrayOl { margin: 0; padding-left: 20px; } @@ -1322,9 +1322,9 @@ li .jsonContents { margin-left: 0px; } .jsonView ol.arrayOl .fa-minus-square-o { top: 7px; } .jsonView ol.arrayOl .fa-plus-square-o { top: -16px; } .jsonView ol.arrayOl > li > span > span > json > .fa-minus-square-o, .jsonView ol.arrayOl > li > span > span > json > .fa-plus-square-o { left: -40px; } -.jsonView ol.arrayOl li { color: grey; font-style: italic; font-family: Georgia, serif; list-style-type: decimal; } -.jsonView ol.arrayOl li input { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal; } -.jsonView li select, .jsonView li button { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-style: normal; } +.jsonView ol.arrayOl li { color: grey; font-style: italic; list-style-type: decimal; } +.jsonView ol.arrayOl li input { font-style: normal; } +.jsonView li select, .jsonView li button { font-style: normal; } .jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { color: black; } .jsonView li li { list-style-type: lower-roman; } .jsonView li li li { list-style-type: upper-roman; } From cd49a18ee31d79fe451151ab224bdf51aba0e762 Mon Sep 17 00:00:00 2001 From: david alexa Date: Wed, 10 Feb 2016 10:40:25 +0100 Subject: [PATCH 024/113] ve vnorenych seznamech poli nezobrazujeme toggle tlacitko --- css/sass/screen.scss | 10 +++++----- css/stylesheets/screen.css | 8 +++----- public/templates.js | 4 ++-- templates/types/array.html | 2 +- templates/types/object.html | 2 +- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/css/sass/screen.scss b/css/sass/screen.scss index 25325821..eece1363 100644 --- a/css/sass/screen.scss +++ b/css/sass/screen.scss @@ -26,7 +26,7 @@ $fa-font-path: "../netopeer-gui/bundles/fitmoduledefault/netopeerangular/css/fon } } .addItemKeyInput { font-weight: bold; } - .fa-plus-square-o, .fa-minus-square-o { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } + .toggle-control { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } > json > .fa-minus-square-o { display: none; } .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0;display: block; i { display: block; } @@ -55,11 +55,11 @@ li .jsonContents { margin-left: 0px; } ol.arrayOl { margin: 0; padding-left: 20px; } li {clear: both;min-height: 30px; } ol.arrayOl { - .fa-minus-square-o, .fa-plus-square-o { margin-left: -20px; } - .fa-minus-square-o { top: 7px; } - .fa-plus-square-o { top: -16px; } + .toggle-control { margin-left: -20px; top: 1.3em; display: none; } + //.fa-minus-square-o { top: 7px; } + //.fa-plus-square-o { top: -16px; } > li > span > span > json > { - .fa-minus-square-o, .fa-plus-square-o { left: -40px; } + .toggle-control { left: -40px; } } li { color: grey; font-style: italic; list-style-type: decimal; input { font-style: normal; } diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css index 9e120af9..76bfb6ff 100644 --- a/css/stylesheets/screen.css +++ b/css/stylesheets/screen.css @@ -1297,7 +1297,7 @@ .jsonView input.keyinput { font-weight: bold; } .jsonView input[type="text"].addItemKeyInput, .jsonView input[type="text"].addItemValueInput { border: 1px solid #ccc; background: white; margin-left: 0; } .jsonView .addItemKeyInput { font-weight: bold; } -.jsonView .fa-plus-square-o, .jsonView .fa-minus-square-o { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } +.jsonView .toggle-control { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } .jsonView > json > .fa-minus-square-o { display: none; } .jsonView .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; display: block; } .jsonView .addObjectItemBtn i { display: block; } @@ -1318,10 +1318,8 @@ li .jsonContents { margin-left: 0px; } .jsonView > json > .jsonItemDesc { display: block; float: left; position: relative; bottom: 25px; height: 0; width: 0; } .jsonView ol.arrayOl { margin: 0; padding-left: 20px; } .jsonView li { clear: both; min-height: 30px; } -.jsonView ol.arrayOl .fa-minus-square-o, .jsonView ol.arrayOl .fa-plus-square-o { margin-left: -20px; } -.jsonView ol.arrayOl .fa-minus-square-o { top: 7px; } -.jsonView ol.arrayOl .fa-plus-square-o { top: -16px; } -.jsonView ol.arrayOl > li > span > span > json > .fa-minus-square-o, .jsonView ol.arrayOl > li > span > span > json > .fa-plus-square-o { left: -40px; } +.jsonView ol.arrayOl .toggle-control { margin-left: -20px; top: 1.3em; display: none; } +.jsonView ol.arrayOl > li > span > span > json > .toggle-control { left: -40px; } .jsonView ol.arrayOl li { color: grey; font-style: italic; list-style-type: decimal; } .jsonView ol.arrayOl li input { font-style: normal; } .jsonView li select, .jsonView li button { font-style: normal; } diff --git a/public/templates.js b/public/templates.js index 661ca781..0016e269 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
        \n \n \n :\n \n\n\n \n\n \n\n \n \n \n \n \n \n
        "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); -$templateCache.put("types/array.html","\n
        \n
          \n
        1. \n \n
        2. \n
        \n \n
        "); -$templateCache.put("types/object.html","\n
        \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
        ");}]); \ No newline at end of file +$templateCache.put("types/array.html","\n
        \n
          \n
        1. \n \n
        2. \n
        \n \n
        "); +$templateCache.put("types/object.html","\n
        \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
        ");}]); \ No newline at end of file diff --git a/templates/types/array.html b/templates/types/array.html index dd87f5f9..9d3e62c6 100644 --- a/templates/types/array.html +++ b/templates/types/array.html @@ -1,4 +1,4 @@ - +
        1. diff --git a/templates/types/object.html b/templates/types/object.html index e7f7840d..2be3b726 100644 --- a/templates/types/object.html +++ b/templates/types/object.html @@ -1,4 +1,4 @@ - +
          From 715897c98476bd4aa06cb5d08d91cd14ff4bc627 Mon Sep 17 00:00:00 2001 From: david alexa Date: Wed, 10 Feb 2016 10:49:27 +0100 Subject: [PATCH 025/113] oprava zarovani vnorenych seznamu --- css/sass/screen.scss | 3 +++ css/stylesheets/screen.css | 2 ++ 2 files changed, 5 insertions(+) diff --git a/css/sass/screen.scss b/css/sass/screen.scss index eece1363..bc998048 100644 --- a/css/sass/screen.scss +++ b/css/sass/screen.scss @@ -64,6 +64,9 @@ li .jsonContents { margin-left: 0px; } li { color: grey; font-style: italic; list-style-type: decimal; input { font-style: normal; } } + ol.arrayOl { margin-top: 15px; + &, & + add-item .block { margin-left: 25px; } + } } li { select, button { font-style: normal;} diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css index 76bfb6ff..25f5a206 100644 --- a/css/stylesheets/screen.css +++ b/css/stylesheets/screen.css @@ -1322,6 +1322,8 @@ li .jsonContents { margin-left: 0px; } .jsonView ol.arrayOl > li > span > span > json > .toggle-control { left: -40px; } .jsonView ol.arrayOl li { color: grey; font-style: italic; list-style-type: decimal; } .jsonView ol.arrayOl li input { font-style: normal; } +.jsonView ol.arrayOl ol.arrayOl { margin-top: 15px; } +.jsonView ol.arrayOl ol.arrayOl, .jsonView ol.arrayOl ol.arrayOl + add-item .block { margin-left: 25px; } .jsonView li select, .jsonView li button { font-style: normal; } .jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { color: black; } .jsonView li li { list-style-type: lower-roman; } From 5d418263873cf48067efeef775e69d8e2cc56b30 Mon Sep 17 00:00:00 2001 From: david alexa Date: Wed, 10 Feb 2016 10:55:54 +0100 Subject: [PATCH 026/113] revert omylem smazane funkce possibleNumber --- js/directives2.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/directives2.js b/js/directives2.js index a0e066b8..cd95aa1b 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -217,6 +217,10 @@ NetopeerGUI.directive('ngModelOnblur', function() { console.error("object to add to was " + obj); } }; + scope.possibleNumber = function(val) { + return isNumber(val) ? parseFloat(val) : val; + }; + scope.changeValue = function(child, key, val) { child[key] = val; if (typeof child['@'+key] === "undefined") { From 00a093dafdb45f0ac5d915b5a6afe4f22e6075ef Mon Sep 17 00:00:00 2001 From: david alexa Date: Fri, 12 Feb 2016 19:27:11 +0100 Subject: [PATCH 027/113] pridana podpora pro naseptavani nazvu novych uzlu, pridana podpora vykresleni typu Enumeration --- js/directives2.js | 29 ++++++++++++++++++++++------ public/templates.js | 4 ++-- templates/directives/addItem.html | 7 ++++--- templates/directives/switchItem.html | 4 ++++ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/js/directives2.js b/js/directives2.js index cd95aa1b..c26214f6 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -31,7 +31,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { child: '=', type: '@', defaultCollapsed: '=', - hideCollapse: '=' + hideCollapse: '=', + key: '=' }, controller: function($scope) { $scope.getTemplateUrl = function(type) { @@ -50,9 +51,10 @@ NetopeerGUI.directive('ngModelOnblur', function() { var urlName = "Url"; var refName = "Reference"; var boolName = "Boolean"; + var enumerationName = "Enumeration"; var literalName = "Literal"; - scope.valueTypes = [stringName, objectName, arrayName, numberName, urlName, refName, boolName, literalName]; + scope.valueTypes = [stringName, objectName, arrayName, numberName, urlName, refName, boolName, enumerationName, literalName]; scope.stringName = stringName; //scope.valueTypes = [stringName, objectName, arrayName, refName, boolName]; scope.sortableOptions = { @@ -85,6 +87,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { var schema = getSchemaFromKey(key, parent); // get custom yang datatype var type = Object.prototype.toString.call(obj); + var eltype = ''; if (type === "[object Object]") { return objectName; @@ -96,9 +99,21 @@ NetopeerGUI.directive('ngModelOnblur', function() { type = schema['type']; } - if(type === "Boolean" || type === "[object Boolean]"){ + if (schema && typeof schema['eltype'] !== "undefined") { + eltype = schema['eltype']; + } + + if (eltype === "container") { + return objectName; + } else if (eltype === "leaf-list") { + return arrayName; + } else if (type === "[object Array]"){ + return arrayName; + } else if (type === "Boolean" || type === "[object Boolean]") { return boolName; - } else if(isNumberType(type) || type === "[object Number]"){ + } else if (type === 'enumeration') { + return enumerationName; + } else if (isNumberType(type) || type === "[object Number]") { // TODO: check range return numberName; } else { @@ -108,8 +123,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { var isNumber = function(n) { return !isNaN(parseFloat(n)) && isFinite(n); }; - scope.getType = function(key, obj, parent) { - return getType(key, obj, parent); + scope.getType = getType; + scope.log = function(data) { + console.log(data); }; var getSchemaFromKey = function(key, parent) { @@ -118,6 +134,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { } return parent['$@'+key]; }; + scope.getSchemaFromKey = getSchemaFromKey; scope.isConfig = function(key, parent) { var schema = getSchemaFromKey(key, parent); diff --git a/public/templates.js b/public/templates.js index 0016e269..c5cf8c71 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ -angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
          \n \n \n :\n \n\n\n \n\n \n\n \n \n \n \n \n \n
          "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
          \n \n \n :\n \n {{ log(getSchemaFromKey($parent.keyName, $parent.$parent.$parent.child[$parent.$parent.$parent.$parent.key])) }}\n {{ log(getType($parent.keyName, undefined, $parent.$parent.$parent.child[$parent.$parent.$parent.$parent.key])) }}\n\n \n\n \n \n \n \n \n \n \n \n \n
          "); +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
          \n
            \n
          1. \n \n
          2. \n
          \n \n
          "); $templateCache.put("types/object.html","\n
          \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
          ");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index b526bf61..a7ebe1d8 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -2,13 +2,14 @@ : + class="form-control input-sm addItemKeyInput" ng-model="$parent.keyName" uib-typeahead="subchild for subchild in $parent.$parent.$parent.child['$@'+ $parent.$parent.$parent.$parent.key]['children']" autocomplete="off" + /> : - - + + \n \n \n \n \n \n
          "); +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
          \n \n \n :\n \n\n \n\n \n \n\n \n \n \n \n \n \n
          "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
          \n
            \n
          1. \n \n
          2. \n
          \n \n
          "); $templateCache.put("types/object.html","\n
          \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
          ");}]); \ No newline at end of file From 2824afe2fea38661c9be5815fe26ec25c8eed092 Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 23 Feb 2016 08:19:12 +0100 Subject: [PATCH 029/113] libyang and netopeerangular added as submodules --- .gitmodules | 10 +++++++++- install/libyang | 1 + install/mod_netconf | 2 +- .../ModuleDefaultBundle/Resources/netopeerangular | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) create mode 160000 install/libyang diff --git a/.gitmodules b/.gitmodules index 65757d62..c394eacc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,11 @@ -[submodule "install/mod_netconf"] +[submodule "mod_netconf"] path = install/mod_netconf url = https://github.com/CESNET/mod_netconf.git + +[submodule "libyang"] + path = install/libyang + url = https://github.com/CESNET/libyang.git + +[submodule "netopeerangular"] + path = src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular + url = https://alexadav@bitbucket.org/alexadav/netopeerangular.git diff --git a/install/libyang b/install/libyang new file mode 160000 index 00000000..ea441fc5 --- /dev/null +++ b/install/libyang @@ -0,0 +1 @@ +Subproject commit ea441fc58eb64a2b9e3a46e3fb32109ed7817a14 diff --git a/install/mod_netconf b/install/mod_netconf index 74dd7a97..a40bcb46 160000 --- a/install/mod_netconf +++ b/install/mod_netconf @@ -1 +1 @@ -Subproject commit 74dd7a97e511b95108a9118d35bec42d17cb6f47 +Subproject commit a40bcb467b6d6d004ffba3f2a1b2ecaf6cae6745 diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular index a8c7fe97..00a093da 160000 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular @@ -1 +1 @@ -Subproject commit a8c7fe9715761dbbc493df312208d5518f9fac3c +Subproject commit 00a093dafdb45f0ac5d915b5a6afe4f22e6075ef From 5efb13ceacc4d93353bcbc8604019920d1d73377 Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 23 Feb 2016 09:08:11 +0100 Subject: [PATCH 030/113] disables ajax loading of links for a while (new netopeerangular does not support it yet) --- .../Resources/public/js/jquery.netopeergui.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FIT/NetopeerBundle/Resources/public/js/jquery.netopeergui.js b/src/FIT/NetopeerBundle/Resources/public/js/jquery.netopeergui.js index 0b063c4a..3315342f 100644 --- a/src/FIT/NetopeerBundle/Resources/public/js/jquery.netopeergui.js +++ b/src/FIT/NetopeerBundle/Resources/public/js/jquery.netopeergui.js @@ -282,7 +282,7 @@ jQuery(function($) { $.netopeergui.createSpinner(); $(document).on('click', 'a.ajaxLink', function(e) { - $.netopeergui.loadAjaxLink(e, $(this), $(this).attr('href'), "GET", ''); + //$.netopeergui.loadAjaxLink(e, $(this), $(this).attr('href'), "GET", ''); }); $("section, #block--leftColumn").on('submit', 'form', function(e) { @@ -301,12 +301,12 @@ jQuery(function($) { }); } - $.netopeergui.loadAjaxLink(e, $(this), formAction, 'POST', serializedData); + //$.netopeergui.loadAjaxLink(e, $(this), formAction, 'POST', serializedData); }); $("body").on('submit', '.modal form', function(e) { $(this).attr('data-callback', 'hideAndEmptyModalWindow()'); - $.netopeergui.loadAjaxLink(e, $(this), $(this).attr('action'), 'POST', $(this).serialize()); + //$.netopeergui.loadAjaxLink(e, $(this), $(this).attr('action'), 'POST', $(this).serialize()); }); }); From 96555d46d19511ca4588c97b87b5603afa5f9b8f Mon Sep 17 00:00:00 2001 From: david alexa Date: Fri, 26 Feb 2016 16:19:29 +0100 Subject: [PATCH 031/113] pyang submodule removed. New install script for centos7 created. Added base support for vagrant, not working properly yet --- .gitmodules | 4 - Vagrantfile | 14 ++ install/centos7/install.sh | 60 +++++ install/libyang | 1 - install/pyang/Makefile.am | 6 - install/pyang/README | 26 -- install/pyang/nmp.py | 386 ----------------------------- install/pyang/resptempl.py | 210 ---------------- install/pyang/wyin.py | 492 ------------------------------------- 9 files changed, 74 insertions(+), 1125 deletions(-) create mode 100644 Vagrantfile create mode 100644 install/centos7/install.sh delete mode 160000 install/libyang delete mode 100644 install/pyang/Makefile.am delete mode 100644 install/pyang/README delete mode 100644 install/pyang/nmp.py delete mode 100644 install/pyang/resptempl.py delete mode 100644 install/pyang/wyin.py diff --git a/.gitmodules b/.gitmodules index c394eacc..d33b8557 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,10 +2,6 @@ path = install/mod_netconf url = https://github.com/CESNET/mod_netconf.git -[submodule "libyang"] - path = install/libyang - url = https://github.com/CESNET/libyang.git - [submodule "netopeerangular"] path = src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular url = https://alexadav@bitbucket.org/alexadav/netopeerangular.git diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 00000000..cb9d319e --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,14 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + config.vm.box = "centos/7" + + config.vm.network "forwarded_port", guest: 80, host: 2280 + config.vm.network "forwarded_port", guest: 5555, host: 5555 + + config.vm.provision "shell", inline: <<-SHELL + ./install/centos7/install.sh +# sudo rpm -ivh https://homeproj.cesnet.cz/rpm/liberouter/devel/x86_64/liberouter-devel-1.0.0-1.noarch.rpm +SHELL +end diff --git a/install/centos7/install.sh b/install/centos7/install.sh new file mode 100644 index 00000000..809e1d60 --- /dev/null +++ b/install/centos7/install.sh @@ -0,0 +1,60 @@ +sudo yum install -y wget git gcc gcc-c++ + +sudo yum install -y zlib1g-devel libssl-devel openssl-devel cmake pcre-devel +wget https://red.libssh.org/attachments/download/177/libssh-0.7.2.tar.xz +tar -xJf libssh-0.7.2.tar.xz +mkdir -p libssh-0.7.2/build && cd libssh-0.7.2/build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DLIB_INSTALL_DIR=/usr/lib64 .. && make -j2 && sudo make install +cd ../.. + +git clone https://github.com/CESNET/libyang.git +mkdir -p libyang/build && cd libyang/build +git checkout devel +cmake -DCMAKE_INSTALL_PREFIX=/usr -DLIB_INSTALL_DIR=lib64 -DENABLE_BUILD_TESTS=OFF .. && sudo make install && sudo make install + +cd ../.. +wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz +tar -xJf cmocka-1.0.1.tar.xz +mkdir -p cmocka-1.0.1/build && cd cmocka-1.0.1/build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install + +cd ../.. +git clone git://github.com/cejkato2/libwebsockets lws +mkdir lws/b && cd lws/b +cmake .. && sudo make install + + +# libnetconf2 +# +cd ../.. +git clone https://github.com/CESNET/libnetconf2.git +git checkout devel +mkdir -p libnetconf2/build && cd libnetconf2/build +cmake -DENABLE_TLS=ON -DENABLE_SSH=ON -DENABLE_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/usr -DLIB_INSTALL_DIR=lib64 .. && sudo make install + + +# libnetconf +# +# cd ../.. +# sudo yum install -y python-setuptools +# git clone https://github.com/mbj4668/pyang.git +# cd pyang +# python setup.py install + +# cd ../.. +# git clone --depth 1 https://github.com/CESNET/libnetconf.git +# sudo yum install -y libxml2-devel libxslt-devel curl-devel libtool +# cd libnetconf +# ./configure --prefix=/usr --libdir=/usr/lib64 -q + + +cd ../.. +cd mod_netconf +# sudo yum install -y json-c-devel +./bootstrap.sh +./configure +make +make install + +ldconfig + diff --git a/install/libyang b/install/libyang deleted file mode 160000 index ea441fc5..00000000 --- a/install/libyang +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ea441fc58eb64a2b9e3a46e3fb32109ed7817a14 diff --git a/install/pyang/Makefile.am b/install/pyang/Makefile.am deleted file mode 100644 index cb5556e4..00000000 --- a/install/pyang/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -webbindir=$(webguidir)/$(webguiname)/src/FIT/NetopeerBundle/bin - -dist_pyplugin_SCRIPTS=nmp.py resptempl.py wyin.py - -EXTRA_DATA=README - diff --git a/install/pyang/README b/install/pyang/README deleted file mode 100644 index 2b27df52..00000000 --- a/install/pyang/README +++ /dev/null @@ -1,26 +0,0 @@ --* About *- -The set of these plug-ins can be used to generate -processed data model for netconfwebgui. -The output is a hierarchical directory structure -with files containing filters and model parts. - --* Prerequisites: *- -Installed pyang version 1.2 on the system. - --* Installation of pyang(1) plug-ins: *- -Copy plug-ins source codes into pyang(1) plugins directory: - -# cp {nmp,resptempl,wyin}.py /usr/lib/python2.6/site-packages/pyang/plugins - --* Usage *- -The simplifies method is to use nmp.sh script. -Script accepts all model formats that pyang(1) supports. - -To get help, execute nmp.sh without arguments. - -Example: -Read model ietf-netconf-monitoring from the current directory -and generate output directories hierarchy in -the /tmp/models directory: -$ ./nmp.sh -i ietf-netconf-monitoring.yang -o /tmp/models - diff --git a/install/pyang/nmp.py b/install/pyang/nmp.py deleted file mode 100644 index f55d147d..00000000 --- a/install/pyang/nmp.py +++ /dev/null @@ -1,386 +0,0 @@ -"""NMP - Netopeer Model Processing plugin - -Idea copied from libsmi. -Created from tree plugin -""" - -import optparse -import sys -import re -import string -import os -import shutil -"""for debug""" -import pprint -import copy -import pdb - -from pyang import plugin -from pyang import statements -from pyang import translators -from pyang.translators.yin import YINPlugin - -CONFIG_STR="config" -STATE_STR="state" - -def pyang_plugin_init(): - plugin.register_plugin(nmpPlugin()) - -class nmpPlugin(plugin.PyangPlugin): - def add_output_format(self, fmts): - self.multiple_modules = True - fmts['nmp'] = self - - def add_opts(self, optparser): - optlist = [ - optparse.make_option("--nmp-help", - dest="nmp_help", - action="store_true", - help="Print help on tree symbols and exit"), - optparse.make_option("--nmp-depth", - type="int", - dest="nmp_depth", - help="Number of levels to print"), - optparse.make_option("--nmp-maxdepth", - type="int", - dest="nmp_maxdepth", - default=2, - help="How many subsection layers to create?"), - optparse.make_option("--nmp-genidentifier", - action="store_true", - dest="nmp_genident", - help="Generate identifier of model and exit"), - optparse.make_option("--nmp-minchildsec", - type="int", - dest="nmp_minchildsec", - default=3, - help="Minimal amount of children to leave in section."), - optparse.make_option("--nmp-breaktree", - action="store_true", - dest="nmp_breaktree", - help="Remove config or state tree."), - optparse.make_option("--nmp-config", - action="store_true", - dest="nmp_config", - help="Generate config or state tree? Generate config if set, otherwise state."), - optparse.make_option("--nmp-outputdir", - type="string", - dest="nmp_outputdir", - help="Where to generate directory tree?"), - optparse.make_option("--nmp-path", - dest="nmp_path", - help="Subtree to print"), - optparse.make_option("--nmp-hostname", - dest="nmp_hostname", - type="string", - default="", - help="Hostname of device that provided model (via get-schema)"), - optparse.make_option("--nmp-port", - dest="nmp_port", - type="string", - default="", - help="Network port of connection to device that provided model (via get-schema)"), - optparse.make_option("--nmp-username", - dest="nmp_username", - type="string", - default="", - help="Username used for connection to device that provided model (via get-schema)"), - ] - g = optparser.add_option_group("Netopeer Model Processing plugin specific options") - g.add_options(optlist) - - def setup_ctx(self, ctx): - if ctx.opts.nmp_help: - print_help() - sys.exit(0) - - def setup_fmt(self, ctx): - ctx.implicit_errors = False - - def emit(self, ctx, modules, fd): - if not ctx.opts.nmp_maxdepth: - ctx.opts.nmp_maxdepth = 2 - if not ctx.opts.nmp_minchildsec: - ctx.opts.nmp_minchildsec = 2 - if ctx.opts.nmp_config: - ctx.opts.nmp_config = (ctx.opts.nmp_config == 1) - else: - ctx.opts.nmp_config = False - pp = pprint.PrettyPrinter(indent=4) - #pp.pprint(dir()) - #pp.pprint(vars(self)) - #pp.pprint(vars(ctx.repository)) - #pp.pprint(dir(modules)) - #pp.pprint(fd) - #pp.pprint(ctx.opts) - emit_nmp(modules, fd, ctx) - -def print_help(): - print """ -TODO help -""" -def create_sect_dir(path): - #print "Creation of directory: %s" % path - try: - os.makedirs(path) - except: - print "Cannot create directory \"%s\"" % path - pass - -class Separator(): - def __init__(self, depth, path, statement): - self.depth = depth - self.path = path - self.statement = statement - def __str__(self): - return "SEPARATOR %i %s %s" % (self.depth, self.path, self.statement.arg) - -def remove_elemtype(root, conftype): - """Remove all elements which are configuration or state. - - root - root element - conftype - list of element types to remove (the rest is not mentioned) - ["config", "state"]""" - - if not conftype: - #print "!!!!NO CONFTYPE!!!!", root.arg, root.keyword, conftype - return False - #print "Called remove_elemtype", conftype - empty = True - if hasattr(root, "i_children") and root.i_children: - for n in root.i_children: - # go through all subtrees - if not empty: - remove_elemtype(n, conftype) - else: - empty = remove_elemtype(n, conftype) - #print "Config of element", root.arg, root.i_config - # subtrees are solved - - if not empty: - #print "Cannot remove non-empty", root.arg, conftype - return False - - doRemove = False - if (CONFIG_STR in conftype): - #remove configuration - if root.i_config == True: - doRemove = True - if (STATE_STR in conftype): - #remove state - if root.i_config == False: - doRemove = True - if doRemove: - removed=False - try: - index = root.parent.substmts.index(root) - root.parent.substmts.pop(index) - #print "REMOVEDsu", root.arg, conftype, root.i_config, empty - return True - except ValueError: - #print "NOT FOUND", root.arg, root.keyword - return False - else: - #print "NOT REMOVED", root.arg, conftype, root.i_config, empty - return False - -def statement_copyrec(parent,origstmt): - new = copy.copy(origstmt) - new.parent = parent - new.top = None - - if hasattr(origstmt, "substmts"): - new.substmts = [] - for s in origstmt.substmts: - new.substmts.append(statement_copyrec(new,s)) - if hasattr(origstmt, "i_children"): - new.i_children = [] - for s in origstmt.i_children: - new.i_children.append(statement_copyrec(new,s)) - return new - - -def statement_deepcopy(origstmt): - """origstmt should be root element""" - return statement_copyrec(None,origstmt) - - -def save_model_part(ctx, root_element, filepath, modeltype): - """Save YIN part of model into file in filepath""" - - #remove state if modeltype is not "config" - if ctx.opts.nmp_breaktree: - if modeltype in [CONFIG_STR, STATE_STR]: - if modeltype == CONFIG_STR: - remove_elemtype(root_element, STATE_STR) - else: - remove_elemtype(root_element, CONFIG_STR) - else: - modeltype = "getpart" - - modelpart = open(filepath + "/" + modeltype + ".yin", "w") - yin = YINPlugin() - yin.emit(ctx, [root_element], modelpart) - modelpart.close() - -def dive_into_section_queue(section, fd, ctx, curpath, maxdepth): - queue = [section] - p = pprint.PrettyPrinter(); - while queue: - node = queue.pop(0) - if isinstance(node, Separator): - print node #separator - continue - elif isinstance(node, list): - if not node: - continue - print "start" - for i in node: - if hasattr(i, "i_children") and i.i_children: - queue.append(i.i_children) - else: - print "\tleaf", i.arg, i.keyword - print "stop" - else: - print "\t", node.arg, node.keyword - if hasattr(node, "i_children") and node.i_children: - queue.append(node.i_children) - #queue.append(Separator(depth, curpath, node.parent)) - return - -def generate_filter(subcurpath, subsection, namespace): - filterfile = open(subcurpath + "/filter.txt", "w") - - #pdb.set_trace() - if not hasattr(subsection, "parent") or subsection.parent.keyword == "module": - filterstr = "<%s xmlns=\"%s\"/>" % (subsection.arg, namespace) - cn = None - else: - filterstr = "<%s/>" % subsection.arg - cn = subsection.parent - - while cn: - key = cn.search_one('key') - if key: - #iterate over words in - for i in re.finditer(r'\S+', key.arg): - filterstr = "<%s/>%s" % (i.group(0), filterstr) - else: - #print "No key for", cn.arg, cn.keyword - pass - if (cn.parent and cn.parent.keyword == "module") or cn.keyword == "module": - filterstr = "<%s xmlns=\"%s\">%s" % (cn.arg, namespace, filterstr, cn.arg) - break - else: - filterstr = "<%s>%s" % (cn.arg, filterstr, cn.arg) - cn = cn.parent - filterfile.write(filterstr) - filterfile.write("\n") - filterfile.close() - -def dive_into_section(section, fd, ctx, curpath, maxdepth, modelname, namespace): - """ Iterate over model and create submodels - modelname - string, name of output file""" - maxdepth -= 1 - #pdb.set_trace() - #print vars(section) - if hasattr(section, "i_children"): - for subsection in section.i_children: - if subsection.keyword in ["container", "list"]: - if subsection.parent.i_children.__len__() >= ctx.opts.nmp_minchildsec and subsection.arg !="data": - subcurpath = curpath + "/" + subsection.arg - create_sect_dir(subcurpath) - - generate_filter(subcurpath, subsection, namespace) - - if maxdepth > 0: - dive_into_section(subsection, fd, ctx, copy.deepcopy(curpath), maxdepth, modelname, namespace) - else: - save_model_part(ctx, subsection, subcurpath, modelname) - else: - dive_into_section(subsection, fd, ctx, copy.deepcopy(curpath), maxdepth, modelname, namespace) - - else: - save_model_part(ctx, section, curpath, modelname) - -def generate_identifier(module, ctx): - revnodes = module.search("revision") - revisions = [] - for rev in revnodes: - revisions.append(rev.arg) - revisions.sort() - version = revisions[-1:][0] # get last version - - rootelem = module.search_one("container") - rootelemarg = "" - if rootelem and rootelem.arg: - rootelemarg = rootelem.arg - namespace = "" - if rootelem and rootelem.top: - namespace = rootelem.top.search_one("namespace").arg - prepare = "%s" % (namespace) - import hashlib - print "Unhashed identifier:", prepare - ident = hashlib.sha1(prepare).hexdigest() - print "Identifier:", ident - import json - print "JSON ", json.dumps({'module': module.i_modulename, 'version': version, 'root_element': rootelemarg, 'ns': namespace, 'host': ctx.opts.nmp_hostname, 'port': ctx.opts.nmp_port, 'user': ctx.opts.nmp_username, 'identifier': ident}) - return [ident,prepare] - - -def emit_nmp(modules, fd, ctx): - """ emit_nmp(modules, fd, depth, path, config) - modules - list of Statements - fd - output file descriptor - ctx - Context of module (ctx.opts contains parameters) - """ - if not ctx.opts.nmp_outputdir: - print "Enter output directory for processed model by --nmp_outputdir." - return - print "Output directory was set to \"%s\"" % ctx.opts.nmp_outputdir - - for module in modules: - pp = pprint.PrettyPrinter(indent=4) - #pp.pprint(vars(module)) - namespace = "" - ns_element = module.search_one('namespace') - if ns_element and hasattr(ns_element, "arg"): - namespace = ns_element.arg - print "Namespace", namespace - modelfile = module.pos.ref - - #Module should be placed in separate directory - print module.i_modulename, module.keyword - - #Generate indentifier and use it as the name of a directory to store data - model_identifier = generate_identifier(module, ctx) - if ctx.opts.nmp_genident: - continue #skip parsing etc - curpathname = ctx.opts.nmp_outputdir - - create_sect_dir(curpathname) - shutil.copy(modelfile, curpathname) - ident = open("%s/ident-unhashed.txt" % ctx.opts.nmp_outputdir, "w") - ident.write(model_identifier[1]) - ident.close() - - # iterate over module - for section in module.i_children: - if section.keyword == "container": - print "Generate global filter.txt" - generate_filter(curpathname, module.search("container")[0], namespace) - #iterate over sections - if ctx.opts.nmp_maxdepth > 0: - if ctx.opts.nmp_config: - #print "Module loop", modelname - #copiedsection = statement_deepcopy(section) - dive_into_section(section, fd, ctx, curpathname, ctx.opts.nmp_maxdepth, CONFIG_STR, namespace) - else: - dive_into_section(section, fd, ctx, curpathname, ctx.opts.nmp_maxdepth, STATE_STR, namespace) - else: - save_model_part(ctx, section, curpathname, "rest") - else: - #print section.arg, section.keyword - pass - return - diff --git a/install/pyang/resptempl.py b/install/pyang/resptempl.py deleted file mode 100644 index 7ad3784d..00000000 --- a/install/pyang/resptempl.py +++ /dev/null @@ -1,210 +0,0 @@ -"""Tree output plugin - -Idea copied from libsmi. -Created from tree plugin -""" - -import optparse -import sys -import re -import string - -from pyang import plugin -from pyang import statements - -def pyang_plugin_init(): - plugin.register_plugin(ResptemplPlugin()) - -class ResptemplPlugin(plugin.PyangPlugin): - def add_output_format(self, fmts): - self.multiple_modules = True - fmts['resptempl'] = self - - def add_opts(self, optparser): - optlist = [ - optparse.make_option("--resptempl-help", - dest="resptempl_help", - action="store_true", - help="Print help on tree symbols and exit"), - optparse.make_option("--resptempl-depth", - type="int", - dest="resptempl_depth", - help="Number of levels to print"), - optparse.make_option("--resptempl-config", - type="int", - dest="resptempl_config", - help="Generate config or state tree? 1 for config otherwise state."), - optparse.make_option("--resptempl-path", - dest="resptempl_path", - help="Subtree to print"), - ] - g = optparser.add_option_group("Response template output specific options") - g.add_options(optlist) - - def setup_ctx(self, ctx): - if ctx.opts.resptempl_help: - print_help() - sys.exit(0) - - def setup_fmt(self, ctx): - ctx.implicit_errors = False - - def emit(self, ctx, modules, fd): - if ctx.opts.resptempl_path is not None: - path = string.split(ctx.opts.resptempl_path, '/') - if path[0] == '': - path = path[1:] - else: - path = None - if ctx.opts.resptempl_config: - resptempl_config = (ctx.opts.resptempl_config == 1) - else: - resptempl_config = False - print resptempl_config - emit_resptempl(modules, fd, ctx.opts.resptempl_depth, path, resptempl_config) - -def print_help(): - print """ -Each node is printed as: - -""" - -def emit_resptempl(modules, fd, depth, path, config): - for module in modules: - bstr = "" - b = module.search_one('belongs-to') - if b is not None: - bstr = " (belongs-to %s)" % b.arg - #fd.write("%s: %s%s\n" % (module.keyword, module.arg, bstr)) - fd.write('\n') - chs = [ch for ch in module.i_children - if ch.keyword in statements.data_definition_keywords] - if path is not None and len(path) > 0: - chs = [ch for ch in chs - if ch.arg == path[0]] - path = path[1:] - - print_children(chs, module, fd, ' ', path, depth, pcconfig=config) - - rpcs = module.search('rpc') - if path is not None and len(path) > 0: - rpcs = [rpc for rpc in rpcs - if rpc.arg == path[0]] - path = path[1:] - if len(rpcs) > 0: - fd.write('\n') - print_children(rpcs, module, fd, ' ', path, depth, pcconfig=config) - - notifs = module.search('notification') - if path is not None and len(path) > 0: - notifs = [n for n in notifs - if n.arg == path[0]] - path = path[1:] - if len(notifs) > 0: - fd.write("notifications:\n") - print_children(notifs, module, fd, ' ', path, depth, pcconfig=config) - -def print_children(i_children, module, fd, prefix, path, depth, pcconfig, width=0): - if depth == 0: - return - def get_width(w, chs): - for ch in chs: - if ch.keyword in ['choice', 'case']: - w = get_width(w, ch.i_children) - else: - if ch.i_module.i_modulename == module.i_modulename: - nlen = len(ch.arg) - else: - nlen = len(ch.i_module.i_prefix) + 1 + len(ch.arg) - if nlen > w: - w = nlen - return w - - if width == 0: - width = get_width(0, i_children) - - for ch in i_children: - if ch == i_children[-1]: - newprefix = prefix + ' ' - else: - newprefix = prefix + ' |' - if ((ch.arg == 'input' or ch.arg == 'output') and - ch.parent.keyword == 'rpc' and - len(ch.i_children) == 0 and - ch.parent.search_one(ch.arg) is None): - pass - else: - print_node(ch, module, fd, newprefix, path, depth, width, pnconfig=pcconfig) - -def find_nodes_by_state(nodes, conf): - for n in nodes: - if n.i_config == conf: - return True - else: - if hasattr(n, "i_children"): - if find_nodes_by_state(n.i_children, conf): - return True - return False - -def print_node(s, module, fd, prefix, path, depth, width, pnconfig): - ##fd.write("-%s-%s" % (prefix[0:-1], width)) - - if s.i_module.i_modulename == module.i_modulename: - name = s.arg - else: - name = s.i_module.i_prefix + ':' + s.arg - flags = get_flags_str(s) - if s.search_one('uses'): - if s.search_one('uses').arg.startswith('histogram'): - if s.i_config == pnconfig: - fd.write("<%s/>\n" % name) - return - if (hasattr(s, 'i_children') and s.i_children): - if depth is not None: - depth = depth - 1 - chs = s.i_children - if path is not None and len(path) > 0: - chs = [ch for ch in chs - if ch.arg == path[0]] - path = path[1:] - iscontent = find_nodes_by_state(chs, pnconfig) - if iscontent: - if name == "packet-sizes": - print s, dir(s), - fd.write("<%s>\n" % name) - if s.keyword in ['choice', 'case']: - print_children(chs, module, fd, prefix, path, depth, width, pcconfig=pnconfig) - else: - print_children(chs, module, fd, prefix, path, depth, pcconfig=pnconfig) - fd.write("\n" % name) - else: - if s.i_config == pnconfig: - fd.write("<%s/>\n" % name) - #else: - # fd.write("\n" % (name, s.i_config)) - -def get_status_str(s): - status = s.search_one('status') - if status is None or status.arg == 'current': - return '+' - elif status.arg == 'deprecated': - return 'x' - elif status.arg == 'obsolete': - return 'o' - -def get_flags_str(s): - if s.keyword == 'rpc': - return '-x' - elif s.keyword == 'notification': - return '-n' - elif s.i_config == True: - return 'rw' - else: - return 'ro' - -def get_typename(s): - t = s.search_one('type') - if t is not None: - return t.arg - else: - return '' diff --git a/install/pyang/wyin.py b/install/pyang/wyin.py deleted file mode 100644 index 44161699..00000000 --- a/install/pyang/wyin.py +++ /dev/null @@ -1,492 +0,0 @@ -"""Wrapped YIN output plugin for Netopeer web purpose. -Move substatements to element attributes is easier -and more useful in GUI processing.""" - -from xml.sax.saxutils import quoteattr -from xml.sax.saxutils import escape - -import optparse -import re -import sys -import pdb - -from pyang import plugin -from pyang import util -from pyang import grammar -from pyang import syntax -from pyang import statements - -yin_namespace = "urn:ietf:params:xml:ns:yang:yin:1" - -identityrefs = {} -wyin_namespace = "" -wyin_prefix = "" -wyin_nsprefixes = {} - -def pyang_plugin_init(): - plugin.register_plugin(WYINPlugin()) - -class WYINPlugin(plugin.PyangPlugin): - def add_opts(self, optparser): - optlist = [ - optparse.make_option("--wyin-canonical", - dest="wyin_canonical", - action="store_true", - help="Print in canonical order"), - optparse.make_option("--wyin-pretty-strings", - dest="wyin_pretty_strings", - action="store_true", - help="Pretty print strings"), - optparse.make_option("--wyin-enum-delim", - type="string", - dest="enum_delim", - default='|', - help="Set delimiter of values for enumerate items."), - optparse.make_option("--wyin-outputdir", - type="string", - dest="wyin_outputdir", - help="Where to generate files?"), - ] - g = optparser.add_option_group("wYIN output specific options") - g.add_options(optlist) - def setup_fmt(self, ctx): - ctx.implicit_errors = False - def add_output_format(self, fmts): - self.multiple_modules = True - fmts['wyin'] = self - def postprocess_rpcfile(self, filepath): - # Read content of generated rpc.yin to remove xmldoc type - rpcfile = open(filepath, "r") - text = rpcfile.readlines() - rpcfile.close() - if text: - rpcfile = open(filepath, "w") - rpcfile.write(text[0]) - # wrap RPC operations into root element - rpcfile.write("\n") - for line in text[1:]: - rpcfile.write(line.replace('\n', '')) - rpcfile.write("\n") - rpcfile.close() - def emit(self, ctx, modules, fd): - #module = modules[0] - for module in modules: - emit_wyin(ctx, module, fd) - - if not ctx.opts.wyin_outputdir: - print "Enter output directory for processed model by --wyin_outputdir." - return - rpcfilepath = "%s/rpc.wyin" % ctx.opts.wyin_outputdir - rpcfile = open(rpcfilepath, "w") - global yin_namespace - yin_namespace_backup = yin_namespace - yin_namespace = wyin_namespace - for module in modules: - for section in module.i_children: - if section.keyword == "rpc": - emit_wyin(ctx, section, rpcfile) - yin_namespace = yin_namespace_backup - rpcfile.close() - self.postprocess_rpcfile(rpcfilepath) - -def escape2xml(str): - return str.replace("&", "&").\ - replace("<", "<").\ - replace(">", ">").\ - replace("'", "'").\ - replace('"', """) - -def emit_wyin(ctx, module, fd): - global wyin_prefix, wyin_namespace, wyin_nsprefixes - fd.write('\n') - if module.keyword and module.arg: - fd.write('<%s name="%s"\n' % (module.keyword, module.arg)) - fd.write(' ' * len(module.keyword) + ' xmlns="%s"' % yin_namespace) - - wyin_init_prefix(ctx, module) - - if wyin_nsprefixes: - for p,ns in wyin_nsprefixes.iteritems(): - namespace = module.search_one('namespace') - fd.write('\n') - fd.write(' ' * len(module.keyword)) - fd.write(' xmlns:' + p + '=' + - quoteattr(ns)) - - fd.write('>\n') - - wyin_init_identityrefs(ctx, module) - for i in module.substmts: - if i not in module.i_children: - emit_stmt(ctx, module, i, fd, " ", " ") - chs = [ch for ch in module.i_children - if ch.keyword in statements.data_definition_keywords] - print_node(ctx, chs, module, fd) - fd.write('\n' % module.keyword) - #end of document - -def wyin_init_prefix(ctx, module): - global wyin_prefix, wyin_namespace, wyin_nsprefixes - prefix = module.search_one('prefix') - if prefix is not None: - namespace = module.search_one('namespace') - wyin_prefix = prefix.arg - wyin_namespace = namespace.arg - wyin_nsprefixes[prefix.arg] = namespace.arg - else: - belongs_to = module.search_one('belongs-to') - if belongs_to is not None: - prefix = belongs_to.search_one('prefix') - if prefix is not None: - # read the parent module in order to find the namespace uri - res = ctx.read_module(belongs_to.arg, extra={'no_include':True}) - if res is not None: - namespace = res.search_one('namespace') - if namespace is None or namespace.arg is None: - pass - else: - # success - namespace found - wyin_namespace = namespace.arg - wyin_nsprefixes[prefix.arg] = namespace.arg - wyin_prefix = prefix.arg - for imp in module.search('import'): - prefix = imp.search_one('prefix') - if prefix is not None: - rev = None - r = imp.search_one('revision-date') - if r is not None: - rev = r.arg - mod = statements.modulename_to_module(module, imp.arg, rev) - if mod is not None: - ns = mod.search_one('namespace') - if ns is not None: - wyin_nsprefixes[prefix.arg] = ns.arg - -def wyin_init_identityrefs(ctx, module): - #pdb.set_trace() - for ident in module.search("identity"): - processIdentityref(ctx, ident) - -# Processing method for statements -def emit_stmt(ctx, module, stmt, fd, indent, indentstep, keys = []): - if util.is_prefixed(stmt.raw_keyword): - # this is an extension. need to find its definition - (prefix, identifier) = stmt.raw_keyword - tag = prefix + ':' + identifier - if stmt.i_extension is not None: - ext_arg = stmt.i_extension.search_one('argument') - if ext_arg is not None: - wyin_element = ext_arg.search_one('yin-element') - if wyin_element is not None and wyin_element.arg == 'true': - argname = prefix + ':' + ext_arg.arg - argiselem = True - else: - # explicit false or no yin-element given - argname = ext_arg.arg - argiselem = False - else: - argiselem = False - argname = None - else: - argiselem = False - argname = None - else: - (argname, argiselem) = syntax.yin_map[stmt.raw_keyword] - tag = stmt.raw_keyword - if argiselem == False or argname is None: - if argname is None: - attr = '' - else: - attr = ' ' + argname + '=' + quoteattr(stmt.arg) - if len(stmt.substmts) == 0: - fd.write(indent + '<' + tag + attr + '/>\n') - else: - if argname and argname in "name": - fd.write(indent + ('<%s eltype="%s"' % (stmt.arg, tag))) - else: - fd.write(indent + '<' + tag + attr) - - used_substmts = 0 - printed_config = False - got_keys = False - for s in stmt.substmts: - if not printed_config: - conf_val = None - # find predecesor with i_config or use s' i_config - p = s - if not hasattr(p, "i_config"): - while (not hasattr(p, "i_config")) and (p != None): - p = p.parent - - # searching finished - if p: - conf_val = p.i_config.__str__().lower() - if conf_val == "none": - conf_val = "true" - # write config attribute - fd.write(' config="%s"' % conf_val) - printed_config = True - del p - - if s.raw_keyword == "key": - fd.write(' key="%s"' % s.arg) - keys = re.findall(r'\S+', s.arg) - got_keys = True - if s.raw_keyword in ["config", "type", "default", "description", "mandatory"]: - # already written - if s.raw_keyword in "config": - setattr(s, "i_config", s.arg) - else: - fd.write(' %s="%s"' % (s.raw_keyword, escape2xml(s.arg))) - if s.raw_keyword == "type": - if s.arg == "enumeration": - fd.write(' enumval="') - first_written = False - for charg in s.substmts: - if first_written: - fd.write(ctx.opts.enum_delim) - else: - first_written = True - fd.write(charg.arg) - fd.write('"') - elif s.arg == "identityref": - basename = get_basename(s) - if identityrefs.has_key(basename): - fd.write(" enumval=\"") - sep = False - for i in identityrefs[basename]: - if sep: - fd.write("|") - else: - sep = True - fd.write(i) - fd.write("\"") - else: - print "no basename %s" % basename - else: - if s.substmts: - #other type "attributes" - for charg in s.substmts: - if charg.raw_keyword == "range": - fd.write(' range="' + charg.arg + '"') - # count used substatements to know what is the rest - used_substmts += 1 - # mark key elements - if stmt.arg in keys: - fd.write(' iskey="true"') - else: - fd.write(' iskey="false"') - if not got_keys: - keys = [] - - # the rest of substatements: - if used_substmts < stmt.substmts.__len__(): - # Need to generate pair tag - fd.write('>\n') - for s in stmt.substmts: - if s.raw_keyword not in ["config", "type",\ - "default", "description", "mandatory",\ - "must", "when", "key"]: - emit_stmt(ctx, module, s, fd, indent + indentstep, - indentstep, keys) - if argname and argname in "name": - fd.write(indent + ('' % stmt.arg)) - else: - fd.write(indent + '\n') - else: - # Everything from child elements was used - fd.write('/>\n') - else: - fd.write(indent + '<' + tag + '>\n') - if ctx.opts.wyin_pretty_strings: - # since whitespace is significant in XML, the current - # code is strictly speaking incorrect. But w/o the whitespace, - # it looks too ugly. - fd.write(indent + indentstep + '<' + argname + '>\n') - fd.write(fmt_text(indent + indentstep + indentstep, stmt.arg)) - fd.write('\n' + indent + indentstep + '\n') - else: - try: - fd.write(indent + indentstep + '<' + argname + '>' + \ - escape(stmt.arg) + \ - '\n') - except Exception as e: - print argname - if ctx.opts.wyin_canonical: - substmts = grammar.sort_canonical(stmt.keyword, stmt.substmts) - else: - substmts = stmt.substmts - for s in substmts: - emit_stmt(ctx, module, s, fd, indent + indentstep, indentstep) - fd.write(indent + '\n') - -def fmt_text(indent, data): - res = [] - for line in re.split("(\n)", escape(data)): - if line == '': - continue - if line == '\n': - res.extend(line) - else: - res.extend(indent + line) - return ''.join(res) - - -def print_children(ctx, i_children, module, fd): - child_index = 1 - for ch in i_children: - print_node(ctx, ch, module, fd, child_index) - child_index += 1 - -def handleEnumeration(ctx, typeelem): - attrs = "" - if typeelem.substmts: - attrs += " enumval=\"" - first_written = False - for charg in typeelem.substmts: - if first_written: - attrs += ctx.opts.enum_delim - else: - first_written = True - attrs += charg.arg - attrs += "\"" - return attrs - -def stripBasenamePrefix(basename): - global identityrefs, wyin_nsprefixes - parts = basename.split(":") - if parts: - expns = wyin_nsprefixes.get(parts[0]) - if expns == wyin_namespace: - basename = ':'.join(parts[1:]) - return basename - -def updateIdentityrefList(ctx, basename, typename = False): - """update identityrefs dict: add derived identity name into base""" - global identityrefs, wyin_nsprefixes - - #remove global prefix - basename = stripBasenamePrefix(basename) - - if not identityrefs.has_key(basename): - if typename != False: - identityrefs[basename] = [typename] - else: - identityrefs[basename] = [] - else: - if typename != False: - identityrefs[basename].append(typename) - -def processIdentityref(ctx, s): - derived = False - for childs in s.substmts: - if childs.keyword == "base": - updateIdentityrefList(ctx, childs.arg, s.arg) - return - # there is no child element - updateIdentityrefList(ctx, s.arg) - -def handleTypes(ctx, typename, typeelem): - attrs = "" - if typename == "identityref": - basename = get_basename(typeelem) - if identityrefs.has_key(basename): - attrs += " enumval=\"" - sep = False - for i in identityrefs[basename]: - if sep: - attrs += "|" - else: - sep = True - attrs += i - attrs += "\"" - attrs += " identitybasename=\"" + basename + "\"" - else: - print "no basename %s" % basename - elif typename == "leafref": - # find path and add leafref-path attribute - leafref = typeelem.search_one("path") - if leafref: - attrs += " leafref-path=\"%s\"" % leafref.arg.__str__() - elif typename == "enumeration": - attrs += handleEnumeration(ctx, typeelem) - return attrs - -def getAttrs(ctx, s): - """ ctx - to make settings accessible - s - current element """ - global identityrefs - attrs="" - attrs += " eltype=\"%s\"" % s.keyword - attrs += " config=\"%s\"" % s.i_config.__str__().lower() - typeelem = get_typename(s) - if typeelem: - if hasattr(typeelem, "i_typedef") and typeelem.i_typedef: - typeelem = get_typename(typeelem.i_typedef) - typename = typeelem.arg - else: - typename = '' - if typename: - attrs += " type=\"%s\"" % typename - attrs += handleTypes(ctx, typename, typeelem) - - description = get_description(s) - if description: - attrs += " description=\"%s\"" % get_description(s) - - if s.keyword == 'leaf' and s.search_one('mandatory') is not None: - attrs += " mandatory=\"%s\"" % s.search_one('mandatory').arg.__str__().lower() - - if hasattr(s, "i_default") and s.i_default and s.search_one('default') and s.search_one('default').arg: - attrs += " default=\"%s\"" % s.search_one('default').arg.__str__() - if hasattr(s, "i_range") and s.i_range: - attrs += " range=\"%s\"" % s.i_range - - if s.keyword == 'list' and s.search_one('key') is not None: - attrs += " key=\"%s\"" % re.sub('\s+', ' ', s.search_one('key').arg) - - attrs += " iskey=" - if hasattr(s, "i_is_key") and s.i_is_key: - attrs += "\"%s\"" % s.i_is_key.__str__().lower() - else: - attrs += "\"false\"" - if s.search_one('ordered-by') is not None: - attrs += " orderedBy=\"%s\"" % s.search_one('ordered-by').arg - return attrs - - -def print_node(ctx, s, module, fd, child_idx = 1): - if type(s) == list: - for m in s: - print_node(ctx,m, module, fd, child_idx) - return - if s.i_module.i_modulename == module.i_modulename: - name = s.arg - else: - name = s.i_module.i_prefix + ':' + s.arg - if hasattr(s, 'i_children') and s.i_children: - fd.write("<%s%s model-level-index=\"%d\">" % (name, getAttrs(ctx, s), child_idx)) - print_children(ctx, s.i_children, module, fd) - fd.write("\n" % (name)) - else: - fd.write("<%s%s model-level-index=\"%d\"/>\n" % (name, getAttrs(ctx, s), child_idx)) - return - -def get_typename(s): - t = s.search_one('type') - return t - -def get_basename(s): - global identityrefs - t = s.search_one('base') - if t is not None: - return stripBasenamePrefix(t.arg) - else: - return '' - -def get_description(s): - t = s.search_one('description') - if t is not None: - return escape2xml(t.arg) - else: - return '' From 32fbbb707d0aea679b1c0636461eeeaeba0c3b4d Mon Sep 17 00:00:00 2001 From: david alexa Date: Fri, 26 Feb 2016 16:22:23 +0100 Subject: [PATCH 032/113] updated version of netopeerguid --- install/mod_netconf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/mod_netconf b/install/mod_netconf index a40bcb46..7f46ede6 160000 --- a/install/mod_netconf +++ b/install/mod_netconf @@ -1 +1 @@ -Subproject commit a40bcb467b6d6d004ffba3f2a1b2ecaf6cae6745 +Subproject commit 7f46ede6f209e12c9edd6051791f6b8b9c99a0c2 From 5d3015f6d922ee2ea567bad0791f927a00eae666 Mon Sep 17 00:00:00 2001 From: david alexa Date: Fri, 26 Feb 2016 16:51:54 +0100 Subject: [PATCH 033/113] install script modifications for availibility to run more than once --- install/centos7/install.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/install/centos7/install.sh b/install/centos7/install.sh index 809e1d60..278c60be 100644 --- a/install/centos7/install.sh +++ b/install/centos7/install.sh @@ -3,24 +3,28 @@ sudo yum install -y wget git gcc gcc-c++ sudo yum install -y zlib1g-devel libssl-devel openssl-devel cmake pcre-devel wget https://red.libssh.org/attachments/download/177/libssh-0.7.2.tar.xz tar -xJf libssh-0.7.2.tar.xz -mkdir -p libssh-0.7.2/build && cd libssh-0.7.2/build +mkdir -p libssh-0.7.2/build +cd libssh-0.7.2/build cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DLIB_INSTALL_DIR=/usr/lib64 .. && make -j2 && sudo make install cd ../.. git clone https://github.com/CESNET/libyang.git -mkdir -p libyang/build && cd libyang/build +mkdir -p libyang/build +cd libyang/build git checkout devel cmake -DCMAKE_INSTALL_PREFIX=/usr -DLIB_INSTALL_DIR=lib64 -DENABLE_BUILD_TESTS=OFF .. && sudo make install && sudo make install cd ../.. wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz tar -xJf cmocka-1.0.1.tar.xz -mkdir -p cmocka-1.0.1/build && cd cmocka-1.0.1/build +mkdir -p cmocka-1.0.1/build +cd cmocka-1.0.1/build cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install cd ../.. git clone git://github.com/cejkato2/libwebsockets lws -mkdir lws/b && cd lws/b +mkdir lws/b +cd lws/b cmake .. && sudo make install @@ -28,8 +32,9 @@ cmake .. && sudo make install # cd ../.. git clone https://github.com/CESNET/libnetconf2.git +mkdir -p libnetconf2/build +cd libnetconf2/build git checkout devel -mkdir -p libnetconf2/build && cd libnetconf2/build cmake -DENABLE_TLS=ON -DENABLE_SSH=ON -DENABLE_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/usr -DLIB_INSTALL_DIR=lib64 .. && sudo make install From 68255f57ef0a73b155ca71c0f3eb62f3d977b7c1 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 1 Mar 2016 10:05:31 +0100 Subject: [PATCH 034/113] install script for centos6 --- install/centos6/install.sh | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100755 install/centos6/install.sh diff --git a/install/centos6/install.sh b/install/centos6/install.sh new file mode 100755 index 00000000..1a75c83e --- /dev/null +++ b/install/centos6/install.sh @@ -0,0 +1,63 @@ +sudo yum install -y wget git gcc gcc-c++ + +sudo yum install -y zlib1g-devel libssl-devel openssl-devel cmake pcre-devel +wget https://red.libssh.org/attachments/download/177/libssh-0.7.2.tar.xz +tar -xJf libssh-0.7.2.tar.xz +mkdir -p libssh-0.7.2/build && cd libssh-0.7.2/build +cmake .. && make -j2 && sudo make install +cd ../.. + +git clone https://github.com/CESNET/libyang.git +mkdir -p libyang/build +cd libyang/build +git checkout devel +cmake -DENABLE_BUILD_TESTS=OFF .. && sudo make install && sudo make install + +cd ../.. +wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz +tar -xJf cmocka-1.0.1.tar.xz +mkdir -p cmocka-1.0.1/build && cd cmocka-1.0.1/build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install + +cd ../.. +git clone git://github.com/cejkato2/libwebsockets lws +mkdir lws/b +cd lws/b +cmake .. && sudo make install + + +# libnetconf2 +# +cd ../.. +git clone https://github.com/CESNET/libnetconf2.git +mkdir -p libnetconf2/build +cd libnetconf2/build +git checkout devel +cmake -DENABLE_TLS=ON -DENABLE_SSH=ON -DENABLE_BUILD_TESTS=OFF .. && sudo make install + + +# libnetconf +# +# cd ../.. +# sudo yum install -y python-setuptools +# git clone https://github.com/mbj4668/pyang.git +# cd pyang +# python setup.py install + +# cd ../.. +# git clone --depth 1 https://github.com/CESNET/libnetconf.git +# sudo yum install -y libxml2-devel libxslt-devel curl-devel libtool +# cd libnetconf +# ./configure --prefix=/usr --libdir=/usr/lib -q + + +cd ../.. +cd mod_netconf +# sudo yum install -y json-c-devel +./bootstrap.sh +./configure +make +make install + +ldconfig + From fa6e124e7d2cdc682fdcf511a135fbaad07701ee Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 8 Mar 2016 17:35:35 +0100 Subject: [PATCH 035/113] zaklad pro nastaveni operace remove --- js/directives2.js | 13 +++++++++++-- public/templates.js | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/js/directives2.js b/js/directives2.js index 81876368..70b90069 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -169,11 +169,15 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.deleteKey = function(key, obj, parent) { if (getType(key, obj, parent) == "Object") { if( confirm('Delete "'+key+'" and all it contains?') ) { + setIetfOperation(obj, key, 'remove'); delete obj[key]; + obj[key] = {}; } } else if (getType(key, obj, parent) == "Array") { if( confirm('Delete "'+obj[key]+'"?') ) { + setIetfOperation(obj, key, 'remove'); obj.splice(key, 1); + obj[key] = {}; } } else { console.error("object to delete from was " + obj); @@ -240,12 +244,17 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.changeValue = function(child, key, val) { child[key] = val; + setIetfOperation(child, key, 'create'); + }; + + var setIetfOperation = function(child, key, operation) { + if (typeof child['@'+key] === "undefined") { child['@'+key] = { - 'ietf-netconf:operation"': '' + 'ietf-netconf:operation': '' } } - child['@'+key]['ietf-netconf:operation"'] = 'create'; + child['@'+key]['ietf-netconf:operation'] = operation; }; ////// diff --git a/public/templates.js b/public/templates.js index 8b21a5b3..57d555e3 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
          \n \n \n :\n \n\n \n\n \n \n\n \n \n \n \n \n \n
          "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
          \n
            \n
          1. \n \n
          2. \n
          \n \n
          "); -$templateCache.put("types/object.html","\n
          \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
          ");}]); \ No newline at end of file +$templateCache.put("types/object.html","\n
          \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
          ");}]); \ No newline at end of file From 215d72f19ad62227093d9904b74a723e2c1399ed Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 8 Mar 2016 20:51:50 +0100 Subject: [PATCH 036/113] pridava funkce pro praci s atributy, vcetne nastaveni atributu pro create, remove a replace --- css/sass/screen.scss | 1 + css/stylesheets/screen.css | 1 + js/JSONedit.js | 2 +- js/directives2.js | 149 +++++++++++++++++++++------ public/templates.js | 6 +- templates/directives/switchItem.html | 8 +- templates/types/array.html | 1 + templates/types/object.html | 2 +- 8 files changed, 131 insertions(+), 39 deletions(-) diff --git a/css/sass/screen.scss b/css/sass/screen.scss index bc998048..0990495e 100644 --- a/css/sass/screen.scss +++ b/css/sass/screen.scss @@ -33,6 +33,7 @@ $fa-font-path: "../netopeer-gui/bundles/fitmoduledefault/netopeerangular/css/fon } .iconButton { float: right; margin-right: 10px; position: relative; top: -1px; z-index: 99999999999999; cursor: pointer; } .jsonObjectKey { font-weight: bold; margin-right: 25px; } + .strike { text-decoration: line-through; } } /* inputs */ diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css index 25f5a206..47f5eff9 100644 --- a/css/stylesheets/screen.css +++ b/css/stylesheets/screen.css @@ -1303,6 +1303,7 @@ .jsonView .addObjectItemBtn i { display: block; } .jsonView .iconButton { float: right; margin-right: 10px; position: relative; top: -1px; z-index: 99999999999999; cursor: pointer; } .jsonView .jsonObjectKey { font-weight: bold; margin-right: 25px; } +.jsonView .strike { text-decoration: line-through; } /* inputs */ /* chevrons */ diff --git a/js/JSONedit.js b/js/JSONedit.js index 7ddcd364..05aac155 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -67,7 +67,7 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) removeSchemaNodes(jsonObj); cleanJson = $filter('json')(jsonObj); return cleanJson; - } + }; $scope.download = function (jsonData) { var cleanJson = cleanupJSON(jsonData); diff --git a/js/directives2.js b/js/directives2.js index 70b90069..25bce994 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -58,7 +58,10 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.stringName = stringName; //scope.valueTypes = [stringName, objectName, arrayName, refName, boolName]; scope.sortableOptions = { - axis: 'y' + axis: 'y', + update: function(e, ui) { + setIetfOperation('replace', scope.$parent.$parent.newkey, scope.$parent.$parent.$parent.$parent.$parent.child); + } }; if (scope.$parent.defaultCollapsed === undefined) { scope.collapsed = false; @@ -87,7 +90,6 @@ NetopeerGUI.directive('ngModelOnblur', function() { var schema = getSchemaFromKey(key, parent); // get custom yang datatype var type = Object.prototype.toString.call(obj); - var eltype = ''; if (type === "[object Object]") { return objectName; @@ -99,9 +101,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { type = schema['type']; } - if (schema && typeof schema['eltype'] !== "undefined") { - eltype = schema['eltype']; - } + var eltype = getEltype(key, parent); if (eltype === "container") { return objectName; @@ -120,9 +120,21 @@ NetopeerGUI.directive('ngModelOnblur', function() { return literalName; } }; + var getEltype = function(key, parent) { + var schema = getSchemaFromKey(key, parent); + // get custom yang datatype + var eltype = ''; + + if (schema && typeof schema['eltype'] !== "undefined") { + eltype = schema['eltype']; + } + + return eltype; + }; var isNumber = function(n) { return !isNaN(parseFloat(n)) && isFinite(n); }; + scope.getType = getType; scope.log = function(data) { console.log(data); @@ -142,10 +154,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { }; scope.editBarVisible = function(key, parent) { - var schema = getSchemaFromKey(key, parent); - if (schema && typeof schema['type'] !== "undefined") { - var type = schema['type']; - return (type == "list" || type == "leaf-list" || type == "container"); + var eltype = getEltype(key, parent); + if (eltype) { + return (eltype == "list" || eltype == "leaf-list" || eltype == "container"); } return false; @@ -159,25 +170,17 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.chevron = "fa-plus-square-o"; } }; - scope.moveKey = function(obj, key, newkey) { - //moves key to newkey in obj - if (key !== newkey) { - obj[newkey] = obj[key]; - delete obj[key]; - } - }; scope.deleteKey = function(key, obj, parent) { if (getType(key, obj, parent) == "Object") { if( confirm('Delete "'+key+'" and all it contains?') ) { - setIetfOperation(obj, key, 'remove'); - delete obj[key]; - obj[key] = {}; + setIetfOperation('remove', key, obj); + //delete obj[key]; // TODO delete children + } } else if (getType(key, obj, parent) == "Array") { if( confirm('Delete "'+obj[key]+'"?') ) { - setIetfOperation(obj, key, 'remove'); - obj.splice(key, 1); - obj[key] = {}; + setIetfOperation('remove', key, obj); + //obj.splice(key, 1); // TODO delete children } } else { console.error("object to delete from was " + obj); @@ -198,6 +201,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { if( !confirm('An item with the name "'+parent.keyName +'" exists already. Do you really want to replace it?') ) { return; + } else { + removeIetfOperation(parent.keyName, obj, parent); + setIetfOperation('create', key, obj, parent); } } // add item to object @@ -217,6 +223,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { parent.keyName = ""; parent.valueName = ""; parent.showAddKey = false; + setIetfOperation('create', key, obj); } } else if (type == "Array") { // add item to array @@ -234,6 +241,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { } parent.valueName = ""; parent.showAddKey = false; + setIetfOperation('create', key, obj); } else { console.error("object to add to was " + obj); } @@ -242,19 +250,100 @@ NetopeerGUI.directive('ngModelOnblur', function() { return isNumber(val) ? parseFloat(val) : val; }; - scope.changeValue = function(child, key, val) { + scope.changeValue = function(val, key, child) { child[key] = val; - setIetfOperation(child, key, 'create'); + setIetfOperation('replace', key, child); + }; + + scope.isVisible = function(key, obj) { + var attr = getAttribute('ietf-netconf:operation', key, obj); + return !(attr && attr === "remove"); }; - var setIetfOperation = function(child, key, operation) { + var getAttributeType = function(key, obj) { + var eltype = getEltype(key, obj); - if (typeof child['@'+key] === "undefined") { - child['@'+key] = { - 'ietf-netconf:operation': '' - } + if (eltype === "container" || eltype === 'list' || eltype === 'anydata') { + return 'anydata'; + } else if (eltype === 'leaf' || eltype === 'anyxml') { + return 'anyxml'; + } else if (eltype === "leaf-list") { + return 'leaf-list'; } - child['@'+key]['ietf-netconf:operation'] = operation; + return 'not-supported'; + }; + + scope.getAttributesNode = function(key, obj, generateEmpty) { + if (typeof generateEmpty === "undefined") { + generateEmpty = false; + } + var eltype = getAttributeType(key, obj); + + switch (eltype) { + case 'anydata': + if (typeof obj[key] !== "undefined") { + if (generateEmpty && typeof obj[key]['@'] === "undefined") { + obj[key]['@'] = {}; // create empty attributes object + } + if (typeof obj[key]['@'] !== "undefined") { + return obj[key]['@']; + } + } + break; + case 'leaf-list': + case 'anyxml': + if (generateEmpty && typeof obj['@'+key] === "undefined") { + obj['@'+key] = {}; // create empty attributes object + } + if (typeof obj['@'+key] !== "undefined") { + return obj['@'+key]; + } + break; + //case 'leaf-list': + // if (typeof obj['@'+key] !== "undefined" && typeof obj['@'+key][attr] !== "undefined") { + // return obj['@'+key][attr]; + // } + // break; + } + + return false; + }; + + var getAttribute = function(attr, key, obj) { + var node = scope.getAttributesNode(key, obj); + if (node !== false && typeof node[attr] !== "undefined") { + return node[attr]; + } + + return false; + }; + + var setAttribute = function(attr, val, key, obj) { + var node = scope.getAttributesNode(key, obj, true); + + if (node) { + node[attr] = val; + return true; + } + + return false; + }; + + var unsetAttribute = function(attr, key, obj) { + var node = scope.getAttributesNode(key, obj); + if (node) { + if (typeof node[attr] !== "undefined") delete node[attr]; + return true; + } + return false; + }; + + var setIetfOperation = function(operation, key, obj) { + setAttribute('ietf-netconf:operation', operation, key, obj); + }; + + var removeIetfOperation = function(key, obj) { + unsetAttribute('ietf-netconf:operation', key, obj); }; ////// diff --git a/public/templates.js b/public/templates.js index 57d555e3..c894f8b7 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
          \n \n \n :\n \n\n \n\n \n \n\n \n \n \n \n \n \n
          "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); -$templateCache.put("types/array.html","\n
          \n
            \n
          1. \n \n
          2. \n
          \n \n
          "); -$templateCache.put("types/object.html","\n
          \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
          ");}]); \ No newline at end of file +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); +$templateCache.put("types/array.html","\n
          \n \n
            \n
          1. \n \n
          2. \n
          \n \n
          "); +$templateCache.put("types/object.html","\n
          \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
          ");}]); \ No newline at end of file diff --git a/templates/directives/switchItem.html b/templates/directives/switchItem.html index 747fa5c3..41ceb315 100644 --- a/templates/directives/switchItem.html +++ b/templates/directives/switchItem.html @@ -3,19 +3,19 @@ - + {{ val }} - + {{ val }} - + {{ val }} - + {{ val }} \ No newline at end of file diff --git a/templates/types/array.html b/templates/types/array.html index 9d3e62c6..e7dcfdf9 100644 --- a/templates/types/array.html +++ b/templates/types/array.html @@ -1,5 +1,6 @@
          +
          1. diff --git a/templates/types/object.html b/templates/types/object.html index 2be3b726..167b07d6 100644 --- a/templates/types/object.html +++ b/templates/types/object.html @@ -1,6 +1,6 @@
            - + {{ key }} From 0bafe45684f726dbd271591a9b407826c7b820e3 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 9 Mar 2016 19:39:37 +0100 Subject: [PATCH 037/113] oprava pridavani novych uzlu. Naseptavani jeste nefunguje u listu. --- js/directives2.js | 38 ++++++++++++++++++++----------- public/templates.js | 2 +- templates/directives/addItem.html | 7 ++---- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/js/directives2.js b/js/directives2.js index 25bce994..d0026065 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -97,10 +97,6 @@ NetopeerGUI.directive('ngModelOnblur', function() { return arrayName; } - if (schema && typeof schema['type'] !== "undefined") { - type = schema['type']; - } - var eltype = getEltype(key, parent); if (eltype === "container") { @@ -114,10 +110,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { } else if (type === 'enumeration') { return enumerationName; } else if (isNumberType(type) || type === "[object Number]") { - // TODO: check range return numberName; } else { - return literalName; + return stringName; } }; var getEltype = function(key, parent) { @@ -187,8 +182,10 @@ NetopeerGUI.directive('ngModelOnblur', function() { } }; scope.addItem = function(key, obj, parent) { - var type = getType(key, obj, parent); - if (type == "Object") { + var type = getType(parent.keyName, undefined, obj); + var parentType = getType(parent.$parent.$parent.$parent.$parent.key, obj); + + if (parentType == "Object") { // check input for key if (parent.keyName == undefined || parent.keyName.length == 0){ alert("Please fill in a name"); @@ -207,7 +204,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { } } // add item to object - switch(parent.valueType) { + switch(type) { case stringName: obj[parent.keyName] = parent.valueName ? parent.possibleNumber(parent.valueName) : ""; break; case objectName: obj[parent.keyName] = {}; @@ -218,16 +215,18 @@ NetopeerGUI.directive('ngModelOnblur', function() { break; case boolName: obj[parent.keyName] = false; break; + default: + console.log('not implemented ' + parent.valueType); // TOOD } + setIetfOperation('create', parent.keyName, obj); //clean-up parent.keyName = ""; parent.valueName = ""; parent.showAddKey = false; - setIetfOperation('create', key, obj); } - } else if (type == "Array") { + } else if (parentType == "Array") { // add item to array - switch(parent.valueType) { + switch(type) { case stringName: obj.push(parent.valueName ? parent.valueName : ""); break; case objectName: obj.push({}); @@ -238,10 +237,12 @@ NetopeerGUI.directive('ngModelOnblur', function() { break; case refName: obj.push({"Reference!!!!": "todo"}); break; + default: + console.log('2not implemented ' + parent.valueType); // TOOD } + setIetfOperation('replace', parent.$parent.$parent.$parent.$parent.key, parent.$parent.$parent.$parent.$parent.$parent.$parent.child); // TODO replace order in array parent.valueName = ""; parent.showAddKey = false; - setIetfOperation('create', key, obj); } else { console.error("object to add to was " + obj); } @@ -260,6 +261,17 @@ NetopeerGUI.directive('ngModelOnblur', function() { return !(attr && attr === "remove"); }; + scope.getAvailableNodeNames = function (key, obj, parent) { + console.log(key);console.log(obj);console.log(parent); + var children = parent.$parent.$parent.$parent.$parent.$parent.$parent.child['$@'+ parent.$parent.$parent.$parent.key]['children']; + angular.forEach(obj, function(value, key) { + if (key.indexOf('@') !== 0 && children.indexOf(key) !== -1) { + children.splice(children.indexOf(key), 1); + } + }); + return children; + }; + var getAttributeType = function(key, obj) { var eltype = getEltype(key, obj); diff --git a/public/templates.js b/public/templates.js index c894f8b7..d35e8f5f 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ -angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
            \n \n \n :\n \n\n \n\n \n \n\n \n \n \n \n \n \n
            "); +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
            \n \n \n :\n \n\n \n\n \n \n \n \n \n \n
            "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); $templateCache.put("types/array.html","\n
            \n \n
              \n
            1. \n \n
            2. \n
            \n \n
            "); $templateCache.put("types/object.html","\n
            \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
            ");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index a7ebe1d8..ce125a69 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -2,14 +2,11 @@ : - - - - + + diff --git a/src/FIT/NetopeerBundle/Controller/ModuleController.php b/src/FIT/NetopeerBundle/Controller/ModuleController.php index 4ea16a51..89977fd6 100644 --- a/src/FIT/NetopeerBundle/Controller/ModuleController.php +++ b/src/FIT/NetopeerBundle/Controller/ModuleController.php @@ -121,7 +121,8 @@ protected function prepareVariablesForModuleAction($bundleName, $key, $module = // if form has been send, we well process it if ($this->getRequest()->getMethod() == 'POST') { - return $this->processSectionForms($key, $module, $subsection); +// return $this->processSectionForms($key, $module, $subsection); // TODO + return; } // we will prepare filter form in column diff --git a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php index 9130cef0..31a0e6b3 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php @@ -471,7 +471,7 @@ public function checkLoggedKeys() { public function buildMenuStructure($key, $path = "") { // we will build menu structure only if we have not build it before - if ( 1 || !$this->getModels($key) || !$this->getModelNamespaces($key) ) { + if ( !$this->getModels($key) || !$this->getModelNamespaces($key) ) { $models = array(); $namespaces = array(); diff --git a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php index f12f44eb..30a049cb 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php @@ -1064,7 +1064,7 @@ public function handle($command, $params = array(), $merge = true, &$result = nu $res = $this->handle_getconfig($sock, $params); break; case "editconfig": - $this->getLogger()->addInfo("Handle editConfig: ", array('configToSend' => $params['config'])); + $this->getLogger()->addInfo("Handle editConfig: ", array('configToSend' => var_export($params['configs'], true))); $res = $this->handle_editconfig($sock, $params); break; case "copyconfig": From d309a402593a7e15dfc64d9cb959eac1d43c8c75 Mon Sep 17 00:00:00 2001 From: david alexa Date: Fri, 11 Mar 2016 16:24:50 +0100 Subject: [PATCH 041/113] adds missing logic for redirecting to the first module of connected device --- .../ModuleDefaultBundle/Resources/netopeerangular | 2 +- .../Controller/DefaultController.php | 3 +-- .../Controller/ModuleController.php | 15 ++++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular index 00a093da..0bafe456 160000 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular @@ -1 +1 @@ -Subproject commit 00a093dafdb45f0ac5d915b5a6afe4f22e6075ef +Subproject commit 0bafe45684f726dbd271591a9b407826c7b820e3 diff --git a/src/FIT/NetopeerBundle/Controller/DefaultController.php b/src/FIT/NetopeerBundle/Controller/DefaultController.php index 228feae5..6dc57a04 100644 --- a/src/FIT/NetopeerBundle/Controller/DefaultController.php +++ b/src/FIT/NetopeerBundle/Controller/DefaultController.php @@ -295,8 +295,7 @@ public function handleConnectionAction($command, $key, $identifier = "") { $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $params = array( - 'connIds' => array($key), - 'filter' => '', + 'connIds' => array($key) ); if ($command === "getschema") { diff --git a/src/FIT/NetopeerBundle/Controller/ModuleController.php b/src/FIT/NetopeerBundle/Controller/ModuleController.php index 89977fd6..11ec9764 100644 --- a/src/FIT/NetopeerBundle/Controller/ModuleController.php +++ b/src/FIT/NetopeerBundle/Controller/ModuleController.php @@ -303,22 +303,19 @@ protected function generateTypeaheadPath($key, $module, $subsection) { * @return RedirectResponse */ protected function redirectToFirstModule($key) { - // TODO - return $this->redirect($this->generateUrl("module", array('key' => $key, 'module' => 'all'))); - -// $dataClass = $this->get('DataModel'); + $connectionFunc = $this->get('fitnetopeerbundle.service.connection.functionality'); $retArr['key'] = $key; $routeName = 'module'; - $modules = $dataClass->getModels(); + $modules = $connectionFunc->getModuleIdentifiersForCurrentDevice($key); if (count($modules)) { - $module1st = array_shift($modules); - if (!isset($module1st["params"]["module"])) { + $first = array_shift($modules); + if (!isset($first["moduleName"])) { /* ERROR - wrong structure of model entry */ $this->get('data_logger') ->err("Cannot get first model (redirect to 1st tab).", - array("message" => "\$module1st[\"params\"][\"module\"] is not set")); + array("message" => "\$first[\"moduleName\"] is not set")); } - $retArr['module'] = $module1st["params"]["module"]; + $retArr['module'] = $first["moduleName"]; return $this->redirect($this->generateUrl($routeName, $retArr)); } else { return $this->redirect($this->generateUrl("module", array('key' => $key, 'module' => 'all'))); From c9d8c9b4887b230a5f2cf286e64e36cb586fe39e Mon Sep 17 00:00:00 2001 From: david alexa Date: Fri, 11 Mar 2016 19:33:43 +0100 Subject: [PATCH 042/113] sends JSON configuration as a clean JSON instead of array --- .../ModuleDefaultBundle/Controller/ModuleController.php | 4 ++-- src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php b/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php index 826c9fcb..5a74f515 100644 --- a/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php +++ b/src/FIT/Bundle/ModuleDefaultBundle/Controller/ModuleController.php @@ -36,11 +36,11 @@ public function moduleAction($key, $module = null, $subsection = null) if ($this->getRequest()->getMethod() == 'POST') { $netconfFunc = $this->get('fitnetopeerbundle.service.netconf.functionality'); $configParams = $this->getConfigParams(); - $postData = json_decode($this->getRequest()->getContent(), true); + $postData = $this->getRequest()->getContent(); $params = array( 'connIds' => array($key), 'target' => $configParams['source'], - 'configs' => array($postData['editConfig']) + 'configs' => array($postData) ); $res = $netconfFunc->handle('editconfig', $params, true, $result); return new JsonResponse(json_decode($res)); diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular index 0bafe456..98f128b5 160000 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular @@ -1 +1 @@ -Subproject commit 0bafe45684f726dbd271591a9b407826c7b820e3 +Subproject commit 98f128b541c8102966f70686a9178d566871523f From a117be3b32c065d5aad983c1e3e5ffc429fdb18f Mon Sep 17 00:00:00 2001 From: Tomas Cejka Date: Mon, 14 Mar 2016 15:04:45 +0100 Subject: [PATCH 043/113] vagrant: prepared and tested Vagrantfile for centos/7 --- install/Vagrantfile | 10 ++++++ install/centos7/install.sh | 64 ++++++++++++++++++-------------------- 2 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 install/Vagrantfile mode change 100644 => 100755 install/centos7/install.sh diff --git a/install/Vagrantfile b/install/Vagrantfile new file mode 100644 index 00000000..d1e5ff19 --- /dev/null +++ b/install/Vagrantfile @@ -0,0 +1,10 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + config.vm.box = "centos/7" + + config.vm.network "forwarded_port", guest: 80, host: 2280 + + config.vm.provision "shell", path: "centos7/install.sh" +end diff --git a/install/centos7/install.sh b/install/centos7/install.sh old mode 100644 new mode 100755 index 278c60be..dac58a2c --- a/install/centos7/install.sh +++ b/install/centos7/install.sh @@ -1,65 +1,61 @@ -sudo yum install -y wget git gcc gcc-c++ +sudo yum install -y wget git gcc gcc-c++ zlib1g-devel libssl-devel openssl-devel cmake pcre-devel autoconf automake json-c-devel -sudo yum install -y zlib1g-devel libssl-devel openssl-devel cmake pcre-devel +# PHP dependencies: +yum install -y php php-common php-json php-dom php-pdo php-intl php-sysvsem + +( wget https://red.libssh.org/attachments/download/177/libssh-0.7.2.tar.xz tar -xJf libssh-0.7.2.tar.xz mkdir -p libssh-0.7.2/build cd libssh-0.7.2/build cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DLIB_INSTALL_DIR=/usr/lib64 .. && make -j2 && sudo make install -cd ../.. +) -git clone https://github.com/CESNET/libyang.git +( +git clone -b devel --depth 1 https://github.com/CESNET/libyang.git mkdir -p libyang/build cd libyang/build -git checkout devel cmake -DCMAKE_INSTALL_PREFIX=/usr -DLIB_INSTALL_DIR=lib64 -DENABLE_BUILD_TESTS=OFF .. && sudo make install && sudo make install +) -cd ../.. +( wget https://cmocka.org/files/1.0/cmocka-1.0.1.tar.xz tar -xJf cmocka-1.0.1.tar.xz mkdir -p cmocka-1.0.1/build cd cmocka-1.0.1/build cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && make -j2 && sudo make install +) -cd ../.. -git clone git://github.com/cejkato2/libwebsockets lws +( +git clone --depth 1 git://github.com/cejkato2/libwebsockets lws mkdir lws/b cd lws/b -cmake .. && sudo make install - +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DLWS_INSTALL_LIB_DIR=/usr/lib -DLIB_SUFFIX=64 .. && sudo make install +) # libnetconf2 -# -cd ../.. -git clone https://github.com/CESNET/libnetconf2.git +( +git clone -b devel --depth 1 https://github.com/CESNET/libnetconf2.git mkdir -p libnetconf2/build cd libnetconf2/build -git checkout devel cmake -DENABLE_TLS=ON -DENABLE_SSH=ON -DENABLE_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=/usr -DLIB_INSTALL_DIR=lib64 .. && sudo make install +) +ldconfig - -# libnetconf -# -# cd ../.. -# sudo yum install -y python-setuptools -# git clone https://github.com/mbj4668/pyang.git -# cd pyang -# python setup.py install - -# cd ../.. -# git clone --depth 1 https://github.com/CESNET/libnetconf.git -# sudo yum install -y libxml2-devel libxslt-devel curl-devel libtool -# cd libnetconf -# ./configure --prefix=/usr --libdir=/usr/lib64 -q - - -cd ../.. +( +git clone -b libyang --depth 1 https://github.com/CESNET/mod_netconf cd mod_netconf -# sudo yum install -y json-c-devel ./bootstrap.sh ./configure make make install - -ldconfig +) + +( +cd /var/www/ +git clone -b netopeerguid --depth 1 https://github.com/CESNET/Netopeer-GUI +cd Netopeer-GUI +php app/check.php +php ./composer.phar install +) From f200b729aa2af9525f3878386deebedd71205c2f Mon Sep 17 00:00:00 2001 From: David Alexa Date: Mon, 14 Mar 2016 18:17:16 +0100 Subject: [PATCH 044/113] adds composer self-update to install script. Adds command for copying of parametrs.yml.dist --- install/centos7/install.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/install/centos7/install.sh b/install/centos7/install.sh index dac58a2c..d2f46844 100755 --- a/install/centos7/install.sh +++ b/install/centos7/install.sh @@ -55,7 +55,9 @@ make install cd /var/www/ git clone -b netopeerguid --depth 1 https://github.com/CESNET/Netopeer-GUI cd Netopeer-GUI +cp app/config/parameters.yml.dist app/config/parameters.yml php app/check.php +php ./composer.phar self-update php ./composer.phar install ) From e1b5bf179625475333a618cc289ad972fb3ff2d4 Mon Sep 17 00:00:00 2001 From: Tomas Cejka Date: Mon, 14 Mar 2016 13:52:45 -0400 Subject: [PATCH 045/113] configure: remove pyang and apache module vars --- install/Makefile.am | 5 ----- install/configure.ac | 23 +---------------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/install/Makefile.am b/install/Makefile.am index 67e4b0b3..0158a16a 100644 --- a/install/Makefile.am +++ b/install/Makefile.am @@ -3,11 +3,6 @@ if MODNETCONF_OPT else MODNETCONF_OPT= endif -if PYANG_OPT - PYANG_OPT=pyang -else - PYANG_OPT= -endif SUBDIRS=$(MODNETCONF_OPT) $(PYANG_OPT) diff --git a/install/configure.ac b/install/configure.ac index 43373b08..7396e4a4 100644 --- a/install/configure.ac +++ b/install/configure.ac @@ -25,9 +25,6 @@ fi AC_ARG_VAR(webguiname, [Installation directory name for webgui [netconfwebgui]]) AC_SUBST(webguiname) -AC_ARG_VAR(httpdmoduledir, [Installation directory for Apache module, leave unset to use Apache default.]) -AC_SUBST(httpdmoduledir) - if test "x$httpdconfddir" == x; then httpdconfddir="/etc/httpd/conf.d" fi @@ -37,9 +34,6 @@ AC_SUBST(httpdconfddir) AC_ARG_WITH(modnetconf, AC_HELP_STRING([--without-modnetconf],[Do not compile and install mod_netconf.]), [], [with_modnetconf="yes"]) AM_CONDITIONAL([MODNETCONF_OPT], [test "x$with_modnetconf" != "xno"]) -AC_ARG_WITH(pyang, AC_HELP_STRING([--without-pyang],[Do not install pyang plugins.]), [], [with_pyang="yes"]) -AM_CONDITIONAL([PYANG_OPT], [test "x$with_pyang" != "xno"]) - # Check for rpmbuild AC_CHECK_PROG(RPMBUILD, [rpmbuild], [rpmbuild], [""]) AC_CHECK_PROG(HTTPD, [httpd], [yes], [""]) @@ -56,18 +50,6 @@ AC_MSG_ERROR([php was not found]) fi AC_SUBST(PHP) -AC_CHECK_PROG(PYANG, [pyang], [yes], [""]) -AC_PATH_PROGS(PYTHON, [python], [no], [$PATH]) -if test "x$PYTHON" == xno; then - AC_MSG_ERROR(["python was not found."]) -fi - -AC_ARG_VAR(pyplugindir, [Installation directory for pyang plugin]) -if test "x$pyplugindir" == x; then -pyplugindir=[$(${PYTHON} -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()+"/pyang/plugins"')] -fi -AC_SUBST(pyplugindir) - # Check for rpmbuild AC_CHECK_PROG(RPMBUILD, rpmbuild, rpmbuild, [""]) RPM_RELEASE=1 @@ -84,8 +66,7 @@ AM_CONDITIONAL(MAKE_RPMS, test x$RPMBUILD != x) AC_CONFIG_SUBDIRS(mod_netconf) AC_CONFIG_FILES([Makefile - netopeergui.conf - pyang/Makefile]) + netopeergui.conf]) AC_OUTPUT echo @@ -106,14 +87,12 @@ echo " CFLAGS...............: $CFLAGS" echo echo "Components" echo " mod_netconf..........: $with_modnetconf" -echo " pyang plugins........: $with_pyang" echo echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')" echo " prefix...............: $prefix" echo " python module dir....: $pyplugindir" echo " webgui dir...........: $webguidir" echo " webgui name..........: $webguiname" -echo " httpdmoduledir.......: $(test -z "$httpdmoduledir" && echo "Apache default path" || echo "$httpdmoduledir")" echo " httpdconfddir........: $(test -z "$httpdconfddir" && echo "Apache default path" || echo "$httpdconfddir")" echo From 549ca022303167c20e4b9b16b5643a40288e6054 Mon Sep 17 00:00:00 2001 From: Tomas Cejka Date: Mon, 14 Mar 2016 19:07:43 +0100 Subject: [PATCH 046/113] centos7: install: copy apache config file + start services --- install/centos7/install.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/install/centos7/install.sh b/install/centos7/install.sh index d2f46844..fca569bf 100755 --- a/install/centos7/install.sh +++ b/install/centos7/install.sh @@ -59,5 +59,9 @@ cp app/config/parameters.yml.dist app/config/parameters.yml php app/check.php php ./composer.phar self-update php ./composer.phar install +cd install +./bootstrap.sh && ./configure --without-modnetconf -q && make install +service httpd restart +service netopeerguid restart ) From 6330b10a8c7fc650953b2bfa6be089e78b5635fe Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 16 Mar 2016 11:15:22 +0100 Subject: [PATCH 047/113] unset empty filter for netconf operations --- .../Services/Functionality/NetconfFunctionality.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php index 30a049cb..bbbc237f 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php @@ -322,7 +322,17 @@ private function getJsonError() { private function addOptionalParams(array $targetArr, array $sourceArr, array $optionalParams) { foreach ($optionalParams as $param) { if (isset($sourceArr[$param])) { - $targetArr[$param] = $sourceArr[$param]; + /** + * if we want to set filter, filter must have some value + * empty filter returns empty response, not all data + */ + if ($param === 'filter' && trim($sourceArr[$param]) !== "") { + $targetArr[$param] = $sourceArr[$param]; + + // set all other params with no limitations + } else { + $targetArr[$param] = $sourceArr[$param]; + } } } From 36348c6cfe51095472f8e8e71aa294b2ce978e81 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 16 Mar 2016 12:01:42 +0100 Subject: [PATCH 048/113] trim filter optional param for netconf --- src/FIT/NetopeerBundle/Controller/BaseController.php | 8 ++++++-- .../Functionality/ConnectionFunctionality.php | 2 +- .../Services/Functionality/NetconfFunctionality.php | 11 +++-------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/FIT/NetopeerBundle/Controller/BaseController.php b/src/FIT/NetopeerBundle/Controller/BaseController.php index b397f5ca..d5fc3137 100644 --- a/src/FIT/NetopeerBundle/Controller/BaseController.php +++ b/src/FIT/NetopeerBundle/Controller/BaseController.php @@ -207,10 +207,14 @@ protected function setSectionFormsParams($key, $filterState = "", $filterConfig } $this->setStateParams('connIds', array($key)); - $this->setStateParams('filter', $filterState); + if ($filterState !== "") { + $this->setStateParams('filter', $filterState); + } $this->setConfigParams('connIds', array($key)); - $this->setConfigParams('filter', $filterConfig); + if ($filterConfig !== "") { + $this->setConfigParams('filter', $filterConfig); + } } /** diff --git a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php index 31a0e6b3..424d82a6 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php @@ -576,7 +576,7 @@ public function loadFilters(&$module, &$subsection) { $filter->addChild($subsection); } - $filterState = $filterConfig = str_replace('', '', $filter->asXml()); + $filterState = $filterConfig = str_replace('', '', trim($filter->asXml())); } return array( diff --git a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php index bbbc237f..a1f9dd20 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/NetconfFunctionality.php @@ -315,7 +315,7 @@ private function getJsonError() { * * @param array $targetArr * @param array $sourceArr - * @param array $params + * @param array $optionalParams * * @return mixed */ @@ -326,16 +326,11 @@ private function addOptionalParams(array $targetArr, array $sourceArr, array $op * if we want to set filter, filter must have some value * empty filter returns empty response, not all data */ - if ($param === 'filter' && trim($sourceArr[$param]) !== "") { - $targetArr[$param] = $sourceArr[$param]; - - // set all other params with no limitations - } else { - $targetArr[$param] = $sourceArr[$param]; + if ($param !== "filter" || ($param === "filter" && trim($sourceArr[$param]) !== "")) { + $targetArr[$param] = trim($sourceArr[$param]); } } } - return $targetArr; } From 4840726ad7505a007a198d1de636ea3c6be82b16 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 16 Mar 2016 12:10:39 +0100 Subject: [PATCH 049/113] vagrant install for centos7: enable selinux and correct permissions for netopeergui --- Vagrantfile | 14 -------------- app/SymfonyRequirements.php | 35 +++++++++++++++++++++++++++-------- composer.phar | Bin 1039012 -> 1580509 bytes install/Vagrantfile | 8 +++++++- install/centos7/install.sh | 6 ++++-- 5 files changed, 38 insertions(+), 25 deletions(-) delete mode 100644 Vagrantfile mode change 100644 => 100755 composer.phar diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index cb9d319e..00000000 --- a/Vagrantfile +++ /dev/null @@ -1,14 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure(2) do |config| - config.vm.box = "centos/7" - - config.vm.network "forwarded_port", guest: 80, host: 2280 - config.vm.network "forwarded_port", guest: 5555, host: 5555 - - config.vm.provision "shell", inline: <<-SHELL - ./install/centos7/install.sh -# sudo rpm -ivh https://homeproj.cesnet.cz/rpm/liberouter/devel/x86_64/liberouter-devel-1.0.0-1.noarch.rpm -SHELL -end diff --git a/app/SymfonyRequirements.php b/app/SymfonyRequirements.php index 1854856b..dd7c2781 100644 --- a/app/SymfonyRequirements.php +++ b/app/SymfonyRequirements.php @@ -530,11 +530,22 @@ function_exists('simplexml_import_dom'), /* optional recommendations follow */ - $this->addRecommendation( - file_get_contents(__FILE__) === file_get_contents(__DIR__.'/../vendor/sensio/distribution-bundle/Sensio/Bundle/DistributionBundle/Resources/skeleton/app/SymfonyRequirements.php'), - 'Requirements file should be up-to-date', - 'Your requirements file is outdated. Run composer install and re-check your configuration.' - ); + if (file_exists(__DIR__.'/../vendor/composer')) { + require_once __DIR__.'/../vendor/autoload.php'; + + try { + $r = new \ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle'); + + $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php'); + } catch (\ReflectionException $e) { + $contents = ''; + } + $this->addRecommendation( + file_get_contents(__FILE__) === $contents, + 'Requirements file should be up-to-date', + 'Your requirements file is outdated. Run composer install and re-check your configuration.' + ); + } $this->addRecommendation( version_compare($installedPhpVersion, '5.3.4', '>='), @@ -614,15 +625,15 @@ class_exists('Locale'), 'Install and enable the intl extension (used for validators).' ); - if (class_exists('Collator')) { + if (extension_loaded('intl')) { + // in some WAMP server installations, new Collator() returns null $this->addRecommendation( null !== new Collator('fr_FR'), 'intl extension should be correctly configured', 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' ); - } - if (class_exists('Locale')) { + // check for compatible ICU versions (only done when you have the intl extension) if (defined('INTL_ICU_VERSION')) { $version = INTL_ICU_VERSION; } else { @@ -641,6 +652,14 @@ class_exists('Locale'), 'intl ICU version should be at least 4+', 'Upgrade your intl extension with a newer ICU version (4+).' ); + + $this->addPhpIniRecommendation( + 'intl.error_level', + create_function('$cfgValue', 'return (int) $cfgValue === 0;'), + true, + 'intl.error_level should be 0 in php.ini', + 'Set "intl.error_level" to "0" in php.ini* to inhibit the messages when an error occurs in ICU functions.' + ); } $accelerator = diff --git a/composer.phar b/composer.phar old mode 100644 new mode 100755 index 17ce684e9b3c1a2ad828cfb168c06edf784f4c16..9a4c08e82ed97ececc3d9eaaa123da25ed799410 GIT binary patch literal 1580509 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%0AoGTD28 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�I1LMDic1+rK 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�fFZL^EMZugjqLA2WFr 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

            >R-Ulx1)nDyBwb=lw#wwdca=hWO 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

            H%|^Gc(8(;OBwJSCy37^pOI@ zy)XgBfMLx0Bg&%3vqCsymR}{?kyn?g4bv%e*4d6}nz}eHNWRJlCy1x#x?ffg5~Z=E z+pkZ-wUhvqL8h#4dD|fek$@zfU`DW8S4Y<|dAYaSeCm_k%Doj}7B{0C3);ZiG|A&> zC(?!$2{KT)#PH-VTUuUkw$I4K0_)y_t#BudBp{Lw4Y(G|&?AzwKZARP!4u@QNRy{7*dZkIRoArdX12*O7CY1)j z+4f;J_CBezUZcM6y}RFv%!BhcP&Z^AgBvn=IFNz0&{vfYN5}BwmksQ?u?GY~8A_D_ zFWB;eTG}m}s*C{AfE<8l!o%-!k7&mOO8HMi5|{}Xn)oP#1@H$V`xW$a=wD3QSCby> z75JM+M*)QkL~mBXOjN%6i}YPwSyvy>qA@rKSxP>vRRV>W8c-T9pVEe}h#dNzboIL5 zEEvU)myL4T(2b`o+Xiy{p2H;p+HsNT0Hv>YG|n|x#ug6DdM?#{;{oFOjv^PhQ5NQQ zKcqs#(6zW7Dk70(pAm|bjS4hy@dNAbJtFmuGw>WyAa-oYC*AanE2)(Rv_(7xRrS6( za$sNXtN`B!thT;`DZa?2JGUOYxr2n?q87SvxHkbm0V*#31?YM8I>jXg0sB)Ph^k1@%LZRP29 zUH_(H0{n;cyI#^y()Z7FkTl3{--T3`IWA^HN2!CJFmiN?q05k$h z=@sqzlDg~so23WRrCx#eAbDpg>}BZz1&g9m@6jfod&LXP@ijE#u^&I-r7VUY0K;w? z!u{S+^}p!tt@m_I=X2A2GejbP=kI}4_h)<0u?H=I>nzD-!%KSxxHL9ifiz2=X#Bjn zo|*Fn0d6}`8cP)S^ufE&@*21|?nYQ}nlsME7zG1^_p2O4<-)Ema-o_wR;@7(;4bPKtC%g=>&( zq($-{qkDjJ|74!ZTscg|8p0n$MBsf&?yU1xrH3uKOUIgXAHvx%*XBVSf(k89@wJ&Y zwJ79!*0+7J-qwm(u@E^C_eU&z1OU(Nl>-HtX=|)l!BF>LFlLBv^@ZG#7iBG#m49FN z5Y%)i2F>11BD46=Y4>Xe)cP6>Yp+90;V3pbYHZ;Q{@|TbMEdsAAFk6CAo+m~2grb; zrBed=xeM0MtW&H9N zBge;8`b%?)WuMl%y}4{{hW8$;8|^L}{k?5Hx4Y}MSrcT4bIv^;!9$43BVdJW+Aw=iLV%3wN3&bcM{EbFnbZtGqBfNWl%Izk>FJFML51au`ikM*jW2U*LFy{u@s zCEJ&p@=CG27IuD3JR!Lvm1^@5@MEv@$z-65zw>uWf^s9tM(8T^=1sPV4X6?WAY^Wz z670gt>U;v1l5iF1yICG`>F7bciBEvQX)A%+uono-RnCuwU0+8BKY}_W7%dl7uj+$n zCT(wOgn3iME8c)5!f@|IsPx6ikR`CxVnf5YZtvD7_S zcplp%MR#hQ!vG;3@ZqlrSmKg?u0GSVweR@FuD}R=p|^Qs%h;tF>pYeCA<;X!!d0{~-_iNOH6)(@BxBn>9{Q{nFjUwp_s2qOzaqKy7$-}P@jPV6s_&`Rz98` z7DA=mqUJ6IaY3t#F0OO^I-Cz@#y3l01ktx4uynlG%_XQIY8Nz0P#o- zI0*hg5+{5pYEp%;!*$7Gw|WKOx$enm8KJL^Hpzl=Z*yG_CmLT$YKSpBFxaQv0hxbA zAX~=Mz-%l=RN!SAw>yH-aCu5ZDo8=2Mi(=f8pq))-fmFsoD|r_^|USEF}1F)09@*W z5ZUpikvvQx0th{}q^A~~hSUy-U{|1%Qgkyw8RlGBL+a%taR`j_F_BNwwDJQ0wHmq@ zN!y#@9zyq@YFS2Cbyol8`T42a^Otq^U$%0@m(6o@ziM3zI5^ouzT;E}djO76MQ{h{ z!1kKz}!Hh1?=28s5UH zzXq<5>-xzdeW#p*D+h+HuU{VnS4p71Z!)l?i|3pRU`hW73ZzxYaFf9=0Be2t5`0>vemkgriR$QI1?FFZv0oT^Yp_scTO}`yVQYt6;83Qw-j%B{_8|fT zYF%{SOG~=VmE|DZ2PQi@%(Z=X`-c;c5zkLcj4_3c(W|DCHbNsr0A_Yw|6=pIH3pF< zhPv`K!eM-C9Fa*B7JHy>kkaJ!`TZcuyIhvHb2|AR1gIR&MCZ8sxYuM6#RRDoINv`( ziV&JW94Fd$(CJqI(>eNO;2=2X=MaMY0Bj{^O84!yz0~L?dYi1AA`{I4x8y*erhhJ%!0gl*HH*|6qd%kfbATuM3_OqwNPrU>2#fRZ05{g zZQs(k!!!4{0tP`!>&N~`yF8F_HIeWhSFT-i7Q_)$N61uem98Ye45fk&k*mtj4fwO- z>aH?@`x9I$RAVu<6cD0zuU$xt`>8JiRX70mej}KE*GtoHLIBY?aBm|4c9))x)b5tw zzWk!E@HgcJ|8mI!2{zj8?F*A+-|so{FCUff@jvj~Ir!ZH7bXHP&jNL-v$$M&;EV~0 z=Qiubi{wG5g$VpxC?8gG1FoBAOgag}o7bdr*qHA~cBd9w-B416v(jh^4$KMB1x{+{ z9q8_&b)k8`tu%%c!u;xQlx}Ofq$OjKu^2%OIaa}t!KDjm* zHC!Ra6seC+67Ff`ZdUl}#6fBnmS;|S05=~O7R%+T^T%%A<(-n#`ki&xGEFM6P=Rnx z!WY?r`3?=$8|dI9A>sBzsW=;PT~t@{gqr|0Odf>4fT!5LI?dHb2`X%fQ%e|&eI=p@ z^hGFx>m`rtgi0UN$xdD7zN_-Kp&n81L5Wx4|1)0eO&{xJgh!=~`HMf|ZwCtg64Zuhl2IEQWt4syu% zSCPLZdBO4z2$=cJ?m%bXm(NdC&6gk-7I)7oopl7=4}YeCn?GR@tTaKTrWQk}N}={I zm!$H^Je{Mj{xkxv(E*rIA6a@ouli8L)1Q6lAKBY5)6HQq{oY#tsNumj{>h8_`6Yi8 z@&D=-1IhaLFZtiR;?ElYzi>mc#USoXRoDs}32&J_Y`#5J-JkmyO&;cY8JBPm3fKKK zA-V1*&rD8FcQRViYL$XVyS(#fA@k*J{m}$uu&1F_N<;OX;pUopfdtz?!!U zhh%573O?2+3-Ns^UkYJ@By&ex0t2u*crKhWp1;@o^VUi>!=tB8cWVP+4MD3-%0-po zusng<=eiYsogm?1Be({Av5>H(R)bJO63lIthk6SNp%!L4w7r;Er&K(hwp_!a2Ql+<;K^rP+D4#Z~?t3LuV#0y%V} z@#?d3IyjksWM;l<`2apCA^6F_d-k@dBLRTzKF2jSd;{)yP;L>+&pHd|`zPUVc~b}l za8hVg@7rPkm`TzmyT|hh8{ExpY2s){gdQGtiE+JNVu%U=1*2(iaIv{4c}_VShAk(86|)+f^seqE-vj-9Pejbe~vcj2R$XZl2y^;uqSsp2Za8dt@(%cXfFAqo_wl+NTA$iixrM# zPqn54$RyIee6Pp$lYACddD0bZi)3pp-|b^-#X^1{C0Nhf3I0JY8Rp9^V#5yFLh(t+ zadUrwJOaGe`m8373C@BeE4qxBVnP&ndr%I0>wpBZa})2$g_gKE#bknjSgmEBC?4J! zc#Fk5ICJc;&U{qNjw_Yg%ui*y9DDlWI)i6Ao4F249Pe2rqmkoUEOp*b%1WD!5Iwh ztJ7P9{ny1FV)_785dk<5j-OB`G*tIs8sP}xCXq<(z?+f37JDQVp0!fFe}t|jKfgwm zZ)wTfXbD9b@}1v%<-cdrd^hf&OXO}8XOLaq?u5A7($)2OKBMbOJ^FChcklMdoR)+J z4l7kk1JdE|p5F*G0{SO9gM?MSA_p&L4Y_6@-LC1Kd%Voo8$90oYHrw zjZ#3Kx@kZeAi=ExaL!fc$8)GHm*c)Xv&Tg6uC^LDrM_v0QS%9Vdlx$}?OkI5i`8g# zW#yCTY@KaQqS}6qX_xIizOIqrwm!5Klpk<1q|IqEXB(waEiMP3#?PfBok z0wXXq^bNi{SL%HUAi?WiV6lEG*O;8%u2>v#*w#xuH0}^?ldu6$*^Fv&?l+FiTrz5o zVw;~^f1K7!a0FY%RQlzGR8F2|909`!p}ml@ik}s8u=(0n=-s2|Wm!g^^L^L|>nTYt zhlfFlw*x-7(TKX*KSOOkx?3E>d^^hgn-14&v-{IIhRI%CuJlKUj<}A8rj)3Vr)`T8 z;&P*3k2!S&GjMY&avhS`S!(&~jgI`UI$SSi4f0PNuGbXpv%@9*=y37pwF=xth*|hq zO-p}?Z+;wlQlOy0nE3ml2gnsL@4$bYdH(tqU+)n4!NUFj-o$&o#n(H8!Nu>Jc>ne- zzK(SW^wH|qTa0oF`qtsc{}$BPpaV(IXG%&nFbteoW7`c;STekK*+;Qy@K3Y#YEXoN z0gdhm0FIy+1V2BD6TPNs9Vge1wG07dX%t&KbQ>R!gUxzex5*|i=bN=0CdQFuZV(E$ zlSBbu1lXV>W~xc~)$woU%z-J(zyD#5FA#do71nbzrs8Ah0oo*ef7i>J(Py zfiaB&K|CQ1W_5@Z_Tf5YY3h;pkAp){UP>km%7 zUr{1gQ$4>~^xvv2iG$R8kTt+oYENwbo})`sp+!41RIPU)P=9r8A@w9WTPA54YeQGh z_{hE&r3yDX9CF4q%d|LMrJ$P&H#syGc+-wpz%EY`M7F}@9d64^csX{NGsG|hW8d5G zRJe(XAR{2Pm8gQPvr)<`Q0v~~0bZfn6EvXLYF^CmLEFHRvZx6Z9`BFcALBp0MW`nw z=(7B8-s0;WBLAzm_^OHiKBn`R#&maE8EZk|)n%Xn2PSpof@h}$Qfp61{Mh&=2!s%; zX;o1vZ@W2`4@FRe>SMx;jjn{Nvh|<2twuK3{muDGZKh{BY-*wLRcBt^LZHk=XdKvc zCbGv+Wn9F3>1iqmP%^&{6d5?iw;THXKsx5>uBMI#L(PgcSswe9Z2C^_yFn< zcws14V7`}cNu0x!az;dclX$1NZvD$@A-Oer!2%v2PgsgS{DTrf<8bk1NN15E5IsRW z0nR?oBj$KltGTj~xT})mT9G|E)FLElg@;j7lhYC7vG!+GxowH6q6V|rudc?{0`Bu- zb9bECi^6{BYpCki_sx?l8xUwE`#Hjdvo1s@s3ef*r-f)6!bIY4DpU%_fl#4-^0Ey$ z-@jF|CdIuzF)H-{K4C*6amo|W2L1&TW#%AT@jRYovU3|9Xa2Op3B6(ACeD8i*!uBY zU@W9Y{lID+0%BE>SxoxDNGrZ$=G--l&tF!7bO*f1H8LJ_8qf8|pZ58o_j= z<)&}(2Fj0`gxt^ROG`i8&JglyZ@DTO_HDPD*PsbWH)GVb8gYQ2qw=zc@wB2}o|v&F z51Z8If|wzvZpB|M&hw7Po=4Ut?Ye(R*m`SGKuFzxm`7RmRTlcM_VZ`(3$TLz+;aZY zY7eoPu-cbjqevPu%l~>Kuyp#pu?$_>qs@K`8NR6@Vy_(-bF9BO)ljOx=5kNyIk47@ zcW@awa40n@lfEtBU^KdY^eSGp1=LsMGq^ZCIB{+;J%p}wMt^0x!2EprShTkw4jJLz zel6aM`c8`Y^)V2^{*d6kd8Z%^^jnhi!xDK7syb4WAlCLxg2zMR1q?}p3sidRLl1&? z+hFhs>QjIPXbw$vmgH!6Bc*DyXlW&=7VELw75yq(zI#0C1KIyod6UmvmU z!UwvfHyL||cEQQ$T{(4(4hrWO4KCGk}Mvf!5dCjN!M`1+#D@h--PlFmU#*hO(2v?c`xj zAvY?&VwzQuoh)>j4dJBP%cWWuAH;)q1oux=ZPqy=q`etVWX$Ntxdn&PCGzITxt_|u zYbgJ=#qdGk{+$l_aYL&P1(eJsJki%KqD&$=+$R0(b{0e))Je9FtLI8|pRT#hS{)Y- zurTeW63IAG-<_6XGwr0hUspEWF)CvSae{NVEps`GCu3Cki*T*$+5`zCfn~ST)fml1 zmL`a`P~uiLbj;`lnCuUSGFMHhxMA+b;eS-VZKdUIG1f|b{KpNd&V$MY@Og&ytcb!y7-BCa+BIV6MjFzm* zqwmWr_K+Uhb1rxCje5*&l}V>(1m}i-YVYb2R8jwNB{M$8^QTzut-&i$fYABVqWQ-q z^YHp;Kg+NA+}XnBX=St`;2DxcG>^QMfEe^Q%P7QV{A$E`5p^JX{Ous}if5s*NQPxm zxn7EIs*Vm+9iR~w?-0upJtF2EfePa_NMZquCqu#i@$2L_saI=#w;T>|xFrdTlX3f8 zO5x8SGS*&FhcA~X6w%4&^C9=ly4ue>B(D4ri9#+@ltI-gchv9i^dvn z35QTHe?A7*c^DH&!k0Mj)pdpVB>6@5`x2nQ85L%UA3xFh5j_v@z=WM(jKOPk-P|Ca z;+7vxSnNU612-^a;C>zoru)fsG}|y~0qXkxD!gl_CGPcSPr}lSTd++ zfjMeK`+TM+!*Tk)K-2ANezv>FYKE+h8lG#hO~882lp<7@V@o9i_9CCH(w53@Q~0-v zrh?~EKaA_EAPo(JLuBD^@h5egu16BgHB*}m0gFV$8kpEa!Ai?* zV+FU;>-h3KJPnJJ=T4$Ft7v}6J`hacu-e5N@1g>!+gG=AzxH;=Bms%LdJ=9jIb4wy z@bWWRNOA5UcFYZAm}zidn>t{-Qhu|qjy-zP&%g(g6z@zMvQpJB&`MBzW2vKahgRHp ztFb4E(^~^k9zrmZH^_e6xWaB4JHxXX@|pIg2Rr45{~qH;Yx!sW^ovsSTdG|LWoDcE zhfb_OICL(bHvyFbxxUrlccDD_IKmGCO`bN{@cT>s@lUd6uD`9u9yBW_VzhNos;iHY zUib6)PNVgi5|3ulK!i`etYK#b3q~+Q`k7QBs#=`q+eSjS=c@<{?hw$OofMnoIbaqG zdA~Lp7>Ct^nKzq>E~7|w#0m1&*xhJvmSr6hb4>#}ZYvr%f(|L>@dd+y{BJltwT=Pa z40ExM4t$fK-OGv0)updu&o$(hRxdEGi+6UR~ zsFxbV-|DG&6S%=Oglst_cPo<2#i-#hoif`LULGF9$^6-8#GIV~AfNF$PT|vh*B+dQ zJc`MTI?8x#_9a}T+y$_=eX!BULj~Wwd-mQ9`wg00RNLEY>jA&!@=Do52J`wKyBBH} zwvR3j{}cZ|<^t5z$7fp1-!J8VTExW$gwS;TWj8S>b;gN32?2O5`FKucZHyf|LF(II z*|{Sq>Anme@6{!5e@jmYLDVQ?upo_BFn2%<+IL`x2KDV6Y(e}y(`qD~A+5s1=v@Dku+Mv$-E@G_{5~+)IH0 zJev1K8oC-3%-?=Iri#+fNeso!Q4M&@@2*Qw(cK_G8KO`?VTVL4_YB-L78kAOMw15dwpeb(M%KFVSj%t zZZKU0B-+06U_k`jdKI>XUcap#cF(F)P@Fhy>dM4>W|ReDog@9)JwmV%eMAJ}J zzkQ8&;Kr$l5~@=Tc{Gs*2FO*~%>2}Ir-F;GcdDMkT5V=OpoV;MEkJe2E53au7jnf? zyazEiJK~B`SCR1pE*39O3oy(fayC|SwiR86wsOdi!cY7C8X^G#(m!?BRbJ!OdEAd; zfJbIqUc1I$Wn_Ju1!*lOd#;Mh2Rv7VwMKPhqwsX4#QOTL83YpEwS+$8J63 zSvdn^wquNLzf{+7OovSoyl6m1Nz<3d1xO_jxe69ENc1SiBRF2(*3z>rs+1szZ}T;J z(X#`{Kwm;Q`w8LPZ~x2CL;}(!%-yyykNajpRH>tY08I09F!z?|1^3bNahF4yf<3%d zB(O!l)N;|^4gFyI4&f$#IrCE*zJR$KLxHt0P5F#Y#}A8+@DQk%2;-&j=g+TmDFf&& zNSfzq(2wx9=}Xu5%7H-s@)j_F=3$TFtyqA>#m~17PS=-Zz!t&!%2BYZFccM0^oT-(=#QWDF|HbD2T>{-*=Q=P~phd6y(9Yef|Et<@Nmc z=Xq2x(iK7p9CfAG8wHmhKhqCNI8czIoxUEIDB7aL$Lopk4~MVscds7=d-Iw)sek!C zwCBG)0bXG^()H^n+7J%*`UkxfevmLy@#_`B*Z(hVZa_G}uH zLmGiyAiAb$bb?tMthk01Ae%!}gu&97B8AC)6mBtAA1nNaLTS8 zET$irht*G5>xE^)P|qK_TB2jI26!=Ec{G1}R1T&zZ(A7f62APzArX5OK(B~nNb~LM zkhy}s?P_3~hHY&=Qo!Nm{p}uJM)08#rUv71bR3^ zmgjd4!Es9+5+lemwHr;`GWS+OmKvd9M_4=lUc9^w-c`jy8a^mob0>KM31M#9-ig2y zk|te{pS8j2(koc=jmj8y)lF%I^EG7kX1f$G7~s6u=Lc|@Vs<>ZIKALl1m15!pGfd; z3e~P}s)K4r*n*P)`+FYOOZ=1xS8&ae&-UVXr(MsKC>Z5a^w3PH)(L>_lgA{Ah}>C* z$bOsR&1Cbmg6CDVQ`hI`!X-AFkQldD*QtRjSGm=)KlfT^)N6%cB%!BC7UxI26V66v z2l6G8u;i3U$kPeB^+viiXXl`)hoikv9SE(6>O;hvXK_Is_7Q$Oi5TtVwGDWa-F~SY z6-AwP_5kt0@s6eX%{r_yokGlQX*6bam3t~lW9HZa%61%%sk(x6q<#!U+Wu`N`w|YP zP54>3{;5u7<~o)9R;M1w<1WSr;0)Tu^1}iDk={Xp0UoSMKYTo3B4@zC8CLEWw2mPw z2sWttlS`~ZNMQYz4Xc2?AHYz}9Av!#2`&zSg+Rn({3jSS)^G$Iz}-BD7|xug?`|B_ zFa6e8t@a9?eGQA})+zKGU~~W^flY)Nmw5X2!G^3F5qY1iLm~U`c4<}Wy z>lAp2y}Y|3p2pTYgA@D{pM!B1*J+{j51a7GAG1;B-SV;bBew+cQ=bzAmaF-~pmvow z4ZH3X`Q2tR8LUQOkwHIo<=`jb5~(Ra0Z0JERSzj$Nwouk zHC5e>x2I^hImAqCo}y!q(J)cx&H-m0(xz9RhV#F-86Oy16qybNjBB`Uwxfs-^^;iY zPpraMk8H#}`w&ejo);@rUt>U9!59G!2?JE9vFXA*U$z?ymmAE`0<`D+dZ|bWbcug!%yEJb? z-MWBx3`}{mf|!I-?e9Ij_n8=y>44j61XRB+vlit+1_v$urBtoetF!6DMacNX8L+FC zczdk$eHJ;}$_9NN`zRh#e|c=D*8Q;w72CnK#T&a4dS7w^lp$CNOA>f?FTMA>HCH`o!8jfQn7pFBkQyjEA&_m z=62{;z+|T*^0u~zrg%7N-Uigsh=s=z45sJh>WB(DB{;09?M#KtuA$z_XOK0@lqP|) z4{@Kuo(*6lE``TwgL=ss0)ArJb?N2xzKXp2!V2U+%*2?}z3)J|{FimAPGwtvv;zM6 zReZ`nkt#9G%vNflW`@Ea>UZk!)AlWtAzz@S(9#6NIvXn#oFnGuYX+OD!8_|jP{EZ3 ziLJcT1#Sy{X=L`x~->7*R^$J*u-&(rRq78p>r=PXL z%<7xtuig{7XCTF#f;GH^w{HpEn|I3v+*thiW&Gj+XP)}&ReUs?|Iy2M?_K=zRe({7 zm=PG%{4)OOsUM{CH+rkAak0B_GHYkye$Q(928kvoF|RwwMc~!SZdMU$7JNp(HV=1KD=LlXs z5U%wgBorpPDFza#lu z=X9ScKrwK=<&Xi5p0?X_8|G_MRlDtOJ%SYA7VRftvuk)?=?t5*VQv!i&Mw5xJej90 z9!iLL+E|po4=mL?xk4SS>NeJ|4{jZvk0H5mHyW4KLXbTV+a@to#f+jHn3bkJLt136o=7zA#O*p{p7`XWC0YqcTo=S1_yxaP9 zo$eNH3b4Diq7b{ymW*!Qr9Wib&g$*$R05X_4~z7%7bY%Hbn}T!*?E$cBv&h-(1I<; ziA>*=F6E;4W3|uN6L$&4>EcyOXREM_dxKsS^Lf`=@>m@2^kuCc0MVqicq8tSTd-RK zb+N2h?g}`$!(^2~&B)a@=dx1MN72Vu-8lxH2=w(~(v}x-_Nb}?KT2HAa2Bw6?98J! z1dT)22~;EUxWMyAvls#Luii~&rzPMiA_^C1fj687YlcA;s$ZcV9 z)Y--(xq840XH(kG=*Y&6J~#Rr!nN{01(0 zgU5ZL(!oJ0U`{S1#z02r8%QVVpx&9ovtNtjdkqWJ9&uDH5{J5#grVuHh=mpM?Z)@p ze){OMwfR>M4te2!c=Uf`ii9i_=#&|T9%RSmUR5_cfROa#O(fJhQ&n~iRAvtLu<;y8N*SrfF`5iCSX0#4Sa~gG? zVBq*h=Zh`5!vWSJRy?Xz7OQ(2n#(Xv(`xi7K-kp41~Njz!3pF$eBM*5A_SOCx4SR3 z)A7#t^&TTwQYPwyq2Dl&@(KFMJ+3e`+~vm}#=;k?xMAfvT05)FQp_7cD75ZX z+%;=@2DWf&e9*z?6#F=&6hu$}1!Mkn)rsrL3$v;(=8>MRx1<}xc+em~5F$-;&kQVN zui&vbWZ4z|{XI2uT^r7tKw)eejF*Y@J=1P3A5$clNJEzZA`gGM9R0#7_MMW{L}{T@ zPaTZR*e4H7n$xuH@0kf)pov_*byHvyVn`IOGc#4L`~s&j)QMD zGs@i!ZP9XuhE$L_vk)6d<`wJ~GRg^RZ(Vn%B6G6KP|!U}xgZ@l9w1CBTnI|xUSZ8W z9|^JOw3QyQ=oBb1gg0&?GDkLwH_2Bo5EmM5m2G-Kar$uB=RTk8@^L+9I*y)JZ5o^s zjv<=SLu?=I^OA&NCPVh@234vHws?XW3`H_+RS?ZexI)FaA{NtQQA>S?wrw5X?B2x! zh%~ZzEiJv;vQxswd~Med{1MjWY1luOiZ<>kx$q5YVIdyI9>g2CfA4KfuC@sesL2J+ zVmofPr%U&?Uc{c0(CN0OqYD6#3$D9>#^R^KFd__GSCGovJ{dAW7n=1Q1t+QM=_XjrL2-94g6M>z?w_OgK z!mgxxY2W-5B>}F?FV*a97Pg&XayA`89fe5e8UzO@`(Dk?30%P61U=VB*XxTy zN)cU0H&<{x{pbSz3=Q!&G6Zn)XC=c6?o%XhdV(*vLFJkNiy!~Ktx*}?+>?B7NlMU? zWI_Q(|7eCmrtPb?p6xqOS3cw%J}Yk{sw?s-KO2TDa46X{KYMP!B|Siw|DPub;--Dv zwOEuh>N?n?y@0K@R*fdB=ic6<>gqYLSy-H}8An3QR}j&*+96`Fxjt2!AzbQGfZ<-e z>*vifffN`XlOetvKSIm9gkWaW<9p*qT~=c+He{9;!n4B618s=4aM($xA>~MAP2m>Y zQnW;sH~|^*EALS)Er2(lAbrcGT>Ilz|J7 z$sfp78*$sCB}nRHY*WBk(D`N6t}+$WgTcqzqM9x^2e%O{w7U}Qn>QspY;>LO%Tn82 zp~0f^3Zz{h)xty8=1dR9mD_Z$P zcesrET!$H6w5g?If8HEd)bhLk2^BKqN16hpJnt1A1Ljd#Khej(!H_rlD;o<7TEKo{i7v5_vp`ER>Um z-}N|PPPJg+m4m;%YuIWA-JX--AA#-2{%=q9?4e-uy)KF+sk}*%YF>H|}jL5(`rN{z8R{@M- zdz?9V8=gB-mkh$(ex^sAn=mO$(vb#zctAT}oWuRhQ};)OinO*qpwtRk^VdM-HXRrU zgJvn!ov8~3-(JV7tDPvhHHgaRN9F1@b<_;)HQ4&qaR@F>b7b-wwzOwWIhf8rFVhu~ zv=k4X{%xPQ>m%w~3noa47FBhc7I?@4KkP{YdfLZ>*SEG{I1M=lXQw6fK(FkyNDVM1 zD+bI}hr~g~TW9vcdFA06cW(p=b%DhXiaj{dF4M~y+ZNb%aUc4tncLbrN>&v+vjz#8 za+PE)uD}f*-BcwhYRKYNy*nr^stb)CQk^EzV!Pa_cf66;Y~#Dz950OH<$_L(u|OyOvd(WU3dN;)!kkhcwpfCfSOI(~VW$;Oq&sd+ zA@e2vF$Mc&+VouwVTVQ+9H=D$y>6F?v0Eu>Sg3~)27O$`cB4DD4e1@wEcfb#c^)(@ zZ>(Bl5Q=8S00*v4+34;P9VdOkWU9UpMGrHJ)vY=!4!j}zbj&%gh%(BbA5-SX2-NWt9V?>&UM z7&5ybD+L&UK!nzt#zsIGl7Lj6!!~$j1o!jY6pZxcXiOAfFW%-AK+#|x!T}s5RVA`> zdVSTyT(%P-z7X1VRR~i(U<6(vN~244h@=_=Vg+gR&&Xv{6C~oWPON88wxejV-kIQF z;$#Jmy|1)0U6&b#fO(rU&D28!`hXC!@PtO#1{^083T`z(>s3R-6L6fpTp;!M2>}X# z{xrw9UT3q$5ya}3MA7y!Kz3daWIM8M+wWc|)d7}Kr|@N;MV_5Pm+{@Z*k>{JlGdwG znnAed<)XkbzLX4`kTsT{}9>hwuXS1xta+(yQ2;bxB~31cCqiZL^?4 z`XPAI;Q(^Rkgu6F_{S7xl~jInsgU`#n;<6fU8e)9h5+H#Z{1i}IN;6SLnH5Ua&3qc zt$<>%2IbU{CiSa1dyDF~_ZMCn71siXG?)cX|IkAPDJR}xJ->G{RFhxclhI@-{(Z`; z9M=v|K-9V4z(u@sdmY{C>NZ~{ATI5}DL_F7a(qCP+}|z}!`*;EqFN2R5r$90{6G!> zn1M+Cr3fE}&_uZ&NzAWrJ~zSi?k=)xVD^Jzw+7uE_{ra%m7?g5#WbwUcAP<(&-Xip zS2XN`8~m^;5Cy=951uBxOfmE>ec%B<8WmuIHD;&S9Q{39XYgx&Z*91~;!fK~CON&7 zEDAJEG@{)oydDj3pfSj`;R80no@;o9A`2-9HaX71H{H z%`}7!AG;nn)2CKx3p(H-c+b(rBy09A4CiIMg-T7I2H;bOnuUqN@!dD{6|$%1Bn*0h=5l4)=J1WL@TI`LXE2-o!^^ zZ883OcVvWfPRZAtNK*){YGoNefpVr(NpLAaE+S}V-eReeH^z;QvmC(KAAT-8{Uv%K zTlso_aLWr@G+{601vpWDHv0M@*97Xh7cA%3$^mMG)8r^Mk%Y;OU0-F$mrb4&{yKQIcFYhub6bSIn*-p4vIIp1ejqPdlP*PAWeK zTS>5XY$j~OQN7=z@DqYk&Ar94g**va*Uw6=mJmPg4$AKC8TvD+2fx5hHzkd1{8c>*a3O0 zn*Wc^Nx(mMfBk761yC#Ok;VOU)J6VuAEo54%>n2QXx79g3ia|TvUEDw2ncdEG0#n4 z@S^PJ3f>?3F3=l~%%IJ%Ko zLE2kul6a`4pN{lSL1K?wwS{G=Pe|3ZE||P$Zqg}>S2y=kTBaaY&0AF?8UEk`6q3YIZL2K~Q)U2aZxyG;L5-z+!IHLj1}`yk=MrZZqdU8k2B9fv z%L>{jB()5VOg+2^b5-Yg&IlG-xnypv+y=rvcPmif+=&}54m;-b&9{XpFpU2v3WOt$ zLVUzyf5PrD@Ne;sY5G!tVxWU*!~5C?yOpqn0sjo$<$v8TB^|!Ot^C%s)K--bll0UN z!c$DRGK+vX+RNa55*=g>5KM-yJ9Wh4vk;h7as{c9mPuYxJuNA@(i``RQs|V0tHLAj zL3IP$SC?L2gE1u2caZUX(;X#wJbGl8ZG_+mqy=mpOC-UK&X{}GFf0Qev&Z<3N$a!; zf>MjtO(+9jC+^kFdVhBC$Po`iyFmArcJxqa*`vrgs7}H#wbzwiN*;)YtiZhCqhG=( zXveeNDFlql&R(J=7KmVZ0Kjs{^h#(-f2EZP+P?7*?b&u=JO5mZyh5b6HsA33;MfZAB4B#Si^zbss||Lx3gFX$EX>(!B>dnDV(zVI zWGm)!4KnhHGAw@Ho*)|r&G7TxOLo~<-BXxbhm5t0o-lwoxKXC27o9io3Uc3__?)1s zv3%|cbXP8~*K)nV8l3>OW}ge!?NhUtdA(fVwZZUaNZIXeBB%S_LL(%t>(V;rApp5^ zn4)aGjlAdSSh`9Vc9G*O_>yvZn`DPpAyi1{c;NBsa0T=r+Uaf0C8$;2r|9Yswpd9<%&n|#S#(jVc4)HhmKv0? z%SD}zQnU}D-rYlsmf@d>zp1kL9$$k)W8SrDjWo_9-OW ze6z1(xni~HHf?}DFQT34adg4f&~$H*`&E(8NrdI`8q(C`txyL?;z~Ij?I<#%sF#vg z9=bk;8TF(uD@|@f0vsep?%!KD*G&(i+m5*oaLt2=T+6#E0mjqWusXrFE$4281UF*a zGtc~~sfAjBuA%}>Xw~OSlX&joW7VHPIl6}giBqmW51Um+br`^HVQwt!8()`L>@jEr zvu}r+m!Gcgxm`ol>8A8Rnblq=2hu!1@+wJt{u~0#Tjd0%-1-~5m>{2pJ3rTbv_jOj zj23j&99*Qi7m-209XMU$K-t2e0 zwH(}F6K&0_0x&hRd7`%yTE>41d;j=exUhw z_D_c~&>rDp8%0%nvs;QM2%MeLn~~gCL-@RiDz=JC;ii;891*v^I$*)k+eX(38zFtX z-=)vv!&(mcW;tUObxwv;j(^_~8raHVtyd!nKk?k;vaOi^e!*ISI4o7efaZl_>UK%yE zMJ3W6D9N?3YvToGo$eeDAv!~P4CP%%=n#1JfHdc;g+z4ii($Uw9@>Sih*j^O{QbqQ zvB`Smm1g81@vkIhd8TE2jpr~vf4Y#RY^uC;CaI0>*oS5;*ARu%*@$7Sq$&$FR^q)n z@hnC36zpa^``uH5YXP#nL0aYrjiiGma|TxVc>&S#XeY@Edsl9)A!Z$Z`z z)@hxGG19eV`5mXv|3t62J(Pd3grH;tTNz9ir<&~`y;6^@;oN{QBpVX<}#xFS|{ zE(V|lbHuc2q%i0n*s2YfGc7HuM@=APmMA zIHG+?;ivUK=Kp>^`i-GKYl^)3m!WCa&rIiksw)_6?q%km21Ops102_o^v8Dfz3BVL zp6B8C;pCg`*ML^ain(`ZuPVVR*g&D;52v2~@{(}s!C2v`T@pu!{^IqXBhf*O3+E%) z=Qi%&%BPrH#TRVxA7^k5-aJ{Hf%_H-5m#w zK0aA4igcZzL+FZhy_-+c0f^dq5r7oENAWb9Im z0j`ax@}u#zl(Jh-2W?NRf|GqB3UEM{1EHIyZiS$1itqcwYRhN%iiT5h>?@7FM@$|+ zHmiqCj618uK?!$AinwANCthyFgF?5L2P1A&jjJ5A6{t-VuQFl3f5_1g;CMPNxH3%P zM+iaJD`bSy4}!|P;&xasjgF?1K8P^M3eWMVCm;%u7eaSixuYw*E|M#GUY68t{5-~AFVZj!Dpl}19)Ku+C=a>4DH@A!{2U0UN_F5px->= zKYhSC%=Gi5@Uis19~7v!gThDHDPyVUco}1-e#`X}x0j7*v34H(?z)wXO;=A0(k_-+ zvtxIr=&fPSlZhGGjlQg*cP)&HbCx})_ztD%z0DkKiC)ohKWh0{ZdZlDQ8^$)^_r;+nLhTF;uK6=LpnD}s z@_Gj;@S3wMBcQ%m2pmBlwY!Vx)Qnj`77Gx=0jW;X^~9BFAwV?2xxZXWl4xiP*z=hR zJ1gehXkKUlMQ*RB4Rd=~n$@he8xl{Cx}Nk@9A3HNeY3Qx4iAlxw^#+clEw((0(h1v7H}G+78u>$*98aKO2fyMkTpQ>4vYD-b z^Ta5njA~!-z4SO^m?OD#7t_d~?;e-l-hG&#{>F&^0m`=gp&$;<;&?M}7(uK}q)KlB z*|FMg8#&s~kpXY6JGNT`G`76mmP~X-fvy0Jq;+?KhR>yiYDCkd4Z=Sbr%jDNF=Kn* z7A{5vnql=98jlqZC~sgt8tS_*VcQxj8_{Y=tn_Z1l&I8)a8H>Ak`5_n&tZloDu}k^ zR|1(2ONWOp4GOt{3R>4FHcrnC9(w_|gyPX!IW6Tmc7=Kt#vQ^ z87GXkvqvbCpgJ&Ag~mOo?v!%^`(1XaaR^@LHU4U~i?bZvy)!7Foje$cv$yaGoj&aD z8tgt#w~rluTSjT-z@EtOO9&be)X8Ti=*8`yd?OonR-gw<--))St#Bhan{*-h#4QIK zAlZnX*6v~4;7Y0Hag}{Q@e5S3n;NOd-^b>WmkUIAzu;-mH~$}h9l}f4oVwFreET@v zni>#HUsk(c4!Zxi47PL0)_!X7fC2Wi5jDm9uprGWweMXdX3Y)2XRl%uI6f$WLg{vg zQS1FX2*aqTxMLytYPgxv^LFEWo5CvJ56a7n{skH@ z0pUji!)*pR2y-a65MeOXjO$GwxSOw33*d9EsaT+3ysEy@hRT0N&_UqLGxMRz3yP%) zyA_J9&0}?*qj(sYsIJCmK=}oC4I0{*4Q5k#naSc>e z@m5`u^q#u9((21o*#{D%+n$ueauA;V^@Cmz415&xtk+$( zNScDVgHv(8zTTlQyrQSX$8N!*@tr%;JX={T-^CSx0_j|&Y?2VzE%cjrMdU-t* zn-VG%M)QqtxkxAI%|+kmA{jQ~c3pkM1f^nqs1lD?XjALuazg{F^0Th{EbAZ_$(`Gb zfM=zkb!JOIX=R7cO9%u9vrlinhCam>5<@QQYU|aFG*$Hut1Ed~-7mwZO5r6^xNCHK z*O+RdF<1C=cLG(-1Bh`w+;D+k-3qR!9|o0woKwzWQ$m1g%&kLOG~t#lBycU9FpiIG%Jnu0Y;R-*dQQE_OWxvGYg0y z?g4;`yj?VG#wyR{YI%zJc<{r_uU; z*}KYc?+hb(;CfuUNCNMyhm~fy05!n6<$y(cn4bJOFNZ_ShnGXg-dG!-R_SiPt|yZz z4kbi>^^}*L$q{Yw4c#3y@~BIRi~w+_?QvP+$#dPW`_SCwRCoW0j~bkW-%8ZZQofPOaNvr4elO@iUf(?HJAhOs zroIOuN3Ywhh#=U_$kB_`+TL2A`%RLdGv;8eZ4CFx& z)t;<#;;FtXdu+!56?t zr@?!&xIg3!e>Q9OmQZbR4McpbB^xiPtq(<0fk;b=f3W5=4+T;Jrf5v_PJ>!dVkjnA z+jZ7K9Os$Yu5mMsCF00m;w4pD&hykiSpfqkT>;==IBAm!i^Ll-55t(r`DfzqGZVd} z&1L|aDzjZZ4VfC<6XRJ&;3^1R*i#nX^INs1L6p>IJ~{#~cX!qg`sq4gG$NYWkRO-s zp&mP*)GMoU7U$DqS+T{bAF(7BSDXixRK1kx-Th{OZm0JF_~4`wN3I|bmTLB=k%UZ5 z>5e3o3vGbY;#iiD35EIxm_#3d656Zx!?uC6tDCYr?km7@KFi%`8Y47u4~Fpc5BW48Bz0X!2wGfF53x8yN7C{b(GI zPD=q_GbfrY-qok`1ML^KmsXd{BDsg+lR#kq7Owi%V{e(XcP&dxAgoBWsL9?^dvec? zv^l8&inv_c0YkGaCeE9pbq~8?bE?ctlJe7$74bXtHCTka>_SFJDyG!c62i*iNQW*m zRu%j~qwwk~IT02=tb_|j3?{)IWI$V}xTAE%^T10M#&8q}b%8zIcm^Tej3{hAtEhrH zIMaTA+%jaF>=_+9%4rsxC8-|oPYN2uCAz<*OuiDjV&h^Ww$^=HFu^=T@B70M!#bp2 zVshc04*d1e-^XnMXdaP!UTKfvk{OH%Er=*lD{cWfOr3YVhBV4|momp=_BL)Ne7|0_ zX(r!zgYAFUJ?OJ==udxrEd6hxN^`}{|IVHLzMsH(PE`M*!BZ`AFmSWjS9^6%*rXx; z1O(ro{RLe;17umPS!-Vshhpv3+nwk9EJ@IDPW*SvKCK_p|pE!=Mv`~+iT5J{$A^HSL#&JuG3wgY^7<-?K= zjJfZh_Ll*z%s%(+$GWXPDcF`cEP?p1uUi&`Km2yjDi!*T`UcM}`gpLfYxaj1NQbQn zHpBR-zy|_A4#J!)KNTxD0{EPSv!Le}89yc2ws+&SxjW67Gf(1qk!RtOIzbBLa5yqL zc%V5RJ_`pEkwLDY7Y(~?m)B>^FV-x!Y_RJIzj6EeiZ)qVO&K9H5L&stgqQnbcb(v% z)#Q@6UQ1foK?7yD@5jY8-yr*CCyp1v0NuayuC4py!0cD^GNkTPusASH2n-xv+sb{n zm6&5{;88cwGb`-vrGv6XVL}iEfU15ZRSd_uL~ys~n(j1$@If~?*($>0<=znkOj54% zt2y;2$X+@E2?;`t$;zT1%cb91y8tXhBdM4wfIniJkmJTnT{yZ=BE;C>>vr_uE|A-8 zWl6TK9@h7EgXS^&Nc`h-^CYWNQEXZJPyB^nf5d-V&Hbr%W2L!v8>P?M%_n)UUxm%~ zX0GZ!kmcn`2hi$IYq#5%$^N(6?e`yZVA6bk%+Eh5D`u%P3i58yVSqaWdSsUv1>y8B z*N60P>%)&l51gH$f&4?&^H0}@&*kA=NR7Z+05HdSWty*{*9m`mo$zPp+_yaC9|aw+ z_2I|m0jP)HmbEX?T!5heJ+gLI5XVh$fw2*Y=RkxGDIOuHkw4azdEWHh!U6^1PZySd zvaY;96aQpkfpz7l^5n1T{h*0j4oP;iFnxszSZt)PF_x;vy>cT8S zh6AY%B%2@AF=%RV4!Om}e>epSE7@@+19`oB4v=9fvqG{_mwP{$@^~la73hw6Zpro; z;YB2<1!!4R%VB$#JY&McM=m8SnW?MTQzX4AX=DLB*l;C-QF^fraVZCJ>7w1U^$Bl z*1vM2G|!E++g?XAH60ZItB75t3L(M5GVTR%>9+O?h!E%uYV2<2n zgoTGGJ{XReOTy)P&izJXz^%u&K8(kMO{i)?BM+qw=!5U%$=@xZ2%rc-y9^PWUqlDL zT0?K{^ICz(WzMl%6u1O@t%6*hP&azT%N&q-4SlET%kNZuiUdL+dT^>6S(|z6ZwLzd z06I_+)@vMlv}GARKoc&UM-U;?cLHYn!c`hh5<+4(W;^XAnG@ZX?g4Y}>PL*eC{L$1 zppMa==i?Rp?2r_3)>ad#Oh%;p`7(U=)$Lh4x`)SH>qvvq-5u%og&aWOc0;v3d@dMM zKaM`R(I*>nNw8!??0g4jifDxGwS01Z@b9{fHYAmbV40FSA&yMQ!KITPHK#31=vgdD;Bnhdv{za{@; zr~coTf`4zm{%Pl+Z}ZMkd?r}v@Nrz3WJ}_Z&T(L1vt)KmIQ@{`1TkY@PyFAC!|xb> zUk;&fhxlKe__41i{<(UB<1qdoIq}a2{ucuybmukq19JX(j$WPKPW;bLUYo@N6#lyt zKa{jAEM(#|ANY~~)QNvC9Kp*22>R!L|HMBZ_>s@{%D;Q!FDMjj3q19_@}`0lv$z+= z6?b5-k~xV2$%}Hw?Qz9$_OZHYcQ{9K`HqknwK@=n6U%11-Z@OSjjFvvc9eeU_LYob zz*jE>n}=`{DQCs=p+!;hu~?ZA=Q8Xd(ca`aXmOXrsz1nmL_g14V$I~CxHnh1A;3Kz z`lajBTS5%q0x0Go`b?#@-gL+|C=6NZ#~AvL6#DOu!IX1Woy2g?UDaJzOn4qBsCvP) z?0C+5M9}NC!#@UbX-q1-PAk0Wx?$AP$yUBUE@3VfgRl`S<61n;a-jWX-+5CJ$t7=H z^<9lL$uJ7ClwL+~Oq>Kk1(dB;g^#*1I^uC>aOP;y+#+j~Lj-6gx9{!-RckqQk0)3^ z+tiTt=kBJL=^aIyOL(Qoh4i}vqjS3DCJ?>b- z?i=?@*QpyDfb*SwvJ4C|OE$Z4;AQw})%p06(EF|GoZix#<|qfI3P6xrSu@Q0E%fLII_Xt0V(@!-GSrVmxbp& z58@wIqQs9URRoTzo~qitMjkLIr7ny{G!vgU}u-ayIN9#lI315`?w>^0mS+FNpB`{F9TnbOA7r{#U4 z^L<%xAZ4Ny)o&=tKy?P#rY?U#2&w#EB(wY z$FF$g8zP)lD2O!yoMO^)-QZdP;NfhScA>H3CY6jPm!Kd4qq-lc0U8_w&X8Hla^kXD zjaU9Aq8bwJkH?h1*?dAXDF_?dohuplbJ2+#(DpJq<6#|XHQaT3| z2Y?*?80sNRs=E|rqF_wCnC$6nkFqn|L6X||!YYUb{%7mhJI>O46nIC%)E~e-AQZw7 ze?Q)>V?}_ZJbudM`VNTjlJ_&?Dse7_%l`P-kiMv$Dr);N5|fa)^NEPzw1i76ol zqu7@Isq21HRzJTqW4@Ku|AB3B-WBI0+Fx#qP=|im(SE-z&buP=xh>lE0I1X%kIb;s z_~lLjb@XyLk`r_^!N4|NAhzRM^Y+Vr{&1?S0lK zBQO(%(3zMoqaW&fkQ$M6sHZL9AiDn=%ap9gT1Op+T_+mNn%mNX0)JhuR1it5%Mq) zCIhM9P8xE?AqX$K$J(i%f+Kdd2Pe2^a|Sj~c7jYK>~Vzd3P=>LZGRzhUg}qOmi+y~ ztDbtfjmy8tTi87R`oG?mU%su9|NAfQfB(-uZ2s$ib^rDM_K*Mif12mNwb1@)VP(1b z%<=dfX7Q#CmUmz!{cM;CB}(%{-TcZZn9G(|Z4xF%@Z5daU8Z5XULi@RWl>YzLKo6pcIpj+*ZwXv_|p27W+XiGHf92fduP?o z%HoM)W@$h%&fTFe0mRBTyEkaqx_~ZIqjQbq%cH(MX!$PZO(CslrhtG09888UcyW=A zbBh72;O{p=!p`Lf8#v@)e1X_QyzqD7OEyHYzE*b7B8{)3l@g)w^4PwHdKE-*)8wj5Z^2cqm~&1KNmLI!hhbF@Md=r>ip{ zOX1>AKBR`lDj$i);3eQp49H^1;=|S3We4=w>|A}{%EduJj|=X?EWw9BtYOd$OAtfv zBF7EGlhczWB4E_!Msyp8TvrLO%Yl$Z-9QINwAi@ZuFGXkhwJrpTVDM$AlZu?3!IyQ z??8xj&z@d;z3$IrZSbO;49Iz!PNsTy?OnV{7J7(xv75n}$9*n#yy0>SzUGLaZmwr> zb=lS+uQ)>3gHJfZh*F3Cwg8$a$ymVcsMbhxaz%1`Q5WRV)SC#RYM_%X<#M}%>R@_{ z_V~~Ve*qi=5cTgwQRGJl-E_P(<&sA4DqRiKZUXDIViOByz43o!ZG3BHOZ{?}4K8vG zhP|x=bb$goJt!A9^`6Q(xNaW&hL_gT?YyOQP=(3Meto9*t%-^y3>jqt#(x68#eJZ# zrsqrET78K4y=Diom2GO2UeNn0mc{JQaZlS=D6*olrJ{z#?sg=kq`I8${_5OuT^X!7 zQ@uvGQz#-ctONWk854~}@MK*F)!pe1eo^N5z}Cy@!6)esQVD82y*#SSj@nGd?u(1z z6m4QU*^)oq&)Q)>q1;_AqQ}jJd_c&=P(i(620D|m7Q~(?E~VUwJiPtg3I)C})M_Mi3v?m73Zcb^kamOSKc@i*Gt ztWE>1?)Mf3&0^S-LcP#?EXZgF$Ht7z2aHbu{%#SLp80nuT_Fn7xhrNjNFUKX^udA^ zID>ky1W#!S%QpOe=s;~;1}^@M+&NF{U&H#h7!YV7D^K;cJg1|&ei4*m?g+O*66nkS z&9#7*|K4GZfJST-3Nn6M6oJs;s4L&)Rw56S`y47#7k;ltkQhVqa>3pd`mOAR4JH5a z6(L_=(uZu~b1XW)m-(+8W8y1qnM~)fW$>CRPJnDs0xVs?F_c~WcEIJ$u?e2nK7k|! z2+fea+ggBT2}_#%?TFr4ULX13n&}mLUFBO60vGq@<*wQ1-0mCX;d0_`i9s?lEpDRH z_vwO3o{&?(oUSUdDP8lzI}1a;pHu9t+UN#nsQz)ZgU#LDDm!mXFV>3h57k2}5E`=6 z&0}0`JR0!7dU`mi%fz`=<}uSwgCbDJD-Gw-`<{8Q7v-!Ip1!!ik%K-;(IJu18>!dF z%HH~UULmKQINX*gHh^$!T@(bN5r7*y1&16QB;bhK7*T^AfO9x3TTMX&74qY~vz3H2CMs@_u%M{qcs{cTv!$ zARSH$_Xr4j;Vr0k2UOuME<4xD&1=8E`8+5Wob3j|_qXkNP4maAxZ+{Y328`b*R1UB z3=3n|K96IexVW_j6f4BIKvv#KlUw!*aCQH&y{^^}Uv1^$A=^`8j`X)lUx!wATbts+ z)b|(2RCI1M43U*i>IT%!?ovp+pkGG-oR5|?ROk z+JG5(n^HO|MC$VXtbO%rr;8SXX$!5~so|E|CU@X%*%x^6Wnua0+1mr@>grKDv|X)s z_hY=7oiAY5eU&f|4H;GIiAZ|;Dk9spkkbEgVq5Crg@h!v2gp?Il^leq>w^qWo`5%fLv zRVe=5=mKh`6PE)tbi)E!UGK3HdV z`$2SQhcb3glsEvMGAkaNUVfT%5N?Q$hOQdPpZvkFD#1MYX(DF9@h&t*ai znzN;q>ov#Ro&#gqmiPB*dTKWLiFU`LX3$+=Gh0c|ULpsbMNsPfA4b_=e zXC-kR)9iOcC!I@#zWDNDi_v)QvR#jr4{sAhhsUs2i{|-&`ep*yY_wAr5RBkk#1oya z2FlwM59WGM@_TeM%8$c1#?K3f*hbAw;*K!3z#cW=8Vm`I+i@TupM79SG}>sh32=^s zsEe*zq^6Ops#ew!o1U(9Zc-;P!5lj zyL)9=FxJ#mk5XOtH?!Y&4t^osBHV&w6|y7}Iwq$D#^D*#N}4nr=r~j_`lhsX1Itkh z7S3m^U?8=keHe4AE4x48*Z47b*8ub`#8m2|nO;S&jq*+}7uMc+9$E(xkB;MCqCN^# z{h^uHlY|A&;ZkMWpdMnAYO#3hQnF0U!Pc;I|%v$Ehw_KW^n<}Z#tZnFE%~9JHpt7vlAUA`&!73*K ztm`m)bKs!Qp}zI)i{O8h47fc6$sHsRLE_w(aIQIZ4`hk&Uw=QP`QRv;LdZUgb}n+W)OS0-%|g+QJCf~aBNLxsmP_PkMv zqyLY(H)(TIO}4h@`V}?Tbv^_VNDM*r0z{9*3`F0H9{u_^lxch0E_-`doiq6cRoj-8 znPjFE#1paBx?iCi5Vn~D-a0&}^3o&n!nt>diQvI5p)T9hgg}qOo@Gf}za4VqWOC^Q z(oF)A;|+BcbFWZRUc7dv|u%to6L?$rlfvKP;QUs_J< z{t)VUa4%lXwm;%H*2F{Aqe<6g`Qn?g4zDrx&fFdh#QmNKXkrsWJbI&TH=A_M`$1`( zsgc9MHf7nzc!p22;O@Am=WO3!9l!G+m}%+nU@EWk?)4;GKqgQdAJ40p9{j`j~< z88&MbcfK%;3Q;IY28RT`0o0wHFyL%YPM4NTZVzzO>p@FDIY}3U_DGjfJgSZ-HB=LG~a;e z)11fTa=+I<-4Bb8IoXQC=^p|{;RW=lX83q6hFWG#5=j&5rNZJG%pin9Wc9F{g%a0W6;7CJ z%ZZmxyw4C9SpZ`gLET3%C6vG4R7KGq6@2@!mM6;!kZ}#7*?NIYvKQ5HlV~}|{lU=? zeIK9dVyFW(ekCNZ;e}JVKW6tc-mF)Co*PX=HfJyrkSKitYDTVQ=XQSvj1AQdx^te_ z*y{UHsSJv`2Ka%W&KK8)-|oUu7o!>rd5vf`dsw&SoQ9yK-9)b#G78F+!Xc+_4EyYC zi-=G*%snLUQ?|Py6NkN5-13a*=wu5Cr)vClD{i;S%W3tIPwlP#^uT6LZ4Tb?Y}C=2 zbP7H{b4ohbD()wLt9X*evHKtM^0k!zv66#x8e+nTuSx^`?ME+anMPB zDclO0OUie9MgbnSA3fLp(XdlE+;@Ocux^$R$@o`dEI21hIOTzb2wt|J+w}L&O95O9 z>Dbl z0S5l)BSYaX2S3yAoIYRFfd7^g@;2|&l*oa{= zg@?QuP~g4gU`4>+${HFky;M05!n40Vw?@S8qPZ(>h(e zp8#LnqRzYbC-{JD16ca!PrQ47;Kvt+F9^>YDEkA`$_x?cdgJ|8qVcc*<`uh{Y725CTb->Op-l*&G{ofDBHekU&t_+^w z&-Ck!2>eTp@CKGU-|jzeV7Xj>zWv~yGjAU2X$C;~dp8x+XMGlP7>Cf1DIwk=s_M&z z=<^f^cRQFLndI}MAbfy{PCqP#HXH@bauMY?a4Y%#bkQ%5yM`eXal^K6Vi9zme*ugB z?z!-u{-7H%Zx!5^>@obOfN6MXaBx?Emk3KmC-z=)*X#@@2&syE8wO#tdFs?#W>~`7 zY*+)%By8z*O1@8B=V5gH5pp@s-3ir($BbRZB}B$;QamcGz{pd=S^YAnGjl&4lW~6D zg|t=kz*xLh-uQt-t&&lOh;$R(`|;H{)R3z=-;ua5Ee|17!eSX^h653~SIkP9NQEP} zF;I^YP-9o)YpX_tA`{2cMihhIgf~>gi2JsI66TXWn+5=molXI^yDmNzrF{h^^YxyT zWX^~np936n+rQ*&@DYz4uWR#M`)iSIl$Llt;gVDs^@-NlTuX7)0KlRi?!242cL*K> z2sc@|8M4G84htn2fU|AD$GG<8zI|Nf;l{qSuP z`s)N@n1BB1ZpbKaaY6bmDd9|Qe@%n~;N%aPjV8p2eQ(O$Fm?*cHXtTqI7BSb)0++s zWBcgK8ph&w|Mu^HA<9j-nS72n;YMdK;D?3vyag%7pMb9@JE}eVk8YfuHoD$8& zGPOJ8jm(Whz}DIej7QP4+xTO;>wBrZi3Acup6GM$^QKyU47k2q{4l>-{49S{ zy_h0!w97Huq+}T-_x@b5teArb4;!XYTE;VuwcL^RW$WN3r=v7a&eI+Hb_^n*?_tOK zk`Zpd6ffdv#!p$?A7Q1lDUbJYs2(+X@gxKSvb>ug=^646tJSv<$>*$Uc>oX0j?zH@ zt}O<>lIAWQ(ML%)nL>w5>SXg4m#Zk-h?Ks^+F9N$Kv@yDx5zT4luf{xr$F$r!PYo8 zlOi3ZtaiSH5GasZFz&{BRys#1cRrpZZ!)~?<#cNMjfFJEHMJe1*Hq!42C~hXM~AL; zLjghbXlKv%8Y}#=C1Q6lA5#f5y#u|^cE;QbJ1awE!f3qL5zR_#^EmjiO{NS}?%n%A zT7)~jTVWPURg>rbp?aCoW9*_2o$=d}dZy4{R<1u*t>E3Ml;4~N^lzpy_n#WxcfQNF z)dmb)vdw3{%i&jc_U{(T-z=%$!eO9ZS#M%6uql8X{Gl2)Kk&IQrg@8tKAfWvN&wC< z5c)DUrhXze0O0=PV+!|^Em z_gobP8G!R4e*WCn7!XebSNWR~_p1tr+#+BXtKA4muTB3{ZEywqDk3O*!idQQgq!A@X={EB^l4B6}b~Y!V{H zMhIXTVEC&yt|pF;k)JNkIS{$QHm)JTCKISktfYmkmOV=AC}-`w1u>JYjr1&b-rqa} zz3@ng-}zkCFS}WsA1fpVO1Q&AzH&zc3^|mIhxC5}@E!ts?}7 z4mz=$xV(D8nmG1un*jpMzvig_7^D8#@v)yx+&2u^ud`m^Aa*&Yn=9>A@-uXWm4DDv z6CQ&iTdbtQSX?_^R3r*AALwJ29`z{k(@N9r!_P!tmR^cGmgOZGyU; zyXAfb!BfB8$rUf5(2~I&i2*6-R@li&|4=!|0%f~n4tuW~Za*fNiiw?5_6L`!lkK64 z9D+Zz`sSKqBoi!0hoj`tzD$l!-4h=zt7yB$r4?C3x6=d34#>HDL2&7z0eFpGN)T#) zbgRmxGDwwjB#*f5(9H^=4r{%o5pap^kOvHrZ}IjTdZ2LM^irfx37bX&u#UeN*_18OCSDCv?Si|dm+tx*eKaQ>lZ#!&J74jgze?W86UQ} zs&1>C!IsPh(1D)~7{e-W1=)K-eTJE#%?^^He^~q8I!sXOcpo1C&;NPU0h8^+jrqj+ z>fmdF*pysfmGWaL4U1}^3%$NQHvjHQe!h?oIn{rBB@j*kN2#CuAuRXVuq7W2+xbJ( z54bu6zc_Gb=fh6#S1uJ-$OLxI&}FR_Qt)oT3eIuHy5J5=>QkEW!)@`evQPkjv_9_0 zWPtx))#It>Tx>hUdb&%m2Bt>?rQh7s5l-SIc~0~W_aRM*x+I-k+SdIbT#RKo-e~U@ zr6aR}Xb?iHZp=#;qW#ly8TonL4+VQnLsx7^P-S(&owj)7QzUdHh@O+(7S3hS>#V-27uc@u!R<)aqo{kR zahsyksH-`bt-*YL?!34{4!$qxI}mYRyEp)ykzOKZlN_`oUL%(2k_O}*3YL7m9-ZJa z*@y-iAu}DMmgt7L)?ycMu)^lx31WoPfg^)G_Dm~m;BJ<+SuWD@oOC;m9_vU0N+{;8 zkO+38@*1S%&iUFuC~YjN`yxCc^ZtS?S=bNZQGRt^IZchwUPczZiI^E<8^99>kTyl9 zk-D$FXK|WmL(umkeylg#1u zBsUlrF35wZ>~g~Q_I|))Z^|MFn8z1Pyxr!am;v+->o)VawOP;(0f(rcVTJdQUV+96 zH`XpV#vK!cdv2_INo+gqF1x|3HZgiZVN3^64U~U{=&ZN$?l&3YKcD$8{%dnE`_2r4 z+k@brrDoIkUM;Q5@^z3Get+gqe~MRZJ1xDegES1`3*z7H4GHcQkmV~KN6p6D5oPQW zn%M!fo5JbDfUrjjd~fV5&)+F(Vb=7WnF0cHoC1`3(Fhx@aNs+ zfqe1jg*5%SOoGD~bCs#V1b;>q>vNqP5RM$4$p$tjT2UUKt)Q$habx=e!o;Fki)=uc zT>^pe_VO?_$hCewr$cJ-uh%}A8cwyeRQ1!_e2pRJ<%AS3N!vvHoeAggPJlEg&X0No z9==mL0BvYImDhrZFdR~iFOf(X+!p$N_IQ?gSqR~<7PdPHaf0K~Jq`k@&Bf-Wn`4>S z4*GmuVfJ@9pIqXQ$w>mZJ^(sPr)Fn$zl1G=x_CPVaB_MM0ZHrzfU2;kbEy^?purPS4+HD9gHI3m5=wGhIk<84}80sAsy*lx=dp^?NzzrDN?!ST|l{euQt$sQ2%7CrtI{g3$q7iRNq zvV-k**CQ85l<#l^gH?%@zTqfv{@Z@#W4&^%VK=VkUHIg& zOPuJ_q!l4iNmJ&vt~z%f9KCXt+QcqII6Q%ucRi*6fVcJX;=_W23(srAq@diy!BdO;;zdyB(%PrDZ8&YL!%Y zJJ_*E!C9LTbT>Kx@B!BHUT>vBu<+43Ds-J1Zv9mmCnINP1xDd>&c!e@iir(*?~6t62lK2Tu^JMe_V zxTd6a!8Y{JZ)XjLo#UDr-1W~c1+R{@1=MbCij=Vs}f`$(QRjg zR_n`6IAQ4R&%2dxNtmBIZS9An8N86+!}w2Ypd~Y>Al~SOrf825HP6?Subvujw z{S=z~`Q+a`_k-;w7%aQtU_h1_bQ@IOq{G|l@#SqLS1A}oes~+vf2FfA(oV-CdAKS4 ze%`LgOd|6RMp>T1t}^1kZq-4@nYopZ(`h`VmHe_%ZU;eu`1#1teRFxX>%>nP+*i+g z^{I``s0)X<0|9>&_2Zd|ZyOQ0D)sRY_7Pu%;g}ps-R^_taq;y#nO+DGIY1UBi-OY| z8MYJ`mN6}G^}3aj;%GYAO|<41K;r%Jh;Jaf&w$Vm+NsYqD~S>Rf}p`C_TYPk)vmkq zJ-maLNR6*eyj~EFOSd-Jse<4fOwuO+g{D;)5BHMuYX<{&TV9nRB<@iFwD3KQ7iy^@ zUx1FaZow;qoa!8KnSeoutDPAt=2YW*V|L0#|s{6Ov{?95rb9?V!i*M>A8R8Z`1Ph{*TIb8Z zsd3-J_8FARAZ7gApbhNF$7;2{r1k;`S&sK4aC5Q;E4q@1^3}! z`Y9s*^WQdK{_%@k3Dz<%$aMP>i1BGE`RTEoRv^1^7Cy&UV9N*d2Tx{qcd=j%{YHFB z6U6s^-~l0E(u7a=O0x7FYj;f>%VP+_Z{&c?5jWOsWO*gOXGB% zWZZP4lB3VASr#F>gRu{H*kpoyG7^bdj+YCJRAWi$M{~<1NfD$rMAbkT;~c1Hv5O{D zz9?Ff@01Hc+|c74+Ata)U%izGk#fFr(q>n+a2O+_ZR<7rLs6Gj7SjMASRZ}m>gWs7 zaYVwrUz6p=AJI{UIL~A)s_LS7?G*{+^_&^Fhh6T@W54MH-QEjUavkwiUWvz+JVPFh zO;T52?rpR4g}|*AQWPJDSE%cU^W?+ zR22u=iQkebKhT1|s+*r32T<)l_LAR5THniBH{j%+%{|~;A@!&$P<>ln{S3A)dt*HP zzVy+uu1=JF>9#8cj49l+4ZAwRY=@F`e}$K-&tIs=Yptd#lq-S)%ScOg78wf*b9f>T zEW9MAkd5|v(m`l!Fe`1IE4cBvUU9j+1()u$VcVd$Pxk>o8=w_2@-4YoJ|DVTb3MFX zb~>NR2I-IfTwb3q34R|j4Ka|bv%j_X3*AgYcvLASq;p8r+XP`~U8Hb(!XB)U-fmgz zLvx5L5@9I(UVVj=eybj093{tG*0bT9&OP#4J4Zig#qEF*C-r6q$5hVH)8;NtjP9_O zi0`lDOX^CBZ>s3gE6a(vt~WC+nCo?2`A8{Kc`=FOFgO9ZWsiw1S;4Ns1R3C|k`5M* zZd0@oqlDFKc(j7ckn!J@K587AE(`q-Y#o0^5*WMQWXp9*J%Bb`1ZQrsW=xtf>>3u#1=+%E8(%H~C>R-X)Oi4p3 z$pk4I#T_E>JRXSL-`VLvU=F(+n)l!E?Hdh3a|k_nKL$4jxEV+W%IM z=JNdx$MG|_53;z&D>3EAlP{tNfmE=OVZbdMl0(Xf6u`vvwPP*pxvuFFUZnN_sdlaF zz{b#|&$!rY_yA2>ay4bdHgI0PDK+3-bzOP*J!#(#+J+{{oOWLAgd5XrR_9r^KqJo3 znmi8bu6?W%C#%V!cpecZ6=L$qF}psBd6^Uk_l^?hf^dBYgrT_)@on0R;6z1H7ep%Z z5J3;@fImzyjU0AJ74INv+}I%o^+I9zOOZ339}=GHuH;?}BzLt!+O(Sebzz=QVZ)vQ z^u9u3rX3GHlyJ6hLqxrIeJh?s1xatjDVd%$7Vm@dNI&_zrEKy2xYGzq%byqAueNx) zLT~4;;-)Pb(ytVm^c0t0Dy<(e7?xE!sk6#{DM;pZIEbfW%IB9sO~54$z3Wcgox0t& zI3dJz85FL*6=L%kZW|>qAFFg;Jp|%ETZKT__`bVku3~J7%e=%luNv-$(wELOklzsU zxg#p^38It{d;~SxTzsw0y4+`j{H`A+BQ3)h);h zR-nn^ONTw3k5pzm>DAN(erM)fWIwi&IFDa9(4h1J#S_?oJ`z^L&6oR;s8IL!Hu|lJ z`SnWXhrZu{J;m6m#(@H#Cgjsok3mp{4J7;(GUTAOpEtk+zQ`vfK;-Y=W@;j@L5%Q^ zI-^YeQD;Ns)LW00&=bWU-ts6=L7hOr1s?#9s}!~W&}+T_4mzy+Tc^d(pF%I51^E;;Q_MSo zl>#F<;DLToO+h^iRxmmw8?D;yA2*I5P+0!vU5_sOX!_LIOmHABM0^S(_q$IBcqG)cj^?Rf;@|jaYPHHn=t8aX3|bZMVUFX3uVBY#~BMyRSgn*@a`4y;zV}ZJ+Z#vUx1N# z+LM#6IUZT2sbx4zXuh_wAf#Da-Pbi-@=Hs1BE(PHsdO#Z`PoSrZ~^kQ!Gd5OEU zy;PmFyV4NN*~%Y|;yt)I31B)4a1+pa14kiRJFU;?9>TSaP!Kq>8bifzhQ`?RzIhTs zxI8s6G6HdA%k2_#Fk<|OHW7APIoQ`-pT$6gX(wIQo68zP=M;Bv0F>}!xvD&vlz=Fp zT>#8>fz29{J>cMePPo^rBl2;6JpFvMTltoHA}L=$NxGVghsB*BViRLhDnGUvE>j~N z4@beXNK>bC83Y0ZJDi+{A8wzDJz_2wRJg|0hl?g*&fm2;;w!4#=>K~()pvc%pBfSF z^d9t()z?M@7?9m|x zf~ts9ps7E6e`W)_=Q|M>pFQ(q0{<23_09o!0TNz$2LT*D&TOy8$Ah42Sb;?dEXN!DpvrL&L_ zq#xqe>+#fkL(QV11sm8?s3nQIY#@2!x`YX!VSpfhWdY^eTpk0KSH{gx{EI+>HAAW+ z$-V4dVqRAm4!?qGA4GLZ6M6>cAwrO=y8%1^d$WD5;iEsF&XVe(!4(Ccd9I($FcN_idrBby1`ht`-n``6xcHU@bhP#8u#UQApkgjRL zPA{v5cZFm6JKe7I;EY-zIi7l*Sxc-K4=9lHQb&Iap$|<#567UAas~m!dB^6E_%w)!U50 zLyZB>>XwWR{3dM$CEX+F=rhL%!nGjG(oftY8x~9GCzN4K465G z_|Q%JF3n)&=v5^3#*zdz47%T0V}J@TtTT*0IUw79<8W^`KfS5nNvDiy-xJ+}p~njl zBl&%n9SM3*DVIyH{XCVhz%=1rA(%@eh&zOt3{qhrFPi?G*B8pQ;4qJ8 z-+p#D0HE)E-3~t4`lez9KudprLLdf%XC1~#79i$efCHZp(n8L(3u$}rlST@mqUi&o zt^Hf`J5$o%@+USleTSB1_waP0Ic3gqkOU2v`33J#C*)_C3;c4z34IxTXp9Zd?04AmbqMHwC+P1<-7cwg@R@$i0uBSut`+;NyfpSI;G@N1rWgMT7xe&bn7; z*q)4e+`F^X0laR$OV=@&@TogJH>rhC`b8n!c=62F+(_yOs1SE#?inH18Z|kYfWy#| zK#wEX`LpWL19MqV!O`7M)vm%*uvlj2$bhK8O@fxQ%-r1Wb>9uj?zm+x&2g(9vUpSt z^X1oay4C3=#a~1QnjiVp1Itdnw+N!G5mChQ^K3cm6s5X`Z+t73>pFeXfyF7eOgakB zI*oWdg5ZxS#qm@j;s=F$b8e5txmmCX5Znb&u+wXxQg{{Zs?L*Q-RM<(Q{Ny`knrKO z>yswGze7~SOfZmD7=j`0ss$@0KVuC$W4#pExeG(1=P>53B@&O=RClP+W-H6*MQaIX zDBH=%-&uWiXcW1&KGz=%bbFj^5rD?=3DIkXD_PCS^W{oejn^6^Z`HAWi(D|7^8x}7 zq-th$q1OQXAzMMx0bJ9_h*7f`8fshn$_bK5pstz;s>}xoHU@M{WTslT^@%t?7~iV$ zDK0Z1cY}w5we0?+q29*ruHMR*y}sUQ)m0Pc4nvjtb{~t*1FzP&2a}W>vIo>T3}-wg zwdw_ibst_6UxnMho*ti5FzG`^>%W@#U+1Q(qV5rWE)4(YU$8Iy^Q7cYeTZPeJejt> z&6DBosKI-ID0=_s|NK^aFXo|){hV*lITptNaORu!m9QYt=sk9TKqGJ#*~xwHtRPGr zAps-xcw_Z$&`|J@Ng;fA;PbnSf~oLxNb;_MAQvFNJrPom%y-i8TeU(a-#6%mx^+BwAl-=KD|fZh$`ekc&mtU-ps~3^y8hQUKFi4jRFdhTd(jLPE%uc`Q8SwS0cdjm3iC1isDhKUre0I1Se0Ryluiso^dH z^Pv=;BLQ=;RsfI%Hx~#idtbpFfLWgjwGdJAfk61@^B}klo+nBfAhdd<+@c`@A+uv& zMfeoK)X*idQ?D9=2>r-Kx4SmKuIW7>+*jb4)rmw4hPz?p7_Sh7Pi<}^mo44BJ>0qe z)FEYTNl)iOt$>8u3Ww>Yxo18#jp+bCfbexl%G^%-ElSO0y0e}&UA_Tk zF~2)vIx}9p#u#~K01i*r%XbGXK@%Urhz4i_h%O|1t+FUmPz;XcvK}3@2HgTpNCyf5 zgxlbWifo{?mX@2MV^qNb=iohJz**zVaHk7-ds@RVToI|qv|^v&(M^pc{dl=u2hb+P zvd415qrG;vqIKt+S8RX@j1T*}an@1Hc$jUMqtEW>ke<1

            gPM!aBv{1>@CPuXea^ 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 xFh)1M4-GkjMW1)Y%)Y&8L+=E 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 Date: Wed, 16 Mar 2016 18:49:58 +0100 Subject: [PATCH 050/113] load filter of section correctly for libnetconf2 --- .../Resources/views/layout.html.twig | 2 +- .../Functionality/ConnectionFunctionality.php | 90 ++++++++----------- 2 files changed, 37 insertions(+), 55 deletions(-) diff --git a/src/FIT/NetopeerBundle/Resources/views/layout.html.twig b/src/FIT/NetopeerBundle/Resources/views/layout.html.twig index a66ab72f..d713af57 100644 --- a/src/FIT/NetopeerBundle/Resources/views/layout.html.twig +++ b/src/FIT/NetopeerBundle/Resources/views/layout.html.twig @@ -95,7 +95,7 @@ if advised of the possibility of such damage. {% if topmenu is defined %} {% set i = 0 %} {% for section in topmenu %} - {{section.name}} + {{section.name}} {% set i = i + 1 %} {% endfor %} All diff --git a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php index 424d82a6..95f18df1 100644 --- a/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php +++ b/src/FIT/NetopeerBundle/Services/Functionality/ConnectionFunctionality.php @@ -231,11 +231,11 @@ public function getModuleIdentifiersForCurrentDevice($key) { $arr[$matches[1]] = array( 'ns' => $matches[1], 'moduleName' => $matches[2], + 'rootElementName' => '*', 'revision' => $matches[3], ); } } - $this->moduleIdentifiers = $arr; return $arr; } @@ -250,37 +250,17 @@ public function getModuleIdentifiersForCurrentDevice($key) { * * @return array */ - public function getRootNamesForModuleIdentifiers($key, array $identifiers) { + public function setRootNamesForModuleIdentifiers($key, array $rootElements) { $newArr = array(); - foreach ($identifiers as $ns => $ident) { - $ident['rootElem'] = $this->getRootNameForNS($key, $ident['ns']); + foreach ($this->getModuleIdentifiersForCurrentDevice($key) as $ns => $ident) { + if (isset($rootElements[$ident['moduleName']])) { + $ident['rootElementName'] = $rootElements[$ident['moduleName']]; + } $newArr[$ns] = $ident; } - return $newArr; } - /** - * Get name of root element for module NS - * - * @param $key Identifier of connection (connected device ID) - * @param $ns - * - * @return string - */ - public function getRootNameForNS($key, $ns) { - $path = $this->getModelsDir().$this->getModulePathByNS($key, $ns); - $file = $path . '/filter.txt'; - $rootElem = ""; - if ( file_exists($file) ) { - $dom = new \DomDocument; - $dom->load($file); - $rootElem = $dom->documentElement->tagName; - } - - return $rootElem; - } - /** * Find instance of SessionConnection.class for key. * @@ -478,15 +458,19 @@ public function buildMenuStructure($key, $path = "") { $netconfFunc = $this->getContainer()->get('fitnetopeerbundle.service.netconf.functionality'); $json = json_decode($netconfFunc->handle('get', array('connIds' => array($key))), true); - $modifiedJson = array(); + $modifiedJson = $elemNames = array(); foreach ($json as $name => $val) { + $names = explode(':', $name); + if (sizeof($names) > 1) { + $elemNames[$names[0]] = $names[1]; + } $newKey = substr($name, 0, strpos($name, ':')); $modifiedJson[$newKey] = array($name => $val); } if ($this->getModuleIdentifiersForCurrentDevice($key)) { - foreach ( $this->getModuleIdentifiersForCurrentDevice( $key ) as $ns => $values ) { - + $identifiers = $this->setRootNamesForModuleIdentifiers($key, $elemNames); + foreach ( $identifiers as $ns => $values ) { $i = 0; $moduleName = $values['moduleName']; @@ -495,20 +479,23 @@ public function buildMenuStructure($key, $path = "") { } else { $configuration = array(); } - - $models[ $moduleName ] = array( - 'path' => "module", - "params" => array( - 'key' => $key, - 'module' => $moduleName, - ), - "title" => "detail of " . $this->getSectionName( $moduleName ), - "name" => $this->getSectionName( $moduleName ), - "children" => $this->buildSubmenu( $key, $moduleName, $configuration ), - "namespace" => $ns, - "version" => $values['revision'], - ); - $namespaces[ $moduleName ] = $ns; + if ($values["rootElementName"] !== "*") { + $models[$moduleName] = array( + 'path' => "module", + "params" => array( + 'key' => $key, + 'module' => $moduleName, + ), + "title" => "detail of " . $this->getSectionName($moduleName), + "name" => $this->getSectionName($values["rootElementName"]), + "children" => $this->buildSubmenu($key, $moduleName, $configuration), + "namespace" => $ns, + "moduleName" => $moduleName, + "rootElementName" => $values["rootElementName"], + "version" => $values['revision'], + ); + } + $namespaces[ $moduleName ] = $values; } } else { $this->getLogger()->addError("Could not build MenuStructure", array('key' => $key)); @@ -564,19 +551,14 @@ private function buildSubmenu($key, $module, $configuration) { * @param string $subsection subsection name * @return array array with config and state filter */ - public function loadFilters(&$module, &$subsection) { + public function loadFilters($module, $subsection) { $filterState = $filterConfig = ""; $namespaces = $this->getModelNamespaces($this->getContainer()->get('request')->get('key')); if (isset($namespaces[$module])) { - $namespace = $namespaces[$module]; - $filter = new \SimpleXMLElement("<".$module.">"); - $filter->addAttribute('xmlns', $namespace); - if ( $subsection ) { - $filter->addChild($subsection); - } - - $filterState = $filterConfig = str_replace('', '', trim($filter->asXml())); + $module = $namespaces[$module]; +// $filterState = $filterConfig = '/'.$module['moduleName'].':'.$module['rootElementName']; + $filterState = $filterConfig = '<'.$module['rootElementName'].' xmlns="'.$module['ns'].'" />"'; } return array( @@ -636,8 +618,8 @@ public function getModelNamespaces($key) { */ public function getNamespaceForModule($key, $module) { $namespaces = $this->getModelNamespaces($key); - if (isset($namespaces[$module])) { - return $namespaces[$module]; + if (isset($namespaces[$module]) && isset($namespaces[$module]['ns'])) { + return $namespaces[$module]['ns']; } else { return false; } From fe31fc0437ea3f1a62664cbfb60f828093c1825c Mon Sep 17 00:00:00 2001 From: david alexa Date: Tue, 22 Mar 2016 09:46:54 +0100 Subject: [PATCH 051/113] bower and node dependencies are versioned (we do not want to run bower or npm install for netopeergui instalation) --- .../ui-bootstrap-tpls.min.js | 12 + .../angular-bootstrap/ui-bootstrap.min.js | 11 + .../angular-ui-sortable/sortable.min.js | 1 + bower_components/angular/angular.min.js | 309 ++++++++++++++ bower_components/jquery-ui/jquery-ui.min.js | 13 + bower_components/ngTraverse/ngTraverse.js | 392 ++++++++++++++++++ node_modules/rhaboo/rhaboo.min.js | 1 + 7 files changed, 739 insertions(+) create mode 100644 bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js create mode 100644 bower_components/angular-bootstrap/ui-bootstrap.min.js create mode 100644 bower_components/angular-ui-sortable/sortable.min.js create mode 100644 bower_components/angular/angular.min.js create mode 100644 bower_components/jquery-ui/jquery-ui.min.js create mode 100644 bower_components/ngTraverse/ngTraverse.js create mode 100644 node_modules/rhaboo/rhaboo.min.js diff --git a/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js b/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js new file mode 100644 index 00000000..f729eda6 --- /dev/null +++ b/bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js @@ -0,0 +1,12 @@ +/* + * angular-ui-bootstrap + * http://angular-ui.github.io/bootstrap/ + + * Version: 0.14.3 - 2015-10-23 + * License: MIT + */ +angular.module("ui.bootstrap",["ui.bootstrap.tpls","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.stackedMap","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]),angular.module("ui.bootstrap.tpls",["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-popup.html","template/tooltip/tooltip-popup.html","template/tooltip/tooltip-template-popup.html","template/popover/popover-html.html","template/popover/popover-template.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]),angular.module("ui.bootstrap.collapse",[]).directive("uibCollapse",["$animate","$injector",function(a,b){var c=b.has("$animateCss")?b.get("$animateCss"):null;return{link:function(b,d,e){function f(){d.removeClass("collapse").addClass("collapsing").attr("aria-expanded",!0).attr("aria-hidden",!1),c?c(d,{addClass:"in",easing:"ease",to:{height:d[0].scrollHeight+"px"}}).start()["finally"](g):a.addClass(d,"in",{to:{height:d[0].scrollHeight+"px"}}).then(g)}function g(){d.removeClass("collapsing").addClass("collapse").css({height:"auto"})}function h(){return d.hasClass("collapse")||d.hasClass("in")?(d.css({height:d[0].scrollHeight+"px"}).removeClass("collapse").addClass("collapsing").attr("aria-expanded",!1).attr("aria-hidden",!0),void(c?c(d,{removeClass:"in",to:{height:"0"}}).start()["finally"](i):a.removeClass(d,"in",{to:{height:"0"}}).then(i))):i()}function i(){d.css({height:"0"}),d.removeClass("collapsing").addClass("collapse")}b.$watch(e.uibCollapse,function(a){a?h():f()})}}}]),angular.module("ui.bootstrap.collapse").value("$collapseSuppressWarning",!1).directive("collapse",["$animate","$injector","$log","$collapseSuppressWarning",function(a,b,c,d){var e=b.has("$animateCss")?b.get("$animateCss"):null;return{link:function(b,f,g){function h(){f.removeClass("collapse").addClass("collapsing").attr("aria-expanded",!0).attr("aria-hidden",!1),e?e(f,{easing:"ease",to:{height:f[0].scrollHeight+"px"}}).start().done(i):a.animate(f,{},{height:f[0].scrollHeight+"px"}).then(i)}function i(){f.removeClass("collapsing").addClass("collapse in").css({height:"auto"})}function j(){return f.hasClass("collapse")||f.hasClass("in")?(f.css({height:f[0].scrollHeight+"px"}).removeClass("collapse in").addClass("collapsing").attr("aria-expanded",!1).attr("aria-hidden",!0),void(e?e(f,{to:{height:"0"}}).start().done(k):a.animate(f,{},{height:"0"}).then(k))):k()}function k(){f.css({height:"0"}),f.removeClass("collapsing").addClass("collapse")}d||c.warn("collapse is now deprecated. Use uib-collapse instead."),b.$watch(g.collapse,function(a){a?j():h()})}}}]),angular.module("ui.bootstrap.accordion",["ui.bootstrap.collapse"]).constant("uibAccordionConfig",{closeOthers:!0}).controller("UibAccordionController",["$scope","$attrs","uibAccordionConfig",function(a,b,c){this.groups=[],this.closeOthers=function(d){var e=angular.isDefined(b.closeOthers)?a.$eval(b.closeOthers):c.closeOthers;e&&angular.forEach(this.groups,function(a){a!==d&&(a.isOpen=!1)})},this.addGroup=function(a){var b=this;this.groups.push(a),a.$on("$destroy",function(c){b.removeGroup(a)})},this.removeGroup=function(a){var b=this.groups.indexOf(a);-1!==b&&this.groups.splice(b,1)}}]).directive("uibAccordion",function(){return{controller:"UibAccordionController",controllerAs:"accordion",transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion.html"}}}).directive("uibAccordionGroup",function(){return{require:"^uibAccordion",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion-group.html"},scope:{heading:"@",isOpen:"=?",isDisabled:"=?"},controller:function(){this.setHeading=function(a){this.heading=a}},link:function(a,b,c,d){d.addGroup(a),a.openClass=c.openClass||"panel-open",a.panelClass=c.panelClass,a.$watch("isOpen",function(c){b.toggleClass(a.openClass,!!c),c&&d.closeOthers(a)}),a.toggleOpen=function(b){a.isDisabled||b&&32!==b.which||(a.isOpen=!a.isOpen)}}}}).directive("uibAccordionHeading",function(){return{transclude:!0,template:"",replace:!0,require:"^uibAccordionGroup",link:function(a,b,c,d,e){d.setHeading(e(a,angular.noop))}}}).directive("uibAccordionTransclude",function(){return{require:["?^uibAccordionGroup","?^accordionGroup"],link:function(a,b,c,d){d=d[0]?d[0]:d[1],a.$watch(function(){return d[c.uibAccordionTransclude]},function(a){a&&(b.find("span").html(""),b.find("span").append(a))})}}}),angular.module("ui.bootstrap.accordion").value("$accordionSuppressWarning",!1).controller("AccordionController",["$scope","$attrs","$controller","$log","$accordionSuppressWarning",function(a,b,c,d,e){e||d.warn("AccordionController is now deprecated. Use UibAccordionController instead."),angular.extend(this,c("UibAccordionController",{$scope:a,$attrs:b}))}]).directive("accordion",["$log","$accordionSuppressWarning",function(a,b){return{restrict:"EA",controller:"AccordionController",controllerAs:"accordion",transclude:!0,replace:!1,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion.html"},link:function(){b||a.warn("accordion is now deprecated. Use uib-accordion instead.")}}}]).directive("accordionGroup",["$log","$accordionSuppressWarning",function(a,b){return{require:"^accordion",restrict:"EA",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion-group.html"},scope:{heading:"@",isOpen:"=?",isDisabled:"=?"},controller:function(){this.setHeading=function(a){this.heading=a}},link:function(c,d,e,f){b||a.warn("accordion-group is now deprecated. Use uib-accordion-group instead."),f.addGroup(c),c.openClass=e.openClass||"panel-open",c.panelClass=e.panelClass,c.$watch("isOpen",function(a){d.toggleClass(c.openClass,!!a),a&&f.closeOthers(c)}),c.toggleOpen=function(a){c.isDisabled||a&&32!==a.which||(c.isOpen=!c.isOpen)}}}}]).directive("accordionHeading",["$log","$accordionSuppressWarning",function(a,b){return{restrict:"EA",transclude:!0,template:"",replace:!0,require:"^accordionGroup",link:function(c,d,e,f,g){b||a.warn("accordion-heading is now deprecated. Use uib-accordion-heading instead."),f.setHeading(g(c,angular.noop))}}}]).directive("accordionTransclude",["$log","$accordionSuppressWarning",function(a,b){return{require:"^accordionGroup",link:function(c,d,e,f){b||a.warn("accordion-transclude is now deprecated. Use uib-accordion-transclude instead."),c.$watch(function(){return f[e.accordionTransclude]},function(a){a&&(d.find("span").html(""),d.find("span").append(a))})}}}]),angular.module("ui.bootstrap.alert",[]).controller("UibAlertController",["$scope","$attrs","$interpolate","$timeout",function(a,b,c,d){a.closeable=!!b.close;var e=angular.isDefined(b.dismissOnTimeout)?c(b.dismissOnTimeout)(a.$parent):null;e&&d(function(){a.close()},parseInt(e,10))}]).directive("uibAlert",function(){return{controller:"UibAlertController",controllerAs:"alert",templateUrl:function(a,b){return b.templateUrl||"template/alert/alert.html"},transclude:!0,replace:!0,scope:{type:"@",close:"&"}}}),angular.module("ui.bootstrap.alert").value("$alertSuppressWarning",!1).controller("AlertController",["$scope","$attrs","$controller","$log","$alertSuppressWarning",function(a,b,c,d,e){e||d.warn("AlertController is now deprecated. Use UibAlertController instead."),angular.extend(this,c("UibAlertController",{$scope:a,$attrs:b}))}]).directive("alert",["$log","$alertSuppressWarning",function(a,b){return{controller:"AlertController",controllerAs:"alert",templateUrl:function(a,b){return b.templateUrl||"template/alert/alert.html"},transclude:!0,replace:!0,scope:{type:"@",close:"&"},link:function(){b||a.warn("alert is now deprecated. Use uib-alert instead.")}}}]),angular.module("ui.bootstrap.buttons",[]).constant("uibButtonConfig",{activeClass:"active",toggleEvent:"click"}).controller("UibButtonsController",["uibButtonConfig",function(a){this.activeClass=a.activeClass||"active",this.toggleEvent=a.toggleEvent||"click"}]).directive("uibBtnRadio",function(){return{require:["uibBtnRadio","ngModel"],controller:"UibButtonsController",controllerAs:"buttons",link:function(a,b,c,d){var e=d[0],f=d[1];b.find("input").css({display:"none"}),f.$render=function(){b.toggleClass(e.activeClass,angular.equals(f.$modelValue,a.$eval(c.uibBtnRadio)))},b.on(e.toggleEvent,function(){if(!c.disabled){var d=b.hasClass(e.activeClass);(!d||angular.isDefined(c.uncheckable))&&a.$apply(function(){f.$setViewValue(d?null:a.$eval(c.uibBtnRadio)),f.$render()})}})}}}).directive("uibBtnCheckbox",function(){return{require:["uibBtnCheckbox","ngModel"],controller:"UibButtonsController",controllerAs:"button",link:function(a,b,c,d){function e(){return g(c.btnCheckboxTrue,!0)}function f(){return g(c.btnCheckboxFalse,!1)}function g(b,c){return angular.isDefined(b)?a.$eval(b):c}var h=d[0],i=d[1];b.find("input").css({display:"none"}),i.$render=function(){b.toggleClass(h.activeClass,angular.equals(i.$modelValue,e()))},b.on(h.toggleEvent,function(){c.disabled||a.$apply(function(){i.$setViewValue(b.hasClass(h.activeClass)?f():e()),i.$render()})})}}}),angular.module("ui.bootstrap.buttons").value("$buttonsSuppressWarning",!1).controller("ButtonsController",["$controller","$log","$buttonsSuppressWarning",function(a,b,c){c||b.warn("ButtonsController is now deprecated. Use UibButtonsController instead."),angular.extend(this,a("UibButtonsController"))}]).directive("btnRadio",["$log","$buttonsSuppressWarning",function(a,b){return{require:["btnRadio","ngModel"],controller:"ButtonsController",controllerAs:"buttons",link:function(c,d,e,f){b||a.warn("btn-radio is now deprecated. Use uib-btn-radio instead.");var g=f[0],h=f[1];d.find("input").css({display:"none"}),h.$render=function(){d.toggleClass(g.activeClass,angular.equals(h.$modelValue,c.$eval(e.btnRadio)))},d.bind(g.toggleEvent,function(){if(!e.disabled){var a=d.hasClass(g.activeClass);(!a||angular.isDefined(e.uncheckable))&&c.$apply(function(){h.$setViewValue(a?null:c.$eval(e.btnRadio)),h.$render()})}})}}}]).directive("btnCheckbox",["$document","$log","$buttonsSuppressWarning",function(a,b,c){return{require:["btnCheckbox","ngModel"],controller:"ButtonsController",controllerAs:"button",link:function(d,e,f,g){function h(){return j(f.btnCheckboxTrue,!0)}function i(){return j(f.btnCheckboxFalse,!1)}function j(a,b){var c=d.$eval(a);return angular.isDefined(c)?c:b}c||b.warn("btn-checkbox is now deprecated. Use uib-btn-checkbox instead.");var k=g[0],l=g[1];e.find("input").css({display:"none"}),l.$render=function(){e.toggleClass(k.activeClass,angular.equals(l.$modelValue,h()))},e.bind(k.toggleEvent,function(){f.disabled||d.$apply(function(){l.$setViewValue(e.hasClass(k.activeClass)?i():h()),l.$render()})}),e.on("keypress",function(b){f.disabled||32!==b.which||a[0].activeElement!==e[0]||d.$apply(function(){l.$setViewValue(e.hasClass(k.activeClass)?i():h()),l.$render()})})}}}]),angular.module("ui.bootstrap.carousel",[]).controller("UibCarouselController",["$scope","$element","$interval","$animate",function(a,b,c,d){function e(b,c,e){s||(angular.extend(b,{direction:e,active:!0}),angular.extend(m.currentSlide||{},{direction:e,active:!1}),d.enabled()&&!a.noTransition&&!a.$currentTransition&&b.$element&&m.slides.length>1&&(b.$element.data(q,b.direction),m.currentSlide&&m.currentSlide.$element&&m.currentSlide.$element.data(q,b.direction),a.$currentTransition=!0,o?d.on("addClass",b.$element,function(b,c){"close"===c&&(a.$currentTransition=null,d.off("addClass",b))}):b.$element.one("$animate:close",function(){a.$currentTransition=null})),m.currentSlide=b,r=c,g())}function f(a){if(angular.isUndefined(n[a].index))return n[a];var b;n.length;for(b=0;b0&&(k=c(i,b))}function h(){k&&(c.cancel(k),k=null)}function i(){var b=+a.interval;l&&!isNaN(b)&&b>0&&n.length?a.next():a.pause()}function j(b){b.length||(a.$currentTransition=null)}var k,l,m=this,n=m.slides=a.slides=[],o=angular.version.minor>=4,p="uib-noTransition",q="uib-slideDirection",r=-1;m.currentSlide=null;var s=!1;m.select=a.select=function(b,c){var d=a.indexOfSlide(b);void 0===c&&(c=d>m.getCurrentIndex()?"next":"prev"),b&&b!==m.currentSlide&&!a.$currentTransition&&e(b,d,c)},a.$on("$destroy",function(){s=!0}),m.getCurrentIndex=function(){return m.currentSlide&&angular.isDefined(m.currentSlide.index)?+m.currentSlide.index:r},a.indexOfSlide=function(a){return angular.isDefined(a.index)?+a.index:n.indexOf(a)},a.next=function(){var b=(m.getCurrentIndex()+1)%n.length;return 0===b&&a.noWrap()?void a.pause():m.select(f(b),"next")},a.prev=function(){var b=m.getCurrentIndex()-1<0?n.length-1:m.getCurrentIndex()-1;return a.noWrap()&&b===n.length-1?void a.pause():m.select(f(b),"prev")},a.isActive=function(a){return m.currentSlide===a},a.$watch("interval",g),a.$watchCollection("slides",j),a.$on("$destroy",h),a.play=function(){l||(l=!0,g())},a.pause=function(){a.noPause||(l=!1,h())},m.addSlide=function(b,c){b.$element=c,n.push(b),1===n.length||b.active?(m.select(n[n.length-1]),1===n.length&&a.play()):b.active=!1},m.removeSlide=function(a){angular.isDefined(a.index)&&n.sort(function(a,b){return+a.index>+b.index});var b=n.indexOf(a);n.splice(b,1),n.length>0&&a.active?b>=n.length?m.select(n[b-1]):m.select(n[b]):r>b&&r--,0===n.length&&(m.currentSlide=null)},a.$watch("noTransition",function(a){b.data(p,a)})}]).directive("uibCarousel",[function(){return{transclude:!0,replace:!0,controller:"UibCarouselController",controllerAs:"carousel",require:"carousel",templateUrl:function(a,b){return b.templateUrl||"template/carousel/carousel.html"},scope:{interval:"=",noTransition:"=",noPause:"=",noWrap:"&"}}}]).directive("uibSlide",function(){return{require:"^uibCarousel",restrict:"EA",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/carousel/slide.html"},scope:{active:"=?",actual:"=?",index:"=?"},link:function(a,b,c,d){d.addSlide(a,b),a.$on("$destroy",function(){d.removeSlide(a)}),a.$watch("active",function(b){b&&d.select(a)})}}}).animation(".item",["$injector","$animate",function(a,b){function c(a,b,c){a.removeClass(b),c&&c()}var d="uib-noTransition",e="uib-slideDirection",f=null;return a.has("$animateCss")&&(f=a.get("$animateCss")),{beforeAddClass:function(a,g,h){if("active"==g&&a.parent()&&a.parent().parent()&&!a.parent().parent().data(d)){var i=!1,j=a.data(e),k="next"==j?"left":"right",l=c.bind(this,a,k+" "+j,h);return a.addClass(j),f?f(a,{addClass:k}).start().done(l):b.addClass(a,k).then(function(){i||l(),h()}),function(){i=!0}}h()},beforeRemoveClass:function(a,g,h){if("active"===g&&a.parent()&&a.parent().parent()&&!a.parent().parent().data(d)){var i=!1,j=a.data(e),k="next"==j?"left":"right",l=c.bind(this,a,k,h);return f?f(a,{addClass:k}).start().done(l):b.addClass(a,k).then(function(){i||l(),h()}),function(){i=!0}}h()}}}]),angular.module("ui.bootstrap.carousel").value("$carouselSuppressWarning",!1).controller("CarouselController",["$scope","$element","$controller","$log","$carouselSuppressWarning",function(a,b,c,d,e){e||d.warn("CarouselController is now deprecated. Use UibCarouselController instead."),angular.extend(this,c("UibCarouselController",{$scope:a,$element:b}))}]).directive("carousel",["$log","$carouselSuppressWarning",function(a,b){return{transclude:!0,replace:!0,controller:"CarouselController",controllerAs:"carousel",require:"carousel",templateUrl:function(a,b){return b.templateUrl||"template/carousel/carousel.html"},scope:{interval:"=",noTransition:"=",noPause:"=",noWrap:"&"},link:function(){b||a.warn("carousel is now deprecated. Use uib-carousel instead.")}}}]).directive("slide",["$log","$carouselSuppressWarning",function(a,b){return{require:"^carousel",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/carousel/slide.html"},scope:{active:"=?",actual:"=?",index:"=?"},link:function(c,d,e,f){b||a.warn("slide is now deprecated. Use uib-slide instead."),f.addSlide(c,d),c.$on("$destroy",function(){f.removeSlide(c)}),c.$watch("active",function(a){a&&f.select(c)})}}}]),angular.module("ui.bootstrap.dateparser",[]).service("uibDateParser",["$log","$locale","orderByFilter",function(a,b,c){function d(a){var b=[],d=a.split("");return angular.forEach(g,function(c,e){var f=a.indexOf(e);if(f>-1){a=a.split(""),d[f]="("+c.regex+")",a[f]="$";for(var g=f+1,h=f+e.length;h>g;g++)d[g]="",a[g]="$";a=a.join(""),b.push({index:f,apply:c.apply})}}),{regex:new RegExp("^"+d.join("")+"$"),map:c(b,"index")}}function e(a,b,c){return 1>c?!1:1===b&&c>28?29===c&&(a%4===0&&a%100!==0||a%400===0):3===b||5===b||8===b||10===b?31>c:!0}var f,g,h=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;this.init=function(){f=b.id,this.parsers={},g={yyyy:{regex:"\\d{4}",apply:function(a){this.year=+a}},yy:{regex:"\\d{2}",apply:function(a){this.year=+a+2e3}},y:{regex:"\\d{1,4}",apply:function(a){this.year=+a}},MMMM:{regex:b.DATETIME_FORMATS.MONTH.join("|"),apply:function(a){this.month=b.DATETIME_FORMATS.MONTH.indexOf(a)}},MMM:{regex:b.DATETIME_FORMATS.SHORTMONTH.join("|"),apply:function(a){this.month=b.DATETIME_FORMATS.SHORTMONTH.indexOf(a)}},MM:{regex:"0[1-9]|1[0-2]",apply:function(a){this.month=a-1}},M:{regex:"[1-9]|1[0-2]",apply:function(a){this.month=a-1}},dd:{regex:"[0-2][0-9]{1}|3[0-1]{1}",apply:function(a){this.date=+a}},d:{regex:"[1-2]?[0-9]{1}|3[0-1]{1}",apply:function(a){this.date=+a}},EEEE:{regex:b.DATETIME_FORMATS.DAY.join("|")},EEE:{regex:b.DATETIME_FORMATS.SHORTDAY.join("|")},HH:{regex:"(?:0|1)[0-9]|2[0-3]",apply:function(a){this.hours=+a}},hh:{regex:"0[0-9]|1[0-2]",apply:function(a){this.hours=+a}},H:{regex:"1?[0-9]|2[0-3]",apply:function(a){this.hours=+a}},h:{regex:"[0-9]|1[0-2]",apply:function(a){this.hours=+a}},mm:{regex:"[0-5][0-9]",apply:function(a){this.minutes=+a}},m:{regex:"[0-9]|[1-5][0-9]",apply:function(a){this.minutes=+a}},sss:{regex:"[0-9][0-9][0-9]",apply:function(a){this.milliseconds=+a}},ss:{regex:"[0-5][0-9]",apply:function(a){this.seconds=+a}},s:{regex:"[0-9]|[1-5][0-9]",apply:function(a){this.seconds=+a}},a:{regex:b.DATETIME_FORMATS.AMPMS.join("|"),apply:function(a){12===this.hours&&(this.hours=0),"PM"===a&&(this.hours+=12)}}}},this.init(),this.parse=function(c,g,i){if(!angular.isString(c)||!g)return c;g=b.DATETIME_FORMATS[g]||g,g=g.replace(h,"\\$&"),b.id!==f&&this.init(),this.parsers[g]||(this.parsers[g]=d(g));var j=this.parsers[g],k=j.regex,l=j.map,m=c.match(k);if(m&&m.length){var n,o;angular.isDate(i)&&!isNaN(i.getTime())?n={year:i.getFullYear(),month:i.getMonth(),date:i.getDate(),hours:i.getHours(),minutes:i.getMinutes(),seconds:i.getSeconds(),milliseconds:i.getMilliseconds()}:(i&&a.warn("dateparser:","baseDate is not a valid date"),n={year:1900,month:0,date:1,hours:0,minutes:0,seconds:0,milliseconds:0});for(var p=1,q=m.length;q>p;p++){var r=l[p-1];r.apply&&r.apply.call(n,m[p])}return e(n.year,n.month,n.date)&&(angular.isDate(i)&&!isNaN(i.getTime())?(o=new Date(i),o.setFullYear(n.year,n.month,n.date,n.hours,n.minutes,n.seconds,n.milliseconds||0)):o=new Date(n.year,n.month,n.date,n.hours,n.minutes,n.seconds,n.milliseconds||0)),o}}}]),angular.module("ui.bootstrap.dateparser").value("$dateParserSuppressWarning",!1).service("dateParser",["$log","$dateParserSuppressWarning","uibDateParser",function(a,b,c){b||a.warn("dateParser is now deprecated. Use uibDateParser instead."),angular.extend(this,c)}]),angular.module("ui.bootstrap.position",[]).factory("$uibPosition",["$document","$window",function(a,b){function c(a,c){return a.currentStyle?a.currentStyle[c]:b.getComputedStyle?b.getComputedStyle(a)[c]:a.style[c]}function d(a){return"static"===(c(a,"position")||"static")}var e=function(b){for(var c=a[0],e=b.offsetParent||c;e&&e!==c&&d(e);)e=e.offsetParent;return e||c};return{position:function(b){var c=this.offset(b),d={top:0,left:0},f=e(b[0]);f!=a[0]&&(d=this.offset(angular.element(f)),d.top+=f.clientTop-f.scrollTop,d.left+=f.clientLeft-f.scrollLeft);var g=b[0].getBoundingClientRect();return{width:g.width||b.prop("offsetWidth"),height:g.height||b.prop("offsetHeight"),top:c.top-d.top,left:c.left-d.left}},offset:function(c){var d=c[0].getBoundingClientRect();return{width:d.width||c.prop("offsetWidth"),height:d.height||c.prop("offsetHeight"),top:d.top+(b.pageYOffset||a[0].documentElement.scrollTop),left:d.left+(b.pageXOffset||a[0].documentElement.scrollLeft)}},positionElements:function(a,b,c,d){var e,f,g,h,i=c.split("-"),j=i[0],k=i[1]||"center";e=d?this.offset(a):this.position(a),f=b.prop("offsetWidth"),g=b.prop("offsetHeight");var l={center:function(){return e.left+e.width/2-f/2},left:function(){return e.left},right:function(){return e.left+e.width}},m={center:function(){return e.top+e.height/2-g/2},top:function(){return e.top},bottom:function(){return e.top+e.height}};switch(j){case"right":h={top:m[k](),left:l[j]()};break;case"left":h={top:m[k](),left:e.left-f};break;case"bottom":h={top:m[j](),left:l[k]()};break;default:h={top:e.top-g,left:l[k]()}}return h}}}]),angular.module("ui.bootstrap.position").value("$positionSuppressWarning",!1).service("$position",["$log","$positionSuppressWarning","$uibPosition",function(a,b,c){b||a.warn("$position is now deprecated. Use $uibPosition instead."),angular.extend(this,c)}]),angular.module("ui.bootstrap.datepicker",["ui.bootstrap.dateparser","ui.bootstrap.position"]).value("$datepickerSuppressError",!1).constant("uibDatepickerConfig",{formatDay:"dd",formatMonth:"MMMM",formatYear:"yyyy",formatDayHeader:"EEE",formatDayTitle:"MMMM yyyy",formatMonthTitle:"yyyy",datepickerMode:"day",minMode:"day",maxMode:"year",showWeeks:!0,startingDay:0,yearRange:20,minDate:null,maxDate:null,shortcutPropagation:!1}).controller("UibDatepickerController",["$scope","$attrs","$parse","$interpolate","$log","dateFilter","uibDatepickerConfig","$datepickerSuppressError",function(a,b,c,d,e,f,g,h){var i=this,j={$setViewValue:angular.noop};this.modes=["day","month","year"],angular.forEach(["formatDay","formatMonth","formatYear","formatDayHeader","formatDayTitle","formatMonthTitle","showWeeks","startingDay","yearRange","shortcutPropagation"],function(c,e){i[c]=angular.isDefined(b[c])?6>e?d(b[c])(a.$parent):a.$parent.$eval(b[c]):g[c]}),angular.forEach(["minDate","maxDate"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(a){i[d]=a?new Date(a):null,i.refreshView()}):i[d]=g[d]?new Date(g[d]):null}),angular.forEach(["minMode","maxMode"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(c){i[d]=angular.isDefined(c)?c:b[d],a[d]=i[d],("minMode"==d&&i.modes.indexOf(a.datepickerMode)i.modes.indexOf(i[d]))&&(a.datepickerMode=i[d])}):(i[d]=g[d]||null,a[d]=i[d])}),a.datepickerMode=a.datepickerMode||g.datepickerMode,a.uniqueId="datepicker-"+a.$id+"-"+Math.floor(1e4*Math.random()),angular.isDefined(b.initDate)?(this.activeDate=a.$parent.$eval(b.initDate)||new Date,a.$parent.$watch(b.initDate,function(a){a&&(j.$isEmpty(j.$modelValue)||j.$invalid)&&(i.activeDate=a,i.refreshView())})):this.activeDate=new Date,a.isActive=function(b){return 0===i.compare(b.date,i.activeDate)?(a.activeDateId=b.uid,!0):!1},this.init=function(a){j=a,j.$render=function(){i.render()}},this.render=function(){if(j.$viewValue){var a=new Date(j.$viewValue),b=!isNaN(a);b?this.activeDate=a:h||e.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.')}this.refreshView()},this.refreshView=function(){if(this.element){this._refreshView();var a=j.$viewValue?new Date(j.$viewValue):null;j.$setValidity("dateDisabled",!a||this.element&&!this.isDisabled(a))}},this.createDateObject=function(a,b){var c=j.$viewValue?new Date(j.$viewValue):null;return{date:a,label:f(a,b),selected:c&&0===this.compare(a,c),disabled:this.isDisabled(a),current:0===this.compare(a,new Date),customClass:this.customClass(a)}},this.isDisabled=function(c){return this.minDate&&this.compare(c,this.minDate)<0||this.maxDate&&this.compare(c,this.maxDate)>0||b.dateDisabled&&a.dateDisabled({date:c,mode:a.datepickerMode})},this.customClass=function(b){return a.customClass({date:b,mode:a.datepickerMode})},this.split=function(a,b){for(var c=[];a.length>0;)c.push(a.splice(0,b));return c},a.select=function(b){if(a.datepickerMode===i.minMode){var c=j.$viewValue?new Date(j.$viewValue):new Date(0,0,0,0,0,0,0);c.setFullYear(b.getFullYear(),b.getMonth(),b.getDate()),j.$setViewValue(c),j.$render()}else i.activeDate=b,a.datepickerMode=i.modes[i.modes.indexOf(a.datepickerMode)-1]},a.move=function(a){var b=i.activeDate.getFullYear()+a*(i.step.years||0),c=i.activeDate.getMonth()+a*(i.step.months||0);i.activeDate.setFullYear(b,c,1),i.refreshView()},a.toggleMode=function(b){b=b||1,a.datepickerMode===i.maxMode&&1===b||a.datepickerMode===i.minMode&&-1===b||(a.datepickerMode=i.modes[i.modes.indexOf(a.datepickerMode)+b])},a.keys={13:"enter",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down"};var k=function(){i.element[0].focus()};a.$on("uib:datepicker.focus",k),a.keydown=function(b){var c=a.keys[b.which];if(c&&!b.shiftKey&&!b.altKey)if(b.preventDefault(),i.shortcutPropagation||b.stopPropagation(),"enter"===c||"space"===c){if(i.isDisabled(i.activeDate))return;a.select(i.activeDate)}else!b.ctrlKey||"up"!==c&&"down"!==c?(i.handleKeyDown(c,b),i.refreshView()):a.toggleMode("up"===c?1:-1)}}]).controller("UibDaypickerController",["$scope","$element","dateFilter",function(a,b,c){function d(a,b){return 1!==b||a%4!==0||a%100===0&&a%400!==0?f[b]:29}function e(a){var b=new Date(a);b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1}var f=[31,28,31,30,31,30,31,31,30,31,30,31];this.step={months:1},this.element=b,this.init=function(b){angular.extend(b,this),a.showWeeks=b.showWeeks,b.refreshView()},this.getDates=function(a,b){for(var c,d=new Array(b),e=new Date(a),f=0;b>f;)c=new Date(e),d[f++]=c,e.setDate(e.getDate()+1);return d},this._refreshView=function(){var b=this.activeDate.getFullYear(),d=this.activeDate.getMonth(),f=new Date(this.activeDate);f.setFullYear(b,d,1);var g=this.startingDay-f.getDay(),h=g>0?7-g:-g,i=new Date(f);h>0&&i.setDate(-h+1);for(var j=this.getDates(i,42),k=0;42>k;k++)j[k]=angular.extend(this.createDateObject(j[k],this.formatDay),{secondary:j[k].getMonth()!==d,uid:a.uniqueId+"-"+k});a.labels=new Array(7);for(var l=0;7>l;l++)a.labels[l]={abbr:c(j[l].date,this.formatDayHeader),full:c(j[l].date,"EEEE")};if(a.title=c(this.activeDate,this.formatDayTitle),a.rows=this.split(j,7),a.showWeeks){a.weekNumbers=[];for(var m=(11-this.startingDay)%7,n=a.rows.length,o=0;n>o;o++)a.weekNumbers.push(e(a.rows[o][m].date))}},this.compare=function(a,b){return new Date(a.getFullYear(),a.getMonth(),a.getDate())-new Date(b.getFullYear(),b.getMonth(),b.getDate())},this.handleKeyDown=function(a,b){var c=this.activeDate.getDate();if("left"===a)c-=1;else if("up"===a)c-=7;else if("right"===a)c+=1;else if("down"===a)c+=7;else if("pageup"===a||"pagedown"===a){var e=this.activeDate.getMonth()+("pageup"===a?-1:1);this.activeDate.setMonth(e,1),c=Math.min(d(this.activeDate.getFullYear(),this.activeDate.getMonth()),c)}else"home"===a?c=1:"end"===a&&(c=d(this.activeDate.getFullYear(),this.activeDate.getMonth()));this.activeDate.setDate(c)}}]).controller("UibMonthpickerController",["$scope","$element","dateFilter",function(a,b,c){this.step={years:1},this.element=b,this.init=function(a){angular.extend(a,this),a.refreshView()},this._refreshView=function(){for(var b,d=new Array(12),e=this.activeDate.getFullYear(),f=0;12>f;f++)b=new Date(this.activeDate),b.setFullYear(e,f,1),d[f]=angular.extend(this.createDateObject(b,this.formatMonth),{uid:a.uniqueId+"-"+f});a.title=c(this.activeDate,this.formatMonthTitle),a.rows=this.split(d,3)},this.compare=function(a,b){return new Date(a.getFullYear(),a.getMonth())-new Date(b.getFullYear(),b.getMonth())},this.handleKeyDown=function(a,b){var c=this.activeDate.getMonth();if("left"===a)c-=1;else if("up"===a)c-=3;else if("right"===a)c+=1;else if("down"===a)c+=3;else if("pageup"===a||"pagedown"===a){var d=this.activeDate.getFullYear()+("pageup"===a?-1:1);this.activeDate.setFullYear(d)}else"home"===a?c=0:"end"===a&&(c=11);this.activeDate.setMonth(c)}}]).controller("UibYearpickerController",["$scope","$element","dateFilter",function(a,b,c){function d(a){return parseInt((a-1)/e,10)*e+1}var e;this.element=b,this.yearpickerInit=function(){e=this.yearRange,this.step={years:e}},this._refreshView=function(){for(var b,c=new Array(e),f=0,g=d(this.activeDate.getFullYear());e>f;f++)b=new Date(this.activeDate),b.setFullYear(g+f,0,1),c[f]=angular.extend(this.createDateObject(b,this.formatYear),{uid:a.uniqueId+"-"+f});a.title=[c[0].label,c[e-1].label].join(" - "),a.rows=this.split(c,5)},this.compare=function(a,b){return a.getFullYear()-b.getFullYear()},this.handleKeyDown=function(a,b){var c=this.activeDate.getFullYear();"left"===a?c-=1:"up"===a?c-=5:"right"===a?c+=1:"down"===a?c+=5:"pageup"===a||"pagedown"===a?c+=("pageup"===a?-1:1)*this.step.years:"home"===a?c=d(this.activeDate.getFullYear()):"end"===a&&(c=d(this.activeDate.getFullYear())+e-1),this.activeDate.setFullYear(c)}}]).directive("uibDatepicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/datepicker.html"},scope:{datepickerMode:"=?",dateDisabled:"&",customClass:"&",shortcutPropagation:"&?"},require:["uibDatepicker","^ngModel"],controller:"UibDatepickerController",controllerAs:"datepicker",link:function(a,b,c,d){var e=d[0],f=d[1];e.init(f)}}}).directive("uibDaypicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/day.html"},require:["^?uibDatepicker","uibDaypicker","^?datepicker"],controller:"UibDaypickerController",link:function(a,b,c,d){var e=d[0]||d[2],f=d[1];f.init(e)}}}).directive("uibMonthpicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/month.html"},require:["^?uibDatepicker","uibMonthpicker","^?datepicker"],controller:"UibMonthpickerController",link:function(a,b,c,d){var e=d[0]||d[2],f=d[1];f.init(e)}}}).directive("uibYearpicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/year.html"},require:["^?uibDatepicker","uibYearpicker","^?datepicker"],controller:"UibYearpickerController",link:function(a,b,c,d){var e=d[0]||d[2];angular.extend(e,d[1]),e.yearpickerInit(),e.refreshView()}}}).constant("uibDatepickerPopupConfig",{datepickerPopup:"yyyy-MM-dd",datepickerPopupTemplateUrl:"template/datepicker/popup.html",datepickerTemplateUrl:"template/datepicker/datepicker.html",html5Types:{date:"yyyy-MM-dd","datetime-local":"yyyy-MM-ddTHH:mm:ss.sss",month:"yyyy-MM"},currentText:"Today",clearText:"Clear",closeText:"Done",closeOnDateSelection:!0,appendToBody:!1,showButtonBar:!0,onOpenFocus:!0}).controller("UibDatepickerPopupController",["$scope","$element","$attrs","$compile","$parse","$document","$rootScope","$uibPosition","dateFilter","uibDateParser","uibDatepickerPopupConfig","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l){ +function m(a){return a.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()})}function n(b){if(angular.isNumber(b)&&(b=new Date(b)),b){if(angular.isDate(b)&&!isNaN(b))return b;if(angular.isString(b)){var c=j.parse(b,r,a.date);return isNaN(c)?void 0:c}return void 0}return null}function o(a,b){var d=a||b;if(!c.ngRequired&&!d)return!0;if(angular.isNumber(d)&&(d=new Date(d)),d){if(angular.isDate(d)&&!isNaN(d))return!0;if(angular.isString(d)){var e=j.parse(d,r);return!isNaN(e)}return!1}return!0}function p(c){var d=A[0],e=b[0].contains(c.target),f=void 0!==d.contains&&d.contains(c.target);!a.isOpen||e||f||a.$apply(function(){a.isOpen=!1})}function q(c){27===c.which&&a.isOpen?(c.preventDefault(),c.stopPropagation(),a.$apply(function(){a.isOpen=!1}),b[0].focus()):40!==c.which||a.isOpen||(c.preventDefault(),c.stopPropagation(),a.$apply(function(){a.isOpen=!0}))}var r,s,t,u,v,w,x,y,z,A,B={},C=!1;a.watchData={},this.init=function(h){if(z=h,s=angular.isDefined(c.closeOnDateSelection)?a.$parent.$eval(c.closeOnDateSelection):k.closeOnDateSelection,t=angular.isDefined(c.datepickerAppendToBody)?a.$parent.$eval(c.datepickerAppendToBody):k.appendToBody,u=angular.isDefined(c.onOpenFocus)?a.$parent.$eval(c.onOpenFocus):k.onOpenFocus,v=angular.isDefined(c.datepickerPopupTemplateUrl)?c.datepickerPopupTemplateUrl:k.datepickerPopupTemplateUrl,w=angular.isDefined(c.datepickerTemplateUrl)?c.datepickerTemplateUrl:k.datepickerTemplateUrl,a.showButtonBar=angular.isDefined(c.showButtonBar)?a.$parent.$eval(c.showButtonBar):k.showButtonBar,k.html5Types[c.type]?(r=k.html5Types[c.type],C=!0):(r=c.datepickerPopup||c.uibDatepickerPopup||k.datepickerPopup,c.$observe("uibDatepickerPopup",function(a,b){var c=a||k.datepickerPopup;if(c!==r&&(r=c,z.$modelValue=null,!r))throw new Error("uibDatepickerPopup must have a date format specified.")})),!r)throw new Error("uibDatepickerPopup must have a date format specified.");if(C&&c.datepickerPopup)throw new Error("HTML5 date input types do not support custom formats.");if(x=angular.element("

            "),x.attr({"ng-model":"date","ng-change":"dateSelection(date)","template-url":v}),y=angular.element(x.children()[0]),y.attr("template-url",w),C&&"month"===c.type&&(y.attr("datepicker-mode",'"month"'),y.attr("min-mode","month")),c.datepickerOptions){var l=a.$parent.$eval(c.datepickerOptions);l&&l.initDate&&(a.initDate=l.initDate,y.attr("init-date","initDate"),delete l.initDate),angular.forEach(l,function(a,b){y.attr(m(b),a)})}angular.forEach(["minMode","maxMode","minDate","maxDate","datepickerMode","initDate","shortcutPropagation"],function(b){if(c[b]){var d=e(c[b]);if(a.$parent.$watch(d,function(c){a.watchData[b]=c,("minDate"===b||"maxDate"===b)&&(B[b]=new Date(c))}),y.attr(m(b),"watchData."+b),"datepickerMode"===b){var f=d.assign;a.$watch("watchData."+b,function(b,c){angular.isFunction(f)&&b!==c&&f(a.$parent,b)})}}}),c.dateDisabled&&y.attr("date-disabled","dateDisabled({ date: date, mode: mode })"),c.showWeeks&&y.attr("show-weeks",c.showWeeks),c.customClass&&y.attr("custom-class","customClass({ date: date, mode: mode })"),C?z.$formatters.push(function(b){return a.date=b,b}):(z.$$parserName="date",z.$validators.date=o,z.$parsers.unshift(n),z.$formatters.push(function(b){return a.date=b,z.$isEmpty(b)?b:i(b,r)})),z.$viewChangeListeners.push(function(){a.date=j.parse(z.$viewValue,r,a.date)}),b.bind("keydown",q),A=d(x)(a),x.remove(),t?f.find("body").append(A):b.after(A),a.$on("$destroy",function(){a.isOpen===!0&&(g.$$phase||a.$apply(function(){a.isOpen=!1})),A.remove(),b.unbind("keydown",q),f.unbind("click",p)})},a.getText=function(b){return a[b+"Text"]||k[b+"Text"]},a.isDisabled=function(b){return"today"===b&&(b=new Date),a.watchData.minDate&&a.compare(b,B.minDate)<0||a.watchData.maxDate&&a.compare(b,B.maxDate)>0},a.compare=function(a,b){return new Date(a.getFullYear(),a.getMonth(),a.getDate())-new Date(b.getFullYear(),b.getMonth(),b.getDate())},a.dateSelection=function(c){angular.isDefined(c)&&(a.date=c);var d=a.date?i(a.date,r):null;b.val(d),z.$setViewValue(d),s&&(a.isOpen=!1,b[0].focus())},a.keydown=function(c){27===c.which&&(a.isOpen=!1,b[0].focus())},a.select=function(b){if("today"===b){var c=new Date;angular.isDate(a.date)?(b=new Date(a.date),b.setFullYear(c.getFullYear(),c.getMonth(),c.getDate())):b=new Date(c.setHours(0,0,0,0))}a.dateSelection(b)},a.close=function(){a.isOpen=!1,b[0].focus()},a.$watch("isOpen",function(c){c?(a.position=t?h.offset(b):h.position(b),a.position.top=a.position.top+b.prop("offsetHeight"),l(function(){u&&a.$broadcast("uib:datepicker.focus"),f.bind("click",p)},0,!1)):f.unbind("click",p)})}]).directive("uibDatepickerPopup",function(){return{require:["ngModel","uibDatepickerPopup"],controller:"UibDatepickerPopupController",scope:{isOpen:"=?",currentText:"@",clearText:"@",closeText:"@",dateDisabled:"&",customClass:"&"},link:function(a,b,c,d){var e=d[0],f=d[1];f.init(e)}}}).directive("uibDatepickerPopupWrap",function(){return{replace:!0,transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/popup.html"}}}),angular.module("ui.bootstrap.datepicker").value("$datepickerSuppressWarning",!1).controller("DatepickerController",["$scope","$attrs","$parse","$interpolate","$log","dateFilter","uibDatepickerConfig","$datepickerSuppressError","$datepickerSuppressWarning",function(a,b,c,d,e,f,g,h,i){i||e.warn("DatepickerController is now deprecated. Use UibDatepickerController instead.");var j=this,k={$setViewValue:angular.noop};this.modes=["day","month","year"],angular.forEach(["formatDay","formatMonth","formatYear","formatDayHeader","formatDayTitle","formatMonthTitle","showWeeks","startingDay","yearRange","shortcutPropagation"],function(c,e){j[c]=angular.isDefined(b[c])?6>e?d(b[c])(a.$parent):a.$parent.$eval(b[c]):g[c]}),angular.forEach(["minDate","maxDate"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(a){j[d]=a?new Date(a):null,j.refreshView()}):j[d]=g[d]?new Date(g[d]):null}),angular.forEach(["minMode","maxMode"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(c){j[d]=angular.isDefined(c)?c:b[d],a[d]=j[d],("minMode"==d&&j.modes.indexOf(a.datepickerMode)j.modes.indexOf(j[d]))&&(a.datepickerMode=j[d])}):(j[d]=g[d]||null,a[d]=j[d])}),a.datepickerMode=a.datepickerMode||g.datepickerMode,a.uniqueId="datepicker-"+a.$id+"-"+Math.floor(1e4*Math.random()),angular.isDefined(b.initDate)?(this.activeDate=a.$parent.$eval(b.initDate)||new Date,a.$parent.$watch(b.initDate,function(a){a&&(k.$isEmpty(k.$modelValue)||k.$invalid)&&(j.activeDate=a,j.refreshView())})):this.activeDate=new Date,a.isActive=function(b){return 0===j.compare(b.date,j.activeDate)?(a.activeDateId=b.uid,!0):!1},this.init=function(a){k=a,k.$render=function(){j.render()}},this.render=function(){if(k.$viewValue){var a=new Date(k.$viewValue),b=!isNaN(a);b?this.activeDate=a:h||e.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.')}this.refreshView()},this.refreshView=function(){if(this.element){this._refreshView();var a=k.$viewValue?new Date(k.$viewValue):null;k.$setValidity("dateDisabled",!a||this.element&&!this.isDisabled(a))}},this.createDateObject=function(a,b){var c=k.$viewValue?new Date(k.$viewValue):null;return{date:a,label:f(a,b),selected:c&&0===this.compare(a,c),disabled:this.isDisabled(a),current:0===this.compare(a,new Date),customClass:this.customClass(a)}},this.isDisabled=function(c){return this.minDate&&this.compare(c,this.minDate)<0||this.maxDate&&this.compare(c,this.maxDate)>0||b.dateDisabled&&a.dateDisabled({date:c,mode:a.datepickerMode})},this.customClass=function(b){return a.customClass({date:b,mode:a.datepickerMode})},this.split=function(a,b){for(var c=[];a.length>0;)c.push(a.splice(0,b));return c},this.fixTimeZone=function(a){var b=a.getHours();a.setHours(23===b?b+2:0)},a.select=function(b){if(a.datepickerMode===j.minMode){var c=k.$viewValue?new Date(k.$viewValue):new Date(0,0,0,0,0,0,0);c.setFullYear(b.getFullYear(),b.getMonth(),b.getDate()),k.$setViewValue(c),k.$render()}else j.activeDate=b,a.datepickerMode=j.modes[j.modes.indexOf(a.datepickerMode)-1]},a.move=function(a){var b=j.activeDate.getFullYear()+a*(j.step.years||0),c=j.activeDate.getMonth()+a*(j.step.months||0);j.activeDate.setFullYear(b,c,1),j.refreshView()},a.toggleMode=function(b){b=b||1,a.datepickerMode===j.maxMode&&1===b||a.datepickerMode===j.minMode&&-1===b||(a.datepickerMode=j.modes[j.modes.indexOf(a.datepickerMode)+b])},a.keys={13:"enter",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down"};var l=function(){j.element[0].focus()};a.$on("uib:datepicker.focus",l),a.keydown=function(b){var c=a.keys[b.which];if(c&&!b.shiftKey&&!b.altKey)if(b.preventDefault(),j.shortcutPropagation||b.stopPropagation(),"enter"===c||"space"===c){if(j.isDisabled(j.activeDate))return;a.select(j.activeDate)}else!b.ctrlKey||"up"!==c&&"down"!==c?(j.handleKeyDown(c,b),j.refreshView()):a.toggleMode("up"===c?1:-1)}}]).directive("datepicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/datepicker.html"},scope:{datepickerMode:"=?",dateDisabled:"&",customClass:"&",shortcutPropagation:"&?"},require:["datepicker","^ngModel"],controller:"DatepickerController",controllerAs:"datepicker",link:function(c,d,e,f){b||a.warn("datepicker is now deprecated. Use uib-datepicker instead.");var g=f[0],h=f[1];g.init(h)}}}]).directive("daypicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:"template/datepicker/day.html",require:["^datepicker","daypicker"],controller:"UibDaypickerController",link:function(c,d,e,f){b||a.warn("daypicker is now deprecated. Use uib-daypicker instead.");var g=f[0],h=f[1];h.init(g)}}}]).directive("monthpicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:"template/datepicker/month.html",require:["^datepicker","monthpicker"],controller:"UibMonthpickerController",link:function(c,d,e,f){b||a.warn("monthpicker is now deprecated. Use uib-monthpicker instead.");var g=f[0],h=f[1];h.init(g)}}}]).directive("yearpicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:"template/datepicker/year.html",require:["^datepicker","yearpicker"],controller:"UibYearpickerController",link:function(c,d,e,f){b||a.warn("yearpicker is now deprecated. Use uib-yearpicker instead.");var g=f[0];angular.extend(g,f[1]),g.yearpickerInit(),g.refreshView()}}}]).directive("datepickerPopup",["$log","$datepickerSuppressWarning",function(a,b){return{require:["ngModel","datepickerPopup"],controller:"UibDatepickerPopupController",scope:{isOpen:"=?",currentText:"@",clearText:"@",closeText:"@",dateDisabled:"&",customClass:"&"},link:function(c,d,e,f){b||a.warn("datepicker-popup is now deprecated. Use uib-datepicker-popup instead.");var g=f[0],h=f[1];h.init(g)}}}]).directive("datepickerPopupWrap",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/popup.html"},link:function(){b||a.warn("datepicker-popup-wrap is now deprecated. Use uib-datepicker-popup-wrap instead.")}}}]),angular.module("ui.bootstrap.dropdown",["ui.bootstrap.position"]).constant("uibDropdownConfig",{openClass:"open"}).service("uibDropdownService",["$document","$rootScope",function(a,b){var c=null;this.open=function(b){c||(a.bind("click",d),a.bind("keydown",e)),c&&c!==b&&(c.isOpen=!1),c=b},this.close=function(b){c===b&&(c=null,a.unbind("click",d),a.unbind("keydown",e))};var d=function(a){if(c&&(!a||"disabled"!==c.getAutoClose())){var d=c.getToggleElement();if(!(a&&d&&d[0].contains(a.target))){var e=c.getDropdownElement();a&&"outsideClick"===c.getAutoClose()&&e&&e[0].contains(a.target)||(c.isOpen=!1,b.$$phase||c.$apply())}}},e=function(a){27===a.which?(c.focusToggleElement(),d()):c.isKeynavEnabled()&&/(38|40)/.test(a.which)&&c.isOpen&&(a.preventDefault(),a.stopPropagation(),c.focusDropdownEntry(a.which))}}]).controller("UibDropdownController",["$scope","$element","$attrs","$parse","uibDropdownConfig","uibDropdownService","$animate","$uibPosition","$document","$compile","$templateRequest",function(a,b,c,d,e,f,g,h,i,j,k){var l,m,n=this,o=a.$new(),p=e.openClass,q=angular.noop,r=c.onToggle?d(c.onToggle):angular.noop,s=!1,t=!1;b.addClass("dropdown"),this.init=function(){c.isOpen&&(m=d(c.isOpen),q=m.assign,a.$watch(m,function(a){o.isOpen=!!a})),s=angular.isDefined(c.dropdownAppendToBody),t=angular.isDefined(c.uibKeyboardNav),s&&n.dropdownMenu&&(i.find("body").append(n.dropdownMenu),b.on("$destroy",function(){n.dropdownMenu.remove()}))},this.toggle=function(a){return o.isOpen=arguments.length?!!a:!o.isOpen},this.isOpen=function(){return o.isOpen},o.getToggleElement=function(){return n.toggleElement},o.getAutoClose=function(){return c.autoClose||"always"},o.getElement=function(){return b},o.isKeynavEnabled=function(){return t},o.focusDropdownEntry=function(a){var c=n.dropdownMenu?angular.element(n.dropdownMenu).find("a"):angular.element(b).find("ul").eq(0).find("a");switch(a){case 40:angular.isNumber(n.selectedOption)?n.selectedOption=n.selectedOption===c.length-1?n.selectedOption:n.selectedOption+1:n.selectedOption=0;break;case 38:angular.isNumber(n.selectedOption)?n.selectedOption=0===n.selectedOption?0:n.selectedOption-1:n.selectedOption=c.length-1}c[n.selectedOption].focus()},o.getDropdownElement=function(){return n.dropdownMenu},o.focusToggleElement=function(){n.toggleElement&&n.toggleElement[0].focus()},o.$watch("isOpen",function(c,d){if(s&&n.dropdownMenu){var e=h.positionElements(b,n.dropdownMenu,"bottom-left",!0),i={top:e.top+"px",display:c?"block":"none"},m=n.dropdownMenu.hasClass("dropdown-menu-right");m?(i.left="auto",i.right=window.innerWidth-(e.left+b.prop("offsetWidth"))+"px"):(i.left=e.left+"px",i.right="auto"),n.dropdownMenu.css(i)}if(g[c?"addClass":"removeClass"](b,p).then(function(){angular.isDefined(c)&&c!==d&&r(a,{open:!!c})}),c)n.dropdownMenuTemplateUrl&&k(n.dropdownMenuTemplateUrl).then(function(a){l=o.$new(),j(a.trim())(l,function(a){var b=a;n.dropdownMenu.replaceWith(b),n.dropdownMenu=b})}),o.focusToggleElement(),f.open(o);else{if(n.dropdownMenuTemplateUrl){l&&l.$destroy();var t=angular.element('');n.dropdownMenu.replaceWith(t),n.dropdownMenu=t}f.close(o),n.selectedOption=null}angular.isFunction(q)&&q(a,c)}),a.$on("$locationChangeSuccess",function(){"disabled"!==o.getAutoClose()&&(o.isOpen=!1)});var u=a.$on("$destroy",function(){o.$destroy()});o.$on("$destroy",u)}]).directive("uibDropdown",function(){return{controller:"UibDropdownController",link:function(a,b,c,d){d.init()}}}).directive("uibDropdownMenu",function(){return{restrict:"AC",require:"?^uibDropdown",link:function(a,b,c,d){if(d&&!angular.isDefined(c.dropdownNested)){b.addClass("dropdown-menu");var e=c.templateUrl;e&&(d.dropdownMenuTemplateUrl=e),d.dropdownMenu||(d.dropdownMenu=b)}}}}).directive("uibKeyboardNav",function(){return{restrict:"A",require:"?^uibDropdown",link:function(a,b,c,d){b.bind("keydown",function(a){if(-1!==[38,40].indexOf(a.which)){a.preventDefault(),a.stopPropagation();var b=d.dropdownMenu.find("a");switch(a.which){case 40:angular.isNumber(d.selectedOption)?d.selectedOption=d.selectedOption===b.length-1?d.selectedOption:d.selectedOption+1:d.selectedOption=0;break;case 38:angular.isNumber(d.selectedOption)?d.selectedOption=0===d.selectedOption?0:d.selectedOption-1:d.selectedOption=b.length-1}b[d.selectedOption].focus()}})}}}).directive("uibDropdownToggle",function(){return{require:"?^uibDropdown",link:function(a,b,c,d){if(d){b.addClass("dropdown-toggle"),d.toggleElement=b;var e=function(e){e.preventDefault(),b.hasClass("disabled")||c.disabled||a.$apply(function(){d.toggle()})};b.bind("click",e),b.attr({"aria-haspopup":!0,"aria-expanded":!1}),a.$watch(d.isOpen,function(a){b.attr("aria-expanded",!!a)}),a.$on("$destroy",function(){b.unbind("click",e)})}}}}),angular.module("ui.bootstrap.dropdown").value("$dropdownSuppressWarning",!1).service("dropdownService",["$log","$dropdownSuppressWarning","uibDropdownService",function(a,b,c){b||a.warn("dropdownService is now deprecated. Use uibDropdownService instead."),angular.extend(this,c)}]).controller("DropdownController",["$scope","$element","$attrs","$parse","uibDropdownConfig","uibDropdownService","$animate","$uibPosition","$document","$compile","$templateRequest","$log","$dropdownSuppressWarning",function(a,b,c,d,e,f,g,h,i,j,k,l,m){m||l.warn("DropdownController is now deprecated. Use UibDropdownController instead.");var n,o,p=this,q=a.$new(),r=e.openClass,s=angular.noop,t=c.onToggle?d(c.onToggle):angular.noop,u=!1,v=!1;b.addClass("dropdown"),this.init=function(){c.isOpen&&(o=d(c.isOpen),s=o.assign,a.$watch(o,function(a){q.isOpen=!!a})),u=angular.isDefined(c.dropdownAppendToBody),v=angular.isDefined(c.uibKeyboardNav),u&&p.dropdownMenu&&(i.find("body").append(p.dropdownMenu),b.on("$destroy",function(){p.dropdownMenu.remove()}))},this.toggle=function(a){return q.isOpen=arguments.length?!!a:!q.isOpen},this.isOpen=function(){return q.isOpen},q.getToggleElement=function(){return p.toggleElement},q.getAutoClose=function(){return c.autoClose||"always"},q.getElement=function(){return b},q.isKeynavEnabled=function(){return v},q.focusDropdownEntry=function(a){var c=p.dropdownMenu?angular.element(p.dropdownMenu).find("a"):angular.element(b).find("ul").eq(0).find("a");switch(a){case 40:angular.isNumber(p.selectedOption)?p.selectedOption=p.selectedOption===c.length-1?p.selectedOption:p.selectedOption+1:p.selectedOption=0;break;case 38:angular.isNumber(p.selectedOption)?p.selectedOption=0===p.selectedOption?0:p.selectedOption-1:p.selectedOption=c.length-1}c[p.selectedOption].focus()},q.getDropdownElement=function(){return p.dropdownMenu},q.focusToggleElement=function(){p.toggleElement&&p.toggleElement[0].focus()},q.$watch("isOpen",function(c,d){if(u&&p.dropdownMenu){var e=h.positionElements(b,p.dropdownMenu,"bottom-left",!0),i={top:e.top+"px",display:c?"block":"none"},l=p.dropdownMenu.hasClass("dropdown-menu-right");l?(i.left="auto",i.right=window.innerWidth-(e.left+b.prop("offsetWidth"))+"px"):(i.left=e.left+"px",i.right="auto"),p.dropdownMenu.css(i)}if(g[c?"addClass":"removeClass"](b,r).then(function(){angular.isDefined(c)&&c!==d&&t(a,{open:!!c})}),c)p.dropdownMenuTemplateUrl&&k(p.dropdownMenuTemplateUrl).then(function(a){n=q.$new(),j(a.trim())(n,function(a){var b=a;p.dropdownMenu.replaceWith(b),p.dropdownMenu=b})}),q.focusToggleElement(),f.open(q);else{if(p.dropdownMenuTemplateUrl){n&&n.$destroy();var m=angular.element('');p.dropdownMenu.replaceWith(m),p.dropdownMenu=m}f.close(q),p.selectedOption=null}angular.isFunction(s)&&s(a,c)}),a.$on("$locationChangeSuccess",function(){"disabled"!==q.getAutoClose()&&(q.isOpen=!1)});var w=a.$on("$destroy",function(){q.$destroy()});q.$on("$destroy",w)}]).directive("dropdown",["$log","$dropdownSuppressWarning",function(a,b){return{controller:"DropdownController",link:function(c,d,e,f){b||a.warn("dropdown is now deprecated. Use uib-dropdown instead."),f.init()}}}]).directive("dropdownMenu",["$log","$dropdownSuppressWarning",function(a,b){return{restrict:"AC",require:"?^dropdown",link:function(c,d,e,f){if(f&&!angular.isDefined(e.dropdownNested)){b||a.warn("dropdown-menu is now deprecated. Use uib-dropdown-menu instead."),d.addClass("dropdown-menu");var g=e.templateUrl;g&&(f.dropdownMenuTemplateUrl=g),f.dropdownMenu||(f.dropdownMenu=d)}}}}]).directive("keyboardNav",["$log","$dropdownSuppressWarning",function(a,b){return{restrict:"A",require:"?^dropdown",link:function(c,d,e,f){b||a.warn("keyboard-nav is now deprecated. Use uib-keyboard-nav instead."),d.bind("keydown",function(a){if(-1!==[38,40].indexOf(a.which)){a.preventDefault(),a.stopPropagation();var b=f.dropdownMenu.find("a");switch(a.which){case 40:angular.isNumber(f.selectedOption)?f.selectedOption=f.selectedOption===b.length-1?f.selectedOption:f.selectedOption+1:f.selectedOption=0;break;case 38:angular.isNumber(f.selectedOption)?f.selectedOption=0===f.selectedOption?0:f.selectedOption-1:f.selectedOption=b.length-1}b[f.selectedOption].focus()}})}}}]).directive("dropdownToggle",["$log","$dropdownSuppressWarning",function(a,b){return{require:"?^dropdown",link:function(c,d,e,f){if(b||a.warn("dropdown-toggle is now deprecated. Use uib-dropdown-toggle instead."),f){d.addClass("dropdown-toggle"),f.toggleElement=d;var g=function(a){a.preventDefault(),d.hasClass("disabled")||e.disabled||c.$apply(function(){f.toggle()})};d.bind("click",g),d.attr({"aria-haspopup":!0,"aria-expanded":!1}),c.$watch(f.isOpen,function(a){d.attr("aria-expanded",!!a)}),c.$on("$destroy",function(){d.unbind("click",g)})}}}}]),angular.module("ui.bootstrap.stackedMap",[]).factory("$$stackedMap",function(){return{createNew:function(){var a=[];return{add:function(b,c){a.push({key:b,value:c})},get:function(b){for(var c=0;c0&&(b=u.top().value,b.modalDomEl.toggleClass(b.windowTopClass||"",a))}function m(){if(q&&-1==j()){var a=r;n(q,r,function(){a=null}),q=void 0,r=void 0}}function n(b,c,d){function e(){e.done||(e.done=!0,p?p(b,{event:"leave"}).start().then(function(){b.remove()}):a.leave(b),c.$destroy(),d&&d())}var g,h=null,i=function(){return g||(g=f.defer(),h=g.promise),function(){g.resolve()}};return c.$broadcast(w.NOW_CLOSING_EVENT,i),f.when(h).then(e)}function o(a,b,c){return!a.value.modalScope.$broadcast("modal.closing",b,c).defaultPrevented}var p=null;g.has("$animateCss")&&(p=g.get("$animateCss"));var q,r,s,t="modal-open",u=i.createNew(),v=h.createNew(),w={NOW_CLOSING_EVENT:"modal.stack.now-closing"},x=0,y="a[href], area[href], input:not([disabled]), button:not([disabled]),select:not([disabled]), textarea:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable=true]";return e.$watch(j,function(a){r&&(r.index=a)}),c.bind("keydown",function(a){if(a.isDefaultPrevented())return a;var b=u.top();if(b&&b.value.keyboard)switch(a.which){case 27:a.preventDefault(),e.$apply(function(){w.dismiss(b.key,"escape key press")});break;case 9:w.loadFocusElementList(b);var c=!1;a.shiftKey?w.isFocusInFirstItem(a)&&(c=w.focusLastFocusableElement()):w.isFocusInLastItem(a)&&(c=w.focusFirstFocusableElement()),c&&(a.preventDefault(),a.stopPropagation())}}),w.open=function(a,b){var f=c[0].activeElement,g=b.openedClass||t;l(!1),u.add(a,{deferred:b.deferred,renderDeferred:b.renderDeferred,modalScope:b.scope,backdrop:b.backdrop,keyboard:b.keyboard,openedClass:b.openedClass,windowTopClass:b.windowTopClass}),v.put(g,a);var h=c.find("body").eq(0),i=j();if(i>=0&&!q){r=e.$new(!0),r.index=i;var k=angular.element('
            ');k.attr("backdrop-class",b.backdropClass),b.animation&&k.attr("modal-animation","true"),q=d(k)(r),h.append(q)}var m=angular.element('
            ');m.attr({"template-url":b.windowTemplateUrl,"window-class":b.windowClass,"window-top-class":b.windowTopClass,size:b.size,index:u.length()-1,animate:"animate"}).html(b.content),b.animation&&m.attr("modal-animation","true");var n=d(m)(b.scope);u.top().value.modalDomEl=n,u.top().value.modalOpener=f,h.append(n),h.addClass(g),w.clearFocusListCache()},w.close=function(a,b){var c=u.get(a);return c&&o(c,b,!0)?(c.value.modalScope.$$uibDestructionScheduled=!0,c.value.deferred.resolve(b),k(a,c.value.modalOpener),!0):!c},w.dismiss=function(a,b){var c=u.get(a);return c&&o(c,b,!1)?(c.value.modalScope.$$uibDestructionScheduled=!0,c.value.deferred.reject(b),k(a,c.value.modalOpener),!0):!c},w.dismissAll=function(a){for(var b=this.getTop();b&&this.dismiss(b.key,a);)b=this.getTop()},w.getTop=function(){return u.top()},w.modalRendered=function(a){var b=u.get(a);b&&b.value.renderDeferred.resolve()},w.focusFirstFocusableElement=function(){return s.length>0?(s[0].focus(),!0):!1},w.focusLastFocusableElement=function(){return s.length>0?(s[s.length-1].focus(),!0):!1},w.isFocusInFirstItem=function(a){return s.length>0?(a.target||a.srcElement)==s[0]:!1},w.isFocusInLastItem=function(a){return s.length>0?(a.target||a.srcElement)==s[s.length-1]:!1},w.clearFocusListCache=function(){s=[],x=0},w.loadFocusElementList=function(a){if((void 0===s||!s.length)&&a){var b=a.value.modalDomEl;b&&b.length&&(s=b[0].querySelectorAll(y))}},w}]).provider("$uibModal",function(){var a={options:{animation:!0,backdrop:!0,keyboard:!0},$get:["$injector","$rootScope","$q","$templateRequest","$controller","$uibModalStack","$modalSuppressWarning","$log",function(b,c,d,e,f,g,h,i){function j(a){return a.template?d.when(a.template):e(angular.isFunction(a.templateUrl)?a.templateUrl():a.templateUrl)}function k(a){var c=[];return angular.forEach(a,function(a){angular.isFunction(a)||angular.isArray(a)?c.push(d.when(b.invoke(a))):angular.isString(a)?c.push(d.when(b.get(a))):c.push(d.when(a))}),c}var l={},m=null;return l.getPromiseChain=function(){return m},l.open=function(b){function e(){return r}var l=d.defer(),n=d.defer(),o=d.defer(),p={result:l.promise,opened:n.promise,rendered:o.promise,close:function(a){return g.close(p,a)},dismiss:function(a){return g.dismiss(p,a)}};if(b=angular.extend({},a.options,b),b.resolve=b.resolve||{},!b.template&&!b.templateUrl)throw new Error("One of template or templateUrl options is required.");var q,r=d.all([j(b)].concat(k(b.resolve)));return q=m=d.all([m]).then(e,e).then(function(a){var d=(b.scope||c).$new();d.$close=p.close,d.$dismiss=p.dismiss,d.$on("$destroy",function(){d.$$uibDestructionScheduled||d.$dismiss("$uibUnscheduledDestruction")});var e,j={},k=1;b.controller&&(j.$scope=d,j.$uibModalInstance=p,Object.defineProperty(j,"$modalInstance",{get:function(){return h||i.warn("$modalInstance is now deprecated. Use $uibModalInstance instead."),p}}),angular.forEach(b.resolve,function(b,c){j[c]=a[k++]}),e=f(b.controller,j),b.controllerAs&&(b.bindToController&&angular.extend(e,d),d[b.controllerAs]=e)),g.open(p,{scope:d,deferred:l,renderDeferred:o,content:a[0],animation:b.animation,backdrop:b.backdrop,keyboard:b.keyboard,backdropClass:b.backdropClass,windowTopClass:b.windowTopClass,windowClass:b.windowClass,windowTemplateUrl:b.windowTemplateUrl,size:b.size,openedClass:b.openedClass}),n.resolve(!0)},function(a){n.reject(a),l.reject(a)})["finally"](function(){m===q&&(m=null)}),p},l}]};return a}),angular.module("ui.bootstrap.modal").value("$modalSuppressWarning",!1).directive("modalBackdrop",["$animate","$injector","$modalStack","$log","$modalSuppressWarning",function(a,b,c,d,e){function f(b,f,h){e||d.warn("modal-backdrop is now deprecated. Use uib-modal-backdrop instead."),f.addClass("modal-backdrop"),h.modalInClass&&(g?g(f,{addClass:h.modalInClass}).start():a.addClass(f,h.modalInClass),b.$on(c.NOW_CLOSING_EVENT,function(b,c){var d=c();g?g(f,{removeClass:h.modalInClass}).start().then(d):a.removeClass(f,h.modalInClass).then(d)}))}var g=null;return b.has("$animateCss")&&(g=b.get("$animateCss")),{replace:!0,templateUrl:"template/modal/backdrop.html",compile:function(a,b){return a.addClass(b.backdropClass),f}}}]).directive("modalWindow",["$modalStack","$q","$animate","$injector","$log","$modalSuppressWarning",function(a,b,c,d,e,f){var g=null;return d.has("$animateCss")&&(g=d.get("$animateCss")),{scope:{index:"@"},replace:!0,transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/modal/window.html"},link:function(d,h,i){f||e.warn("modal-window is now deprecated. Use uib-modal-window instead."),h.addClass(i.windowClass||""),h.addClass(i.windowTopClass||""),d.size=i.size,d.close=function(b){var c=a.getTop();c&&c.value.backdrop&&"static"!==c.value.backdrop&&b.target===b.currentTarget&&(b.preventDefault(),b.stopPropagation(),a.dismiss(c.key,"backdrop click"))},h.on("click",d.close),d.$isRendered=!0;var j=b.defer();i.$observe("modalRender",function(a){"true"==a&&j.resolve()}),j.promise.then(function(){var e=null;i.modalInClass&&(e=g?g(h,{addClass:i.modalInClass}).start():c.addClass(h,i.modalInClass),d.$on(a.NOW_CLOSING_EVENT,function(a,b){var d=b();g?g(h,{removeClass:i.modalInClass}).start().then(d):c.removeClass(h,i.modalInClass).then(d)})),b.when(e).then(function(){var a=h[0].querySelector("[autofocus]");a?a.focus():h[0].focus()});var f=a.getTop();f&&a.modalRendered(f.key)})}}}]).directive("modalAnimationClass",["$log","$modalSuppressWarning",function(a,b){return{compile:function(c,d){b||a.warn("modal-animation-class is now deprecated. Use uib-modal-animation-class instead."),d.modalAnimation&&c.addClass(d.modalAnimationClass)}}}]).directive("modalTransclude",["$log","$modalSuppressWarning",function(a,b){return{link:function(c,d,e,f,g){ +b||a.warn("modal-transclude is now deprecated. Use uib-modal-transclude instead."),g(c.$parent,function(a){d.empty(),d.append(a)})}}}]).service("$modalStack",["$animate","$timeout","$document","$compile","$rootScope","$q","$injector","$$multiMap","$$stackedMap","$uibModalStack","$log","$modalSuppressWarning",function(a,b,c,d,e,f,g,h,i,j,k,l){l||k.warn("$modalStack is now deprecated. Use $uibModalStack instead."),angular.extend(this,j)}]).provider("$modal",["$uibModalProvider",function(a){angular.extend(this,a),this.$get=["$injector","$log","$modalSuppressWarning",function(b,c,d){return d||c.warn("$modal is now deprecated. Use $uibModal instead."),b.invoke(a.$get)}]}]),angular.module("ui.bootstrap.pagination",[]).controller("UibPaginationController",["$scope","$attrs","$parse",function(a,b,c){var d=this,e={$setViewValue:angular.noop},f=b.numPages?c(b.numPages).assign:angular.noop;this.init=function(g,h){e=g,this.config=h,e.$render=function(){d.render()},b.itemsPerPage?a.$parent.$watch(c(b.itemsPerPage),function(b){d.itemsPerPage=parseInt(b,10),a.totalPages=d.calculateTotalPages()}):this.itemsPerPage=h.itemsPerPage,a.$watch("totalItems",function(){a.totalPages=d.calculateTotalPages()}),a.$watch("totalPages",function(b){f(a.$parent,b),a.page>b?a.selectPage(b):e.$render()})},this.calculateTotalPages=function(){var b=this.itemsPerPage<1?1:Math.ceil(a.totalItems/this.itemsPerPage);return Math.max(b||0,1)},this.render=function(){a.page=parseInt(e.$viewValue,10)||1},a.selectPage=function(b,c){c&&c.preventDefault();var d=!a.ngDisabled||!c;d&&a.page!==b&&b>0&&b<=a.totalPages&&(c&&c.target&&c.target.blur(),e.$setViewValue(b),e.$render())},a.getText=function(b){return a[b+"Text"]||d.config[b+"Text"]},a.noPrevious=function(){return 1===a.page},a.noNext=function(){return a.page===a.totalPages}}]).constant("uibPaginationConfig",{itemsPerPage:10,boundaryLinks:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0}).directive("uibPagination",["$parse","uibPaginationConfig",function(a,b){return{restrict:"EA",scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@",ngDisabled:"="},require:["uibPagination","?ngModel"],controller:"UibPaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pagination.html"},replace:!0,link:function(c,d,e,f){function g(a,b,c){return{number:a,text:b,active:c}}function h(a,b){var c=[],d=1,e=b,f=angular.isDefined(k)&&b>k;f&&(l?(d=Math.max(a-Math.floor(k/2),1),e=d+k-1,e>b&&(e=b,d=e-k+1)):(d=(Math.ceil(a/k)-1)*k+1,e=Math.min(d+k-1,b)));for(var h=d;e>=h;h++){var i=g(h,h,h===a);c.push(i)}if(f&&!l){if(d>1){var j=g(d-1,"...",!1);c.unshift(j)}if(b>e){var m=g(e+1,"...",!1);c.push(m)}}return c}var i=f[0],j=f[1];if(j){var k=angular.isDefined(e.maxSize)?c.$parent.$eval(e.maxSize):b.maxSize,l=angular.isDefined(e.rotate)?c.$parent.$eval(e.rotate):b.rotate;c.boundaryLinks=angular.isDefined(e.boundaryLinks)?c.$parent.$eval(e.boundaryLinks):b.boundaryLinks,c.directionLinks=angular.isDefined(e.directionLinks)?c.$parent.$eval(e.directionLinks):b.directionLinks,i.init(j,b),e.maxSize&&c.$parent.$watch(a(e.maxSize),function(a){k=parseInt(a,10),i.render()});var m=i.render;i.render=function(){m(),c.page>0&&c.page<=c.totalPages&&(c.pages=h(c.page,c.totalPages))}}}}}]).constant("uibPagerConfig",{itemsPerPage:10,previousText:"« Previous",nextText:"Next »",align:!0}).directive("uibPager",["uibPagerConfig",function(a){return{restrict:"EA",scope:{totalItems:"=",previousText:"@",nextText:"@",ngDisabled:"="},require:["uibPager","?ngModel"],controller:"UibPaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pager.html"},replace:!0,link:function(b,c,d,e){var f=e[0],g=e[1];g&&(b.align=angular.isDefined(d.align)?b.$parent.$eval(d.align):a.align,f.init(g,a))}}}]),angular.module("ui.bootstrap.pagination").value("$paginationSuppressWarning",!1).controller("PaginationController",["$scope","$attrs","$parse","$log","$paginationSuppressWarning",function(a,b,c,d,e){e||d.warn("PaginationController is now deprecated. Use UibPaginationController instead.");var f=this,g={$setViewValue:angular.noop},h=b.numPages?c(b.numPages).assign:angular.noop;this.init=function(d,e){g=d,this.config=e,g.$render=function(){f.render()},b.itemsPerPage?a.$parent.$watch(c(b.itemsPerPage),function(b){f.itemsPerPage=parseInt(b,10),a.totalPages=f.calculateTotalPages()}):this.itemsPerPage=e.itemsPerPage,a.$watch("totalItems",function(){a.totalPages=f.calculateTotalPages()}),a.$watch("totalPages",function(b){h(a.$parent,b),a.page>b?a.selectPage(b):g.$render()})},this.calculateTotalPages=function(){var b=this.itemsPerPage<1?1:Math.ceil(a.totalItems/this.itemsPerPage);return Math.max(b||0,1)},this.render=function(){a.page=parseInt(g.$viewValue,10)||1},a.selectPage=function(b,c){c&&c.preventDefault();var d=!a.ngDisabled||!c;d&&a.page!==b&&b>0&&b<=a.totalPages&&(c&&c.target&&c.target.blur(),g.$setViewValue(b),g.$render())},a.getText=function(b){return a[b+"Text"]||f.config[b+"Text"]},a.noPrevious=function(){return 1===a.page},a.noNext=function(){return a.page===a.totalPages}}]).directive("pagination",["$parse","uibPaginationConfig","$log","$paginationSuppressWarning",function(a,b,c,d){return{restrict:"EA",scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@",ngDisabled:"="},require:["pagination","?ngModel"],controller:"PaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pagination.html"},replace:!0,link:function(e,f,g,h){function i(a,b,c){return{number:a,text:b,active:c}}function j(a,b){var c=[],d=1,e=b,f=angular.isDefined(m)&&b>m;f&&(n?(d=Math.max(a-Math.floor(m/2),1),e=d+m-1,e>b&&(e=b,d=e-m+1)):(d=(Math.ceil(a/m)-1)*m+1,e=Math.min(d+m-1,b)));for(var g=d;e>=g;g++){var h=i(g,g,g===a);c.push(h)}if(f&&!n){if(d>1){var j=i(d-1,"...",!1);c.unshift(j)}if(b>e){var k=i(e+1,"...",!1);c.push(k)}}return c}d||c.warn("pagination is now deprecated. Use uib-pagination instead.");var k=h[0],l=h[1];if(l){var m=angular.isDefined(g.maxSize)?e.$parent.$eval(g.maxSize):b.maxSize,n=angular.isDefined(g.rotate)?e.$parent.$eval(g.rotate):b.rotate;e.boundaryLinks=angular.isDefined(g.boundaryLinks)?e.$parent.$eval(g.boundaryLinks):b.boundaryLinks,e.directionLinks=angular.isDefined(g.directionLinks)?e.$parent.$eval(g.directionLinks):b.directionLinks,k.init(l,b),g.maxSize&&e.$parent.$watch(a(g.maxSize),function(a){m=parseInt(a,10),k.render()});var o=k.render;k.render=function(){o(),e.page>0&&e.page<=e.totalPages&&(e.pages=j(e.page,e.totalPages))}}}}}]).directive("pager",["uibPagerConfig","$log","$paginationSuppressWarning",function(a,b,c){return{restrict:"EA",scope:{totalItems:"=",previousText:"@",nextText:"@",ngDisabled:"="},require:["pager","?ngModel"],controller:"PaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pager.html"},replace:!0,link:function(d,e,f,g){c||b.warn("pager is now deprecated. Use uib-pager instead.");var h=g[0],i=g[1];i&&(d.align=angular.isDefined(f.align)?d.$parent.$eval(f.align):a.align,h.init(i,a))}}}]),angular.module("ui.bootstrap.tooltip",["ui.bootstrap.position","ui.bootstrap.stackedMap"]).provider("$uibTooltip",function(){function a(a){var b=/[A-Z]/g,c="-";return a.replace(b,function(a,b){return(b?c:"")+a.toLowerCase()})}var b={placement:"top",animation:!0,popupDelay:0,popupCloseDelay:0,useContentExp:!1},c={mouseenter:"mouseleave",click:"click",focus:"blur",none:""},d={};this.options=function(a){angular.extend(d,a)},this.setTriggers=function(a){angular.extend(c,a)},this.$get=["$window","$compile","$timeout","$document","$uibPosition","$interpolate","$rootScope","$parse","$$stackedMap",function(e,f,g,h,i,j,k,l,m){var n=m.createNew();return h.on("keypress",function(a){if(27===a.which){var b=n.top();b&&(b.value.close(),n.removeTop(),b=null)}}),function(e,k,m,o){function p(a){var b=(a||o.trigger||m).split(" "),d=b.map(function(a){return c[a]||a});return{show:b,hide:d}}o=angular.extend({},b,d,o);var q=a(e),r=j.startSymbol(),s=j.endSymbol(),t="
            ';return{compile:function(a,b){var c=f(t);return function(a,b,d,f){function j(){L.isOpen?q():m()}function m(){(!K||a.$eval(d[k+"Enable"]))&&(u(),x(),L.popupDelay?F||(F=g(r,L.popupDelay,!1)):r())}function q(){s(),L.popupCloseDelay?G||(G=g(t,L.popupCloseDelay,!1)):t()}function r(){return s(),u(),L.content?(v(),void L.$evalAsync(function(){L.isOpen=!0,y(!0),Q()})):angular.noop}function s(){F&&(g.cancel(F),F=null),H&&(g.cancel(H),H=null)}function t(){s(),u(),L&&L.$evalAsync(function(){L.isOpen=!1,y(!1),L.animation?E||(E=g(w,150,!1)):w()})}function u(){G&&(g.cancel(G),G=null),E&&(g.cancel(E),E=null)}function v(){C||(D=L.$new(),C=c(D,function(a){I?h.find("body").append(a):b.after(a)}),z())}function w(){A(),E=null,C&&(C.remove(),C=null),D&&(D.$destroy(),D=null)}function x(){L.title=d[k+"Title"],O?L.content=O(a):L.content=d[e],L.popupClass=d[k+"Class"],L.placement=angular.isDefined(d[k+"Placement"])?d[k+"Placement"]:o.placement;var b=parseInt(d[k+"PopupDelay"],10),c=parseInt(d[k+"PopupCloseDelay"],10);L.popupDelay=isNaN(b)?o.popupDelay:b,L.popupCloseDelay=isNaN(c)?o.popupCloseDelay:c}function y(b){N&&angular.isFunction(N.assign)&&N.assign(a,b)}function z(){P.length=0,O?(P.push(a.$watch(O,function(a){L.content=a,!a&&L.isOpen&&t()})),P.push(D.$watch(function(){M||(M=!0,D.$$postDigest(function(){M=!1,L&&L.isOpen&&Q()}))}))):P.push(d.$observe(e,function(a){L.content=a,!a&&L.isOpen?t():Q()})),P.push(d.$observe(k+"Title",function(a){L.title=a,L.isOpen&&Q()})),P.push(d.$observe(k+"Placement",function(a){L.placement=a?a:o.placement,L.isOpen&&Q()}))}function A(){P.length&&(angular.forEach(P,function(a){a()}),P.length=0)}function B(){var a=d[k+"Trigger"];R(),J=p(a),"none"!==J.show&&J.show.forEach(function(a,c){a===J.hide[c]?b[0].addEventListener(a,j):a&&(b[0].addEventListener(a,m),J.hide[c].split(" ").forEach(function(a){b[0].addEventListener(a,q)})),b.on("keypress",function(a){27===a.which&&q()})})}var C,D,E,F,G,H,I=angular.isDefined(o.appendToBody)?o.appendToBody:!1,J=p(void 0),K=angular.isDefined(d[k+"Enable"]),L=a.$new(!0),M=!1,N=angular.isDefined(d[k+"IsOpen"])?l(d[k+"IsOpen"]):!1,O=o.useContentExp?l(d[e]):!1,P=[],Q=function(){C&&C.html()&&(H||(H=g(function(){C.css({top:0,left:0});var a=i.positionElements(b,C,L.placement,I);a.top+="px",a.left+="px",a.visibility="visible",C.css(a),H=null},0,!1)))};L.origScope=a,L.isOpen=!1,n.add(L,{close:t}),L.contentExp=function(){return L.content},d.$observe("disabled",function(a){a&&s(),a&&L.isOpen&&t()}),N&&a.$watch(N,function(a){L&&!a===L.isOpen&&j()});var R=function(){J.show.forEach(function(a){b.unbind(a,m)}),J.hide.forEach(function(a){a.split(" ").forEach(function(a){b[0].removeEventListener(a,q)})})};B();var S=a.$eval(d[k+"Animation"]);L.animation=angular.isDefined(S)?!!S:o.animation;var T=a.$eval(d[k+"AppendToBody"]);I=angular.isDefined(T)?T:I,I&&a.$on("$locationChangeSuccess",function(){L.isOpen&&t()}),a.$on("$destroy",function(){s(),u(),R(),w(),n.remove(L),L=null})}}}}}]}).directive("uibTooltipTemplateTransclude",["$animate","$sce","$compile","$templateRequest",function(a,b,c,d){return{link:function(e,f,g){var h,i,j,k=e.$eval(g.tooltipTemplateTranscludeScope),l=0,m=function(){i&&(i.remove(),i=null),h&&(h.$destroy(),h=null),j&&(a.leave(j).then(function(){i=null}),i=j,j=null)};e.$watch(b.parseAsResourceUrl(g.uibTooltipTemplateTransclude),function(b){var g=++l;b?(d(b,!0).then(function(d){if(g===l){var e=k.$new(),i=d,n=c(i)(e,function(b){m(),a.enter(b,f)});h=e,j=n,h.$emit("$includeContentLoaded",b)}},function(){g===l&&(m(),e.$emit("$includeContentError",b))}),e.$emit("$includeContentRequested",b)):m()}),e.$on("$destroy",m)}}}]).directive("uibTooltipClasses",function(){return{restrict:"A",link:function(a,b,c){a.placement&&b.addClass(a.placement),a.popupClass&&b.addClass(a.popupClass),a.animation()&&b.addClass(c.tooltipAnimationClass)}}}).directive("uibTooltipPopup",function(){return{replace:!0,scope:{content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-popup.html",link:function(a,b){b.addClass("tooltip")}}}).directive("uibTooltip",["$uibTooltip",function(a){return a("uibTooltip","tooltip","mouseenter")}]).directive("uibTooltipTemplatePopup",function(){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/tooltip/tooltip-template-popup.html",link:function(a,b){b.addClass("tooltip")}}}).directive("uibTooltipTemplate",["$uibTooltip",function(a){return a("uibTooltipTemplate","tooltip","mouseenter",{useContentExp:!0})}]).directive("uibTooltipHtmlPopup",function(){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-html-popup.html",link:function(a,b){b.addClass("tooltip")}}}).directive("uibTooltipHtml",["$uibTooltip",function(a){return a("uibTooltipHtml","tooltip","mouseenter",{useContentExp:!0})}]),angular.module("ui.bootstrap.tooltip").value("$tooltipSuppressWarning",!1).provider("$tooltip",["$uibTooltipProvider",function(a){angular.extend(this,a),this.$get=["$log","$tooltipSuppressWarning","$injector",function(b,c,d){return c||b.warn("$tooltip is now deprecated. Use $uibTooltip instead."),d.invoke(a.$get)}]}]).directive("tooltipTemplateTransclude",["$animate","$sce","$compile","$templateRequest","$log","$tooltipSuppressWarning",function(a,b,c,d,e,f){return{link:function(g,h,i){f||e.warn("tooltip-template-transclude is now deprecated. Use uib-tooltip-template-transclude instead.");var j,k,l,m=g.$eval(i.tooltipTemplateTranscludeScope),n=0,o=function(){k&&(k.remove(),k=null),j&&(j.$destroy(),j=null),l&&(a.leave(l).then(function(){k=null}),k=l,l=null)};g.$watch(b.parseAsResourceUrl(i.tooltipTemplateTransclude),function(b){var e=++n;b?(d(b,!0).then(function(d){if(e===n){var f=m.$new(),g=d,i=c(g)(f,function(b){o(),a.enter(b,h)});j=f,l=i,j.$emit("$includeContentLoaded",b)}},function(){e===n&&(o(),g.$emit("$includeContentError",b))}),g.$emit("$includeContentRequested",b)):o()}),g.$on("$destroy",o)}}}]).directive("tooltipClasses",["$log","$tooltipSuppressWarning",function(a,b){return{restrict:"A",link:function(c,d,e){b||a.warn("tooltip-classes is now deprecated. Use uib-tooltip-classes instead."),c.placement&&d.addClass(c.placement),c.popupClass&&d.addClass(c.popupClass),c.animation()&&d.addClass(e.tooltipAnimationClass)}}}]).directive("tooltipPopup",["$log","$tooltipSuppressWarning",function(a,b){return{replace:!0,scope:{content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-popup.html",link:function(c,d){b||a.warn("tooltip-popup is now deprecated. Use uib-tooltip-popup instead."),d.addClass("tooltip")}}}]).directive("tooltip",["$tooltip",function(a){return a("tooltip","tooltip","mouseenter")}]).directive("tooltipTemplatePopup",["$log","$tooltipSuppressWarning",function(a,b){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/tooltip/tooltip-template-popup.html",link:function(c,d){b||a.warn("tooltip-template-popup is now deprecated. Use uib-tooltip-template-popup instead."),d.addClass("tooltip")}}}]).directive("tooltipTemplate",["$tooltip",function(a){return a("tooltipTemplate","tooltip","mouseenter",{useContentExp:!0})}]).directive("tooltipHtmlPopup",["$log","$tooltipSuppressWarning",function(a,b){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-html-popup.html",link:function(c,d){b||a.warn("tooltip-html-popup is now deprecated. Use uib-tooltip-html-popup instead."),d.addClass("tooltip")}}}]).directive("tooltipHtml",["$tooltip",function(a){return a("tooltipHtml","tooltip","mouseenter",{useContentExp:!0})}]),angular.module("ui.bootstrap.popover",["ui.bootstrap.tooltip"]).directive("uibPopoverTemplatePopup",function(){return{replace:!0,scope:{title:"@",contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/popover/popover-template.html",link:function(a,b){b.addClass("popover")}}}).directive("uibPopoverTemplate",["$uibTooltip",function(a){return a("uibPopoverTemplate","popover","click",{useContentExp:!0})}]).directive("uibPopoverHtmlPopup",function(){return{replace:!0,scope:{contentExp:"&",title:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover-html.html",link:function(a,b){b.addClass("popover")}}}).directive("uibPopoverHtml",["$uibTooltip",function(a){return a("uibPopoverHtml","popover","click",{useContentExp:!0})}]).directive("uibPopoverPopup",function(){return{replace:!0,scope:{title:"@",content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover.html",link:function(a,b){b.addClass("popover")}}}).directive("uibPopover",["$uibTooltip",function(a){return a("uibPopover","popover","click")}]),angular.module("ui.bootstrap.popover").value("$popoverSuppressWarning",!1).directive("popoverTemplatePopup",["$log","$popoverSuppressWarning",function(a,b){return{replace:!0,scope:{title:"@",contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/popover/popover-template.html",link:function(c,d){b||a.warn("popover-template-popup is now deprecated. Use uib-popover-template-popup instead."),d.addClass("popover")}}}]).directive("popoverTemplate",["$tooltip",function(a){return a("popoverTemplate","popover","click",{useContentExp:!0})}]).directive("popoverHtmlPopup",["$log","$popoverSuppressWarning",function(a,b){return{replace:!0,scope:{contentExp:"&",title:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover-html.html",link:function(c,d){b||a.warn("popover-html-popup is now deprecated. Use uib-popover-html-popup instead."),d.addClass("popover")}}}]).directive("popoverHtml",["$tooltip",function(a){return a("popoverHtml","popover","click",{useContentExp:!0})}]).directive("popoverPopup",["$log","$popoverSuppressWarning",function(a,b){return{replace:!0,scope:{title:"@",content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover.html",link:function(c,d){b||a.warn("popover-popup is now deprecated. Use uib-popover-popup instead."),d.addClass("popover")}}}]).directive("popover",["$tooltip",function(a){return a("popover","popover","click")}]),angular.module("ui.bootstrap.progressbar",[]).constant("uibProgressConfig",{animate:!0,max:100}).controller("UibProgressController",["$scope","$attrs","uibProgressConfig",function(a,b,c){var d=this,e=angular.isDefined(b.animate)?a.$parent.$eval(b.animate):c.animate;this.bars=[],a.max=angular.isDefined(a.max)?a.max:c.max,this.addBar=function(b,c,f){e||c.css({transition:"none"}),this.bars.push(b),b.max=a.max,b.title=f&&angular.isDefined(f.title)?f.title:"progressbar",b.$watch("value",function(a){b.recalculatePercentage()}),b.recalculatePercentage=function(){var a=d.bars.reduce(function(a,b){return b.percent=+(100*b.value/b.max).toFixed(2),a+b.percent},0);a>100&&(b.percent-=a-100)},b.$on("$destroy",function(){c=null,d.removeBar(b)})},this.removeBar=function(a){this.bars.splice(this.bars.indexOf(a),1),this.bars.forEach(function(a){a.recalculatePercentage()})},a.$watch("max",function(b){d.bars.forEach(function(b){b.max=a.max,b.recalculatePercentage()})})}]).directive("uibProgress",function(){return{replace:!0,transclude:!0,controller:"UibProgressController",require:"uibProgress",scope:{max:"=?"},templateUrl:"template/progressbar/progress.html"}}).directive("uibBar",function(){return{replace:!0,transclude:!0,require:"^uibProgress",scope:{value:"=",type:"@"},templateUrl:"template/progressbar/bar.html",link:function(a,b,c,d){d.addBar(a,b,c)}}}).directive("uibProgressbar",function(){return{replace:!0,transclude:!0,controller:"UibProgressController",scope:{value:"=",max:"=?",type:"@"},templateUrl:"template/progressbar/progressbar.html",link:function(a,b,c,d){d.addBar(a,angular.element(b.children()[0]),{title:c.title})}}}),angular.module("ui.bootstrap.progressbar").value("$progressSuppressWarning",!1).controller("ProgressController",["$scope","$attrs","uibProgressConfig","$log","$progressSuppressWarning",function(a,b,c,d,e){e||d.warn("ProgressController is now deprecated. Use UibProgressController instead.");var f=this,g=angular.isDefined(b.animate)?a.$parent.$eval(b.animate):c.animate;this.bars=[],a.max=angular.isDefined(a.max)?a.max:c.max,this.addBar=function(b,c,d){g||c.css({transition:"none"}),this.bars.push(b),b.max=a.max,b.title=d&&angular.isDefined(d.title)?d.title:"progressbar",b.$watch("value",function(a){b.recalculatePercentage()}),b.recalculatePercentage=function(){b.percent=+(100*b.value/b.max).toFixed(2);var a=f.bars.reduce(function(a,b){return a+b.percent},0);a>100&&(b.percent-=a-100)},b.$on("$destroy",function(){c=null,f.removeBar(b)})},this.removeBar=function(a){this.bars.splice(this.bars.indexOf(a),1)},a.$watch("max",function(b){f.bars.forEach(function(b){b.max=a.max,b.recalculatePercentage()})})}]).directive("progress",["$log","$progressSuppressWarning",function(a,b){return{replace:!0,transclude:!0,controller:"ProgressController",require:"progress",scope:{max:"=?",title:"@?"},templateUrl:"template/progressbar/progress.html",link:function(){b||a.warn("progress is now deprecated. Use uib-progress instead.")}}}]).directive("bar",["$log","$progressSuppressWarning",function(a,b){return{replace:!0,transclude:!0,require:"^progress",scope:{value:"=",type:"@"},templateUrl:"template/progressbar/bar.html",link:function(c,d,e,f){b||a.warn("bar is now deprecated. Use uib-bar instead."),f.addBar(c,d)}}}]).directive("progressbar",["$log","$progressSuppressWarning",function(a,b){return{replace:!0,transclude:!0,controller:"ProgressController",scope:{value:"=",max:"=?",type:"@"},templateUrl:"template/progressbar/progressbar.html",link:function(c,d,e,f){b||a.warn("progressbar is now deprecated. Use uib-progressbar instead."),f.addBar(c,angular.element(d.children()[0]),{title:e.title})}}}]),angular.module("ui.bootstrap.rating",[]).constant("uibRatingConfig",{max:5,stateOn:null,stateOff:null,titles:["one","two","three","four","five"]}).controller("UibRatingController",["$scope","$attrs","uibRatingConfig",function(a,b,c){var d={$setViewValue:angular.noop};this.init=function(e){d=e,d.$render=this.render,d.$formatters.push(function(a){return angular.isNumber(a)&&a<<0!==a&&(a=Math.round(a)),a}),this.stateOn=angular.isDefined(b.stateOn)?a.$parent.$eval(b.stateOn):c.stateOn,this.stateOff=angular.isDefined(b.stateOff)?a.$parent.$eval(b.stateOff):c.stateOff;var f=angular.isDefined(b.titles)?a.$parent.$eval(b.titles):c.titles;this.titles=angular.isArray(f)&&f.length>0?f:c.titles;var g=angular.isDefined(b.ratingStates)?a.$parent.$eval(b.ratingStates):new Array(angular.isDefined(b.max)?a.$parent.$eval(b.max):c.max);a.range=this.buildTemplateObjects(g)},this.buildTemplateObjects=function(a){for(var b=0,c=a.length;c>b;b++)a[b]=angular.extend({index:b},{stateOn:this.stateOn,stateOff:this.stateOff,title:this.getTitle(b)},a[b]);return a},this.getTitle=function(a){return a>=this.titles.length?a+1:this.titles[a]},a.rate=function(b){!a.readonly&&b>=0&&b<=a.range.length&&(d.$setViewValue(d.$viewValue===b?0:b),d.$render())},a.enter=function(b){a.readonly||(a.value=b),a.onHover({value:b})},a.reset=function(){a.value=d.$viewValue,a.onLeave()},a.onKeydown=function(b){/(37|38|39|40)/.test(b.which)&&(b.preventDefault(),b.stopPropagation(),a.rate(a.value+(38===b.which||39===b.which?1:-1)))},this.render=function(){a.value=d.$viewValue}}]).directive("uibRating",function(){return{require:["uibRating","ngModel"],scope:{readonly:"=?",onHover:"&",onLeave:"&"},controller:"UibRatingController",templateUrl:"template/rating/rating.html",replace:!0,link:function(a,b,c,d){var e=d[0],f=d[1];e.init(f)}}}),angular.module("ui.bootstrap.rating").value("$ratingSuppressWarning",!1).controller("RatingController",["$scope","$attrs","$controller","$log","$ratingSuppressWarning",function(a,b,c,d,e){e||d.warn("RatingController is now deprecated. Use UibRatingController instead."),angular.extend(this,c("UibRatingController",{$scope:a,$attrs:b}))}]).directive("rating",["$log","$ratingSuppressWarning",function(a,b){return{require:["rating","ngModel"],scope:{readonly:"=?",onHover:"&",onLeave:"&"},controller:"RatingController",templateUrl:"template/rating/rating.html",replace:!0,link:function(c,d,e,f){b||a.warn("rating is now deprecated. Use uib-rating instead.");var g=f[0],h=f[1];g.init(h)}}}]),angular.module("ui.bootstrap.tabs",[]).controller("UibTabsetController",["$scope",function(a){var b=this,c=b.tabs=a.tabs=[];b.select=function(a){angular.forEach(c,function(b){b.active&&b!==a&&(b.active=!1,b.onDeselect(),a.selectCalled=!1)}),a.active=!0,a.selectCalled||(a.onSelect(),a.selectCalled=!0)},b.addTab=function(a){c.push(a),1===c.length&&a.active!==!1?a.active=!0:a.active?b.select(a):a.active=!1},b.removeTab=function(a){var e=c.indexOf(a);if(a.active&&c.length>1&&!d){var f=e==c.length-1?e-1:e+1;b.select(c[f])}c.splice(e,1)};var d;a.$on("$destroy",function(){d=!0})}]).directive("uibTabset",function(){return{restrict:"EA",transclude:!0,replace:!0,scope:{type:"@"},controller:"UibTabsetController",templateUrl:"template/tabs/tabset.html",link:function(a,b,c){a.vertical=angular.isDefined(c.vertical)?a.$parent.$eval(c.vertical):!1,a.justified=angular.isDefined(c.justified)?a.$parent.$eval(c.justified):!1}}}).directive("uibTab",["$parse",function(a){return{require:"^uibTabset",restrict:"EA",replace:!0,templateUrl:"template/tabs/tab.html",transclude:!0,scope:{active:"=?",heading:"@",onSelect:"&select",onDeselect:"&deselect"},controller:function(){},link:function(b,c,d,e,f){b.$watch("active",function(a){a&&e.select(b)}),b.disabled=!1,d.disable&&b.$parent.$watch(a(d.disable),function(a){b.disabled=!!a}),b.select=function(){b.disabled||(b.active=!0)},e.addTab(b),b.$on("$destroy",function(){e.removeTab(b)}),b.$transcludeFn=f}}}]).directive("uibTabHeadingTransclude",function(){return{restrict:"A",require:["?^uibTab","?^tab"],link:function(a,b){a.$watch("headingElement",function(a){a&&(b.html(""),b.append(a))})}}}).directive("uibTabContentTransclude",function(){function a(a){return a.tagName&&(a.hasAttribute("tab-heading")||a.hasAttribute("data-tab-heading")||a.hasAttribute("x-tab-heading")||a.hasAttribute("uib-tab-heading")||a.hasAttribute("data-uib-tab-heading")||a.hasAttribute("x-uib-tab-heading")||"tab-heading"===a.tagName.toLowerCase()||"data-tab-heading"===a.tagName.toLowerCase()||"x-tab-heading"===a.tagName.toLowerCase()||"uib-tab-heading"===a.tagName.toLowerCase()||"data-uib-tab-heading"===a.tagName.toLowerCase()||"x-uib-tab-heading"===a.tagName.toLowerCase())}return{restrict:"A",require:["?^uibTabset","?^tabset"],link:function(b,c,d){var e=b.$eval(d.uibTabContentTransclude);e.$transcludeFn(e.$parent,function(b){angular.forEach(b,function(b){a(b)?e.headingElement=b:c.append(b)})})}}}),angular.module("ui.bootstrap.tabs").value("$tabsSuppressWarning",!1).controller("TabsetController",["$scope","$controller","$log","$tabsSuppressWarning",function(a,b,c,d){d||c.warn("TabsetController is now deprecated. Use UibTabsetController instead."),angular.extend(this,b("UibTabsetController",{$scope:a}))}]).directive("tabset",["$log","$tabsSuppressWarning",function(a,b){return{restrict:"EA",transclude:!0,replace:!0,scope:{type:"@"},controller:"TabsetController",templateUrl:"template/tabs/tabset.html",link:function(c,d,e){b||a.warn("tabset is now deprecated. Use uib-tabset instead."),c.vertical=angular.isDefined(e.vertical)?c.$parent.$eval(e.vertical):!1,c.justified=angular.isDefined(e.justified)?c.$parent.$eval(e.justified):!1}}}]).directive("tab",["$parse","$log","$tabsSuppressWarning",function(a,b,c){return{require:"^tabset",restrict:"EA",replace:!0,templateUrl:"template/tabs/tab.html",transclude:!0,scope:{active:"=?",heading:"@",onSelect:"&select",onDeselect:"&deselect"},controller:function(){},link:function(d,e,f,g,h){c||b.warn("tab is now deprecated. Use uib-tab instead."),d.$watch("active",function(a){a&&g.select(d)}),d.disabled=!1,f.disable&&d.$parent.$watch(a(f.disable),function(a){d.disabled=!!a}),d.select=function(){d.disabled||(d.active=!0)},g.addTab(d),d.$on("$destroy",function(){g.removeTab(d)}),d.$transcludeFn=h}}}]).directive("tabHeadingTransclude",["$log","$tabsSuppressWarning",function(a,b){return{restrict:"A",require:"^tab",link:function(c,d){b||a.warn("tab-heading-transclude is now deprecated. Use uib-tab-heading-transclude instead."),c.$watch("headingElement",function(a){a&&(d.html(""),d.append(a))})}}}]).directive("tabContentTransclude",["$log","$tabsSuppressWarning",function(a,b){function c(a){return a.tagName&&(a.hasAttribute("tab-heading")||a.hasAttribute("data-tab-heading")||a.hasAttribute("x-tab-heading")||"tab-heading"===a.tagName.toLowerCase()||"data-tab-heading"===a.tagName.toLowerCase()||"x-tab-heading"===a.tagName.toLowerCase())}return{restrict:"A",require:"^tabset",link:function(d,e,f){b||a.warn("tab-content-transclude is now deprecated. Use uib-tab-content-transclude instead.");var g=d.$eval(f.tabContentTransclude);g.$transcludeFn(g.$parent,function(a){angular.forEach(a,function(a){c(a)?g.headingElement=a:e.append(a)})})}}}]),angular.module("ui.bootstrap.timepicker",[]).constant("uibTimepickerConfig",{hourStep:1,minuteStep:1,showMeridian:!0,meridians:null,readonlyInput:!1,mousewheel:!0,arrowkeys:!0,showSpinners:!0}).controller("UibTimepickerController",["$scope","$element","$attrs","$parse","$log","$locale","uibTimepickerConfig",function(a,b,c,d,e,f,g){function h(){var b=parseInt(a.hours,10),c=a.showMeridian?b>0&&13>b:b>=0&&24>b;return c?(a.showMeridian&&(12===b&&(b=0),a.meridian===r[1]&&(b+=12)),b):void 0}function i(){var b=parseInt(a.minutes,10);return b>=0&&60>b?b:void 0}function j(a){return angular.isDefined(a)&&a.toString().length<2?"0"+a:a.toString()}function k(a){l(),q.$setViewValue(new Date(p)),m(a)}function l(){q.$setValidity("time",!0),a.invalidHours=!1,a.invalidMinutes=!1}function m(b){var c=p.getHours(),d=p.getMinutes();a.showMeridian&&(c=0===c||12===c?12:c%12),a.hours="h"===b?c:j(c),"m"!==b&&(a.minutes=j(d)),a.meridian=p.getHours()<12?r[0]:r[1]}function n(a,b){var c=new Date(a.getTime()+6e4*b),d=new Date(a);return d.setHours(c.getHours(),c.getMinutes()),d}function o(a){p=n(p,a),k()}var p=new Date,q={$setViewValue:angular.noop},r=angular.isDefined(c.meridians)?a.$parent.$eval(c.meridians):g.meridians||f.DATETIME_FORMATS.AMPMS;a.tabindex=angular.isDefined(c.tabindex)?c.tabindex:0,b.removeAttr("tabindex"),this.init=function(b,d){q=b,q.$render=this.render,q.$formatters.unshift(function(a){return a?new Date(a):null});var e=d.eq(0),f=d.eq(1),h=angular.isDefined(c.mousewheel)?a.$parent.$eval(c.mousewheel):g.mousewheel;h&&this.setupMousewheelEvents(e,f);var i=angular.isDefined(c.arrowkeys)?a.$parent.$eval(c.arrowkeys):g.arrowkeys;i&&this.setupArrowkeyEvents(e,f),a.readonlyInput=angular.isDefined(c.readonlyInput)?a.$parent.$eval(c.readonlyInput):g.readonlyInput,this.setupInputEvents(e,f)};var s=g.hourStep;c.hourStep&&a.$parent.$watch(d(c.hourStep),function(a){s=parseInt(a,10)});var t=g.minuteStep;c.minuteStep&&a.$parent.$watch(d(c.minuteStep),function(a){t=parseInt(a,10)});var u;a.$parent.$watch(d(c.min),function(a){var b=new Date(a);u=isNaN(b)?void 0:b});var v;a.$parent.$watch(d(c.max),function(a){var b=new Date(a);v=isNaN(b)?void 0:b}),a.noIncrementHours=function(){var a=n(p,60*s); +return a>v||p>a&&u>a},a.noDecrementHours=function(){var a=n(p,60*-s);return u>a||a>p&&a>v},a.noIncrementMinutes=function(){var a=n(p,t);return a>v||p>a&&u>a},a.noDecrementMinutes=function(){var a=n(p,-t);return u>a||a>p&&a>v},a.noToggleMeridian=function(){return p.getHours()<13?n(p,720)>v:n(p,-720)0};b.bind("mousewheel wheel",function(b){a.$apply(d(b)?a.incrementHours():a.decrementHours()),b.preventDefault()}),c.bind("mousewheel wheel",function(b){a.$apply(d(b)?a.incrementMinutes():a.decrementMinutes()),b.preventDefault()})},this.setupArrowkeyEvents=function(b,c){b.bind("keydown",function(b){38===b.which?(b.preventDefault(),a.incrementHours(),a.$apply()):40===b.which&&(b.preventDefault(),a.decrementHours(),a.$apply())}),c.bind("keydown",function(b){38===b.which?(b.preventDefault(),a.incrementMinutes(),a.$apply()):40===b.which&&(b.preventDefault(),a.decrementMinutes(),a.$apply())})},this.setupInputEvents=function(b,c){if(a.readonlyInput)return a.updateHours=angular.noop,void(a.updateMinutes=angular.noop);var d=function(b,c){q.$setViewValue(null),q.$setValidity("time",!1),angular.isDefined(b)&&(a.invalidHours=b),angular.isDefined(c)&&(a.invalidMinutes=c)};a.updateHours=function(){var a=h(),b=i();angular.isDefined(a)&&angular.isDefined(b)?(p.setHours(a),u>p||p>v?d(!0):k("h")):d(!0)},b.bind("blur",function(b){!a.invalidHours&&a.hours<10&&a.$apply(function(){a.hours=j(a.hours)})}),a.updateMinutes=function(){var a=i(),b=h();angular.isDefined(a)&&angular.isDefined(b)?(p.setMinutes(a),u>p||p>v?d(void 0,!0):k("m")):d(void 0,!0)},c.bind("blur",function(b){!a.invalidMinutes&&a.minutes<10&&a.$apply(function(){a.minutes=j(a.minutes)})})},this.render=function(){var b=q.$viewValue;isNaN(b)?(q.$setValidity("time",!1),e.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.')):(b&&(p=b),u>p||p>v?(q.$setValidity("time",!1),a.invalidHours=!0,a.invalidMinutes=!0):l(),m())},a.showSpinners=angular.isDefined(c.showSpinners)?a.$parent.$eval(c.showSpinners):g.showSpinners,a.incrementHours=function(){a.noIncrementHours()||o(60*s)},a.decrementHours=function(){a.noDecrementHours()||o(60*-s)},a.incrementMinutes=function(){a.noIncrementMinutes()||o(t)},a.decrementMinutes=function(){a.noDecrementMinutes()||o(-t)},a.toggleMeridian=function(){a.noToggleMeridian()||o(720*(p.getHours()<12?1:-1))}}]).directive("uibTimepicker",function(){return{restrict:"EA",require:["uibTimepicker","?^ngModel"],controller:"UibTimepickerController",controllerAs:"timepicker",replace:!0,scope:{},templateUrl:function(a,b){return b.templateUrl||"template/timepicker/timepicker.html"},link:function(a,b,c,d){var e=d[0],f=d[1];f&&e.init(f,b.find("input"))}}}),angular.module("ui.bootstrap.timepicker").value("$timepickerSuppressWarning",!1).controller("TimepickerController",["$scope","$element","$attrs","$controller","$log","$timepickerSuppressWarning",function(a,b,c,d,e,f){f||e.warn("TimepickerController is now deprecated. Use UibTimepickerController instead."),angular.extend(this,d("UibTimepickerController",{$scope:a,$element:b,$attrs:c}))}]).directive("timepicker",["$log","$timepickerSuppressWarning",function(a,b){return{restrict:"EA",require:["timepicker","?^ngModel"],controller:"TimepickerController",controllerAs:"timepicker",replace:!0,scope:{},templateUrl:function(a,b){return b.templateUrl||"template/timepicker/timepicker.html"},link:function(c,d,e,f){b||a.warn("timepicker is now deprecated. Use uib-timepicker instead.");var g=f[0],h=f[1];h&&g.init(h,d.find("input"))}}}]),angular.module("ui.bootstrap.typeahead",["ui.bootstrap.position"]).factory("uibTypeaheadParser",["$parse",function(a){var b=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;return{parse:function(c){var d=c.match(b);if(!d)throw new Error('Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_" but got "'+c+'".');return{itemName:d[3],source:a(d[4]),viewMapper:a(d[2]||d[1]),modelMapper:a(d[1])}}}}]).controller("UibTypeaheadController",["$scope","$element","$attrs","$compile","$parse","$q","$timeout","$document","$window","$rootScope","$uibPosition","uibTypeaheadParser",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(){K.moveInProgress||(K.moveInProgress=!0,K.$digest()),S&&g.cancel(S),S=g(function(){K.matches.length&&n(),K.moveInProgress=!1},r)}function n(){K.position=C?k.offset(b):k.position(b),K.position.top+=b.prop("offsetHeight")}var o,p,q=[9,13,27,38,40],r=200,s=a.$eval(c.typeaheadMinLength);s||0===s||(s=1);var t,u,v=a.$eval(c.typeaheadWaitMs)||0,w=a.$eval(c.typeaheadEditable)!==!1,x=e(c.typeaheadLoading).assign||angular.noop,y=e(c.typeaheadOnSelect),z=angular.isDefined(c.typeaheadSelectOnBlur)?a.$eval(c.typeaheadSelectOnBlur):!1,A=e(c.typeaheadNoResults).assign||angular.noop,B=c.typeaheadInputFormatter?e(c.typeaheadInputFormatter):void 0,C=c.typeaheadAppendToBody?a.$eval(c.typeaheadAppendToBody):!1,D=c.typeaheadAppendToElementId||!1,E=a.$eval(c.typeaheadFocusFirst)!==!1,F=c.typeaheadSelectOnExact?a.$eval(c.typeaheadSelectOnExact):!1,G=e(c.ngModel),H=e(c.ngModel+"($$$p)"),I=function(b,c){return angular.isFunction(G(a))&&p&&p.$options&&p.$options.getterSetter?H(b,{$$$p:c}):G.assign(b,c)},J=l.parse(c.uibTypeahead),K=a.$new(),L=a.$on("$destroy",function(){K.$destroy()});K.$on("$destroy",L);var M="typeahead-"+K.$id+"-"+Math.floor(1e4*Math.random());b.attr({"aria-autocomplete":"list","aria-expanded":!1,"aria-owns":M});var N=angular.element("
            ");N.attr({id:M,matches:"matches",active:"activeIdx",select:"select(activeIdx)","move-in-progress":"moveInProgress",query:"query",position:"position"}),angular.isDefined(c.typeaheadTemplateUrl)&&N.attr("template-url",c.typeaheadTemplateUrl),angular.isDefined(c.typeaheadPopupTemplateUrl)&&N.attr("popup-template-url",c.typeaheadPopupTemplateUrl);var O=function(){K.matches=[],K.activeIdx=-1,b.attr("aria-expanded",!1)},P=function(a){return M+"-option-"+a};K.$watch("activeIdx",function(a){0>a?b.removeAttr("aria-activedescendant"):b.attr("aria-activedescendant",P(a))});var Q=function(a,b){return K.matches.length>b&&a?a.toUpperCase()===K.matches[b].label.toUpperCase():!1},R=function(c){var d={$viewValue:c};x(a,!0),A(a,!1),f.when(J.source(a,d)).then(function(e){var f=c===o.$viewValue;if(f&&t)if(e&&e.length>0){K.activeIdx=E?0:-1,A(a,!1),K.matches.length=0;for(var g=0;g0?K.activeIdx:K.matches.length)-1,K.$digest()):13===a.which||9===a.which?K.$apply(function(){K.select(K.activeIdx)}):27===a.which&&(a.stopPropagation(),O(),K.$digest())}}),b.bind("blur",function(){z&&K.matches.length&&-1!==K.activeIdx&&!u&&(u=!0,K.$apply(function(){K.select(K.activeIdx)})),t=!1,u=!1});var W=function(a){b[0]!==a.target&&3!==a.which&&0!==K.matches.length&&(O(),j.$$phase||K.$digest())};h.bind("click",W),a.$on("$destroy",function(){h.unbind("click",W),(C||D)&&X.remove(),C&&(angular.element(i).unbind("resize",m),h.find("body").unbind("scroll",m)),N.remove()});var X=d(N)(K);C?h.find("body").append(X):D!==!1?angular.element(h[0].getElementById(D)).append(X):b.after(X),this.init=function(b,c){o=b,p=c,o.$parsers.unshift(function(b){return t=!0,0===s||b&&b.length>=s?v>0?(V(),U(b)):R(b):(x(a,!1),V(),O()),w?b:b?void o.$setValidity("editable",!1):(o.$setValidity("editable",!0),null)}),o.$formatters.push(function(b){var c,d,e={};return w||o.$setValidity("editable",!0),B?(e.$model=b,B(a,e)):(e[J.itemName]=b,c=J.viewMapper(a,e),e[J.itemName]=void 0,d=J.viewMapper(a,e),c!==d?c:b)})}}]).directive("uibTypeahead",function(){return{controller:"UibTypeaheadController",require:["ngModel","^?ngModelOptions","uibTypeahead"],link:function(a,b,c,d){d[2].init(d[0],d[1])}}}).directive("uibTypeaheadPopup",function(){return{scope:{matches:"=",query:"=",active:"=",position:"&",moveInProgress:"=",select:"&"},replace:!0,templateUrl:function(a,b){return b.popupTemplateUrl||"template/typeahead/typeahead-popup.html"},link:function(a,b,c){a.templateUrl=c.templateUrl,a.isOpen=function(){return a.matches.length>0},a.isActive=function(b){return a.active==b},a.selectActive=function(b){a.active=b},a.selectMatch=function(b){a.select({activeIdx:b})}}}}).directive("uibTypeaheadMatch",["$templateRequest","$compile","$parse",function(a,b,c){return{scope:{index:"=",match:"=",query:"="},link:function(d,e,f){var g=c(f.templateUrl)(d.$parent)||"template/typeahead/typeahead-match.html";a(g).then(function(a){b(a.trim())(d,function(a){e.replaceWith(a)})})}}}]).filter("uibTypeaheadHighlight",["$sce","$injector","$log",function(a,b,c){function d(a){return a.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}function e(a){return/<.*>/g.test(a)}var f;return f=b.has("$sanitize"),function(b,g){return!f&&e(b)&&c.warn("Unsafe use of typeahead please use ngSanitize"),b=g?(""+b).replace(new RegExp(d(g),"gi"),"$&"):b,f||(b=a.trustAsHtml(b)),b}}]),angular.module("ui.bootstrap.typeahead").value("$typeaheadSuppressWarning",!1).service("typeaheadParser",["$parse","uibTypeaheadParser","$log","$typeaheadSuppressWarning",function(a,b,c,d){return d||c.warn("typeaheadParser is now deprecated. Use uibTypeaheadParser instead."),b}]).directive("typeahead",["$compile","$parse","$q","$timeout","$document","$window","$rootScope","$uibPosition","typeaheadParser","$log","$typeaheadSuppressWarning",function(a,b,c,d,e,f,g,h,i,j,k){var l=[9,13,27,38,40],m=200;return{require:["ngModel","^?ngModelOptions"],link:function(n,o,p,q){function r(){N.moveInProgress||(N.moveInProgress=!0,N.$digest()),V&&d.cancel(V),V=d(function(){N.matches.length&&s(),N.moveInProgress=!1},m)}function s(){N.position=F?h.offset(o):h.position(o),N.position.top+=o.prop("offsetHeight")}k||j.warn("typeahead is now deprecated. Use uib-typeahead instead.");var t=q[0],u=q[1],v=n.$eval(p.typeaheadMinLength);v||0===v||(v=1);var w,x,y=n.$eval(p.typeaheadWaitMs)||0,z=n.$eval(p.typeaheadEditable)!==!1,A=b(p.typeaheadLoading).assign||angular.noop,B=b(p.typeaheadOnSelect),C=angular.isDefined(p.typeaheadSelectOnBlur)?n.$eval(p.typeaheadSelectOnBlur):!1,D=b(p.typeaheadNoResults).assign||angular.noop,E=p.typeaheadInputFormatter?b(p.typeaheadInputFormatter):void 0,F=p.typeaheadAppendToBody?n.$eval(p.typeaheadAppendToBody):!1,G=p.typeaheadAppendToElementId||!1,H=n.$eval(p.typeaheadFocusFirst)!==!1,I=p.typeaheadSelectOnExact?n.$eval(p.typeaheadSelectOnExact):!1,J=b(p.ngModel),K=b(p.ngModel+"($$$p)"),L=function(a,b){return angular.isFunction(J(n))&&u&&u.$options&&u.$options.getterSetter?K(a,{$$$p:b}):J.assign(a,b)},M=i.parse(p.typeahead),N=n.$new(),O=n.$on("$destroy",function(){N.$destroy()});N.$on("$destroy",O);var P="typeahead-"+N.$id+"-"+Math.floor(1e4*Math.random());o.attr({"aria-autocomplete":"list","aria-expanded":!1,"aria-owns":P});var Q=angular.element("
            ");Q.attr({id:P,matches:"matches",active:"activeIdx",select:"select(activeIdx)","move-in-progress":"moveInProgress",query:"query",position:"position"}),angular.isDefined(p.typeaheadTemplateUrl)&&Q.attr("template-url",p.typeaheadTemplateUrl),angular.isDefined(p.typeaheadPopupTemplateUrl)&&Q.attr("popup-template-url",p.typeaheadPopupTemplateUrl);var R=function(){N.matches=[],N.activeIdx=-1,o.attr("aria-expanded",!1)},S=function(a){return P+"-option-"+a};N.$watch("activeIdx",function(a){0>a?o.removeAttr("aria-activedescendant"):o.attr("aria-activedescendant",S(a))});var T=function(a,b){return N.matches.length>b&&a?a.toUpperCase()===N.matches[b].label.toUpperCase():!1},U=function(a){var b={$viewValue:a};A(n,!0),D(n,!1),c.when(M.source(n,b)).then(function(c){var d=a===t.$viewValue;if(d&&w)if(c&&c.length>0){N.activeIdx=H?0:-1,D(n,!1),N.matches.length=0;for(var e=0;e=v?y>0?(Y(),X(a)):U(a):(A(n,!1),Y(),R()),z?a:a?void t.$setValidity("editable",!1):(t.$setValidity("editable",!0),null)}),t.$formatters.push(function(a){var b,c,d={};return z||t.$setValidity("editable",!0),E?(d.$model=a,E(n,d)):(d[M.itemName]=a,b=M.viewMapper(n,d),d[M.itemName]=void 0,c=M.viewMapper(n,d),b!==c?b:a)}),N.select=function(a){var b,c,e={};x=!0,e[M.itemName]=c=N.matches[a].model,b=M.modelMapper(n,e),L(n,b),t.$setValidity("editable",!0),t.$setValidity("parse",!0),B(n,{$item:c,$model:b,$label:M.viewMapper(n,e)}),R(),N.$eval(p.typeaheadFocusOnSelect)!==!1&&d(function(){o[0].focus()},0,!1)},o.bind("keydown",function(a){if(0!==N.matches.length&&-1!==l.indexOf(a.which)){if(-1===N.activeIdx&&(9===a.which||13===a.which))return R(),void N.$digest();a.preventDefault(),40===a.which?(N.activeIdx=(N.activeIdx+1)%N.matches.length,N.$digest()):38===a.which?(N.activeIdx=(N.activeIdx>0?N.activeIdx:N.matches.length)-1,N.$digest()):13===a.which||9===a.which?N.$apply(function(){N.select(N.activeIdx)}):27===a.which&&(a.stopPropagation(),R(),N.$digest())}}),o.bind("blur",function(){C&&N.matches.length&&-1!==N.activeIdx&&!x&&(x=!0,N.$apply(function(){N.select(N.activeIdx)})),w=!1,x=!1});var Z=function(a){o[0]!==a.target&&3!==a.which&&0!==N.matches.length&&(R(),g.$$phase||N.$digest())};e.bind("click",Z),n.$on("$destroy",function(){e.unbind("click",Z),(F||G)&&$.remove(),F&&(angular.element(f).unbind("resize",r),e.find("body").unbind("scroll",r)),Q.remove()});var $=a(Q)(N);F?e.find("body").append($):G!==!1?angular.element(e[0].getElementById(G)).append($):o.after($)}}}]).directive("typeaheadPopup",["$typeaheadSuppressWarning","$log",function(a,b){return{scope:{matches:"=",query:"=",active:"=",position:"&",moveInProgress:"=",select:"&"},replace:!0,templateUrl:function(a,b){return b.popupTemplateUrl||"template/typeahead/typeahead-popup.html"},link:function(c,d,e){a||b.warn("typeahead-popup is now deprecated. Use uib-typeahead-popup instead."),c.templateUrl=e.templateUrl,c.isOpen=function(){return c.matches.length>0},c.isActive=function(a){return c.active==a},c.selectActive=function(a){c.active=a},c.selectMatch=function(a){c.select({activeIdx:a})}}}}]).directive("typeaheadMatch",["$templateRequest","$compile","$parse","$typeaheadSuppressWarning","$log",function(a,b,c,d,e){return{restrict:"EA",scope:{index:"=",match:"=",query:"="},link:function(f,g,h){d||e.warn("typeahead-match is now deprecated. Use uib-typeahead-match instead.");var i=c(h.templateUrl)(f.$parent)||"template/typeahead/typeahead-match.html";a(i).then(function(a){b(a.trim())(f,function(a){g.replaceWith(a)})})}}}]).filter("typeaheadHighlight",["$sce","$injector","$log","$typeaheadSuppressWarning",function(a,b,c,d){function e(a){return a.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}function f(a){return/<.*>/g.test(a)}var g;return g=b.has("$sanitize"),function(b,h){return d||c.warn("typeaheadHighlight is now deprecated. Use uibTypeaheadHighlight instead."),!g&&f(b)&&c.warn("Unsafe use of typeahead please use ngSanitize"),b=h?(""+b).replace(new RegExp(e(h),"gi"),"$&"):b,g||(b=a.trustAsHtml(b)),b}}]),angular.module("template/accordion/accordion-group.html",[]).run(["$templateCache",function(a){a.put("template/accordion/accordion-group.html",'
            \n
            \n

            \n {{heading}}\n

            \n
            \n
            \n
            \n
            \n
            \n')}]),angular.module("template/accordion/accordion.html",[]).run(["$templateCache",function(a){a.put("template/accordion/accordion.html",'
            ')}]),angular.module("template/alert/alert.html",[]).run(["$templateCache",function(a){a.put("template/alert/alert.html",'\n')}]),angular.module("template/carousel/carousel.html",[]).run(["$templateCache",function(a){a.put("template/carousel/carousel.html",'')}]),angular.module("template/carousel/slide.html",[]).run(["$templateCache",function(a){a.put("template/carousel/slide.html",'
            \n')}]),angular.module("template/datepicker/datepicker.html",[]).run(["$templateCache",function(a){a.put("template/datepicker/datepicker.html",'
            \n \n \n \n
            ')}]),angular.module("template/datepicker/day.html",[]).run(["$templateCache",function(a){a.put("template/datepicker/day.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
            {{::label.abbr}}
            {{ weekNumbers[$index] }}\n \n
            \n')}]),angular.module("template/datepicker/month.html",[]).run(["$templateCache",function(a){a.put("template/datepicker/month.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n
            \n \n
            \n')}]),angular.module("template/datepicker/popup.html",[]).run(["$templateCache",function(a){a.put("template/datepicker/popup.html",'\n')}]),angular.module("template/datepicker/year.html",[]).run(["$templateCache",function(a){a.put("template/datepicker/year.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n
            \n \n
            \n')}]),angular.module("template/modal/backdrop.html",[]).run(["$templateCache",function(a){a.put("template/modal/backdrop.html",'
            \n')}]),angular.module("template/modal/window.html",[]).run(["$templateCache",function(a){a.put("template/modal/window.html",'\n')}]),angular.module("template/pagination/pager.html",[]).run(["$templateCache",function(a){a.put("template/pagination/pager.html",'\n')}]),angular.module("template/pagination/pagination.html",[]).run(["$templateCache",function(a){a.put("template/pagination/pagination.html",'\n')}]),angular.module("template/tooltip/tooltip-html-popup.html",[]).run(["$templateCache",function(a){a.put("template/tooltip/tooltip-html-popup.html",'\n
            \n
            \n
            \n')}]),angular.module("template/tooltip/tooltip-popup.html",[]).run(["$templateCache",function(a){a.put("template/tooltip/tooltip-popup.html",'\n
            \n
            \n
          \n')}]),angular.module("template/tooltip/tooltip-template-popup.html",[]).run(["$templateCache",function(a){a.put("template/tooltip/tooltip-template-popup.html",'\n
          \n
          \n
        \n')}]),angular.module("template/popover/popover-html.html",[]).run(["$templateCache",function(a){a.put("template/popover/popover-html.html",'
        \n
        \n\n
        \n

        \n
        \n
        \n
        \n')}]),angular.module("template/popover/popover-template.html",[]).run(["$templateCache",function(a){a.put("template/popover/popover-template.html",'
        \n
        \n\n
        \n

        \n
        \n
        \n
        \n')}]),angular.module("template/popover/popover.html",[]).run(["$templateCache",function(a){a.put("template/popover/popover.html",'
        \n
        \n\n
        \n

        \n
        \n
        \n
        \n')}]),angular.module("template/progressbar/bar.html",[]).run(["$templateCache",function(a){a.put("template/progressbar/bar.html",'
        \n')}]),angular.module("template/progressbar/progress.html",[]).run(["$templateCache",function(a){a.put("template/progressbar/progress.html",'
        ')}]),angular.module("template/progressbar/progressbar.html",[]).run(["$templateCache",function(a){a.put("template/progressbar/progressbar.html",'
        \n
        \n
        \n')}]),angular.module("template/rating/rating.html",[]).run(["$templateCache",function(a){a.put("template/rating/rating.html",'\n ({{ $index < value ? \'*\' : \' \' }})\n \n\n'); +}]),angular.module("template/tabs/tab.html",[]).run(["$templateCache",function(a){a.put("template/tabs/tab.html",'
      2. \n {{heading}}\n
      3. \n')}]),angular.module("template/tabs/tabset.html",[]).run(["$templateCache",function(a){a.put("template/tabs/tabset.html",'
        \n \n
        \n
        \n
        \n
        \n
        \n')}]),angular.module("template/timepicker/timepicker.html",[]).run(["$templateCache",function(a){a.put("template/timepicker/timepicker.html",'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
         
        \n \n :\n \n
         
        \n')}]),angular.module("template/typeahead/typeahead-match.html",[]).run(["$templateCache",function(a){a.put("template/typeahead/typeahead-match.html",'\n')}]),angular.module("template/typeahead/typeahead-popup.html",[]).run(["$templateCache",function(a){a.put("template/typeahead/typeahead-popup.html",'\n')}]),!angular.$$csp()&&angular.element(document).find("head").prepend(''); \ No newline at end of file diff --git a/bower_components/angular-bootstrap/ui-bootstrap.min.js b/bower_components/angular-bootstrap/ui-bootstrap.min.js new file mode 100644 index 00000000..cbabc328 --- /dev/null +++ b/bower_components/angular-bootstrap/ui-bootstrap.min.js @@ -0,0 +1,11 @@ +/* + * angular-ui-bootstrap + * http://angular-ui.github.io/bootstrap/ + + * Version: 0.14.3 - 2015-10-23 + * License: MIT + */ +angular.module("ui.bootstrap",["ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.stackedMap","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]),angular.module("ui.bootstrap.collapse",[]).directive("uibCollapse",["$animate","$injector",function(a,b){var c=b.has("$animateCss")?b.get("$animateCss"):null;return{link:function(b,d,e){function f(){d.removeClass("collapse").addClass("collapsing").attr("aria-expanded",!0).attr("aria-hidden",!1),c?c(d,{addClass:"in",easing:"ease",to:{height:d[0].scrollHeight+"px"}}).start()["finally"](g):a.addClass(d,"in",{to:{height:d[0].scrollHeight+"px"}}).then(g)}function g(){d.removeClass("collapsing").addClass("collapse").css({height:"auto"})}function h(){return d.hasClass("collapse")||d.hasClass("in")?(d.css({height:d[0].scrollHeight+"px"}).removeClass("collapse").addClass("collapsing").attr("aria-expanded",!1).attr("aria-hidden",!0),void(c?c(d,{removeClass:"in",to:{height:"0"}}).start()["finally"](i):a.removeClass(d,"in",{to:{height:"0"}}).then(i))):i()}function i(){d.css({height:"0"}),d.removeClass("collapsing").addClass("collapse")}b.$watch(e.uibCollapse,function(a){a?h():f()})}}}]),angular.module("ui.bootstrap.collapse").value("$collapseSuppressWarning",!1).directive("collapse",["$animate","$injector","$log","$collapseSuppressWarning",function(a,b,c,d){var e=b.has("$animateCss")?b.get("$animateCss"):null;return{link:function(b,f,g){function h(){f.removeClass("collapse").addClass("collapsing").attr("aria-expanded",!0).attr("aria-hidden",!1),e?e(f,{easing:"ease",to:{height:f[0].scrollHeight+"px"}}).start().done(i):a.animate(f,{},{height:f[0].scrollHeight+"px"}).then(i)}function i(){f.removeClass("collapsing").addClass("collapse in").css({height:"auto"})}function j(){return f.hasClass("collapse")||f.hasClass("in")?(f.css({height:f[0].scrollHeight+"px"}).removeClass("collapse in").addClass("collapsing").attr("aria-expanded",!1).attr("aria-hidden",!0),void(e?e(f,{to:{height:"0"}}).start().done(k):a.animate(f,{},{height:"0"}).then(k))):k()}function k(){f.css({height:"0"}),f.removeClass("collapsing").addClass("collapse")}d||c.warn("collapse is now deprecated. Use uib-collapse instead."),b.$watch(g.collapse,function(a){a?j():h()})}}}]),angular.module("ui.bootstrap.accordion",["ui.bootstrap.collapse"]).constant("uibAccordionConfig",{closeOthers:!0}).controller("UibAccordionController",["$scope","$attrs","uibAccordionConfig",function(a,b,c){this.groups=[],this.closeOthers=function(d){var e=angular.isDefined(b.closeOthers)?a.$eval(b.closeOthers):c.closeOthers;e&&angular.forEach(this.groups,function(a){a!==d&&(a.isOpen=!1)})},this.addGroup=function(a){var b=this;this.groups.push(a),a.$on("$destroy",function(c){b.removeGroup(a)})},this.removeGroup=function(a){var b=this.groups.indexOf(a);-1!==b&&this.groups.splice(b,1)}}]).directive("uibAccordion",function(){return{controller:"UibAccordionController",controllerAs:"accordion",transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion.html"}}}).directive("uibAccordionGroup",function(){return{require:"^uibAccordion",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion-group.html"},scope:{heading:"@",isOpen:"=?",isDisabled:"=?"},controller:function(){this.setHeading=function(a){this.heading=a}},link:function(a,b,c,d){d.addGroup(a),a.openClass=c.openClass||"panel-open",a.panelClass=c.panelClass,a.$watch("isOpen",function(c){b.toggleClass(a.openClass,!!c),c&&d.closeOthers(a)}),a.toggleOpen=function(b){a.isDisabled||b&&32!==b.which||(a.isOpen=!a.isOpen)}}}}).directive("uibAccordionHeading",function(){return{transclude:!0,template:"",replace:!0,require:"^uibAccordionGroup",link:function(a,b,c,d,e){d.setHeading(e(a,angular.noop))}}}).directive("uibAccordionTransclude",function(){return{require:["?^uibAccordionGroup","?^accordionGroup"],link:function(a,b,c,d){d=d[0]?d[0]:d[1],a.$watch(function(){return d[c.uibAccordionTransclude]},function(a){a&&(b.find("span").html(""),b.find("span").append(a))})}}}),angular.module("ui.bootstrap.accordion").value("$accordionSuppressWarning",!1).controller("AccordionController",["$scope","$attrs","$controller","$log","$accordionSuppressWarning",function(a,b,c,d,e){e||d.warn("AccordionController is now deprecated. Use UibAccordionController instead."),angular.extend(this,c("UibAccordionController",{$scope:a,$attrs:b}))}]).directive("accordion",["$log","$accordionSuppressWarning",function(a,b){return{restrict:"EA",controller:"AccordionController",controllerAs:"accordion",transclude:!0,replace:!1,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion.html"},link:function(){b||a.warn("accordion is now deprecated. Use uib-accordion instead.")}}}]).directive("accordionGroup",["$log","$accordionSuppressWarning",function(a,b){return{require:"^accordion",restrict:"EA",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/accordion/accordion-group.html"},scope:{heading:"@",isOpen:"=?",isDisabled:"=?"},controller:function(){this.setHeading=function(a){this.heading=a}},link:function(c,d,e,f){b||a.warn("accordion-group is now deprecated. Use uib-accordion-group instead."),f.addGroup(c),c.openClass=e.openClass||"panel-open",c.panelClass=e.panelClass,c.$watch("isOpen",function(a){d.toggleClass(c.openClass,!!a),a&&f.closeOthers(c)}),c.toggleOpen=function(a){c.isDisabled||a&&32!==a.which||(c.isOpen=!c.isOpen)}}}}]).directive("accordionHeading",["$log","$accordionSuppressWarning",function(a,b){return{restrict:"EA",transclude:!0,template:"",replace:!0,require:"^accordionGroup",link:function(c,d,e,f,g){b||a.warn("accordion-heading is now deprecated. Use uib-accordion-heading instead."),f.setHeading(g(c,angular.noop))}}}]).directive("accordionTransclude",["$log","$accordionSuppressWarning",function(a,b){return{require:"^accordionGroup",link:function(c,d,e,f){b||a.warn("accordion-transclude is now deprecated. Use uib-accordion-transclude instead."),c.$watch(function(){return f[e.accordionTransclude]},function(a){a&&(d.find("span").html(""),d.find("span").append(a))})}}}]),angular.module("ui.bootstrap.alert",[]).controller("UibAlertController",["$scope","$attrs","$interpolate","$timeout",function(a,b,c,d){a.closeable=!!b.close;var e=angular.isDefined(b.dismissOnTimeout)?c(b.dismissOnTimeout)(a.$parent):null;e&&d(function(){a.close()},parseInt(e,10))}]).directive("uibAlert",function(){return{controller:"UibAlertController",controllerAs:"alert",templateUrl:function(a,b){return b.templateUrl||"template/alert/alert.html"},transclude:!0,replace:!0,scope:{type:"@",close:"&"}}}),angular.module("ui.bootstrap.alert").value("$alertSuppressWarning",!1).controller("AlertController",["$scope","$attrs","$controller","$log","$alertSuppressWarning",function(a,b,c,d,e){e||d.warn("AlertController is now deprecated. Use UibAlertController instead."),angular.extend(this,c("UibAlertController",{$scope:a,$attrs:b}))}]).directive("alert",["$log","$alertSuppressWarning",function(a,b){return{controller:"AlertController",controllerAs:"alert",templateUrl:function(a,b){return b.templateUrl||"template/alert/alert.html"},transclude:!0,replace:!0,scope:{type:"@",close:"&"},link:function(){b||a.warn("alert is now deprecated. Use uib-alert instead.")}}}]),angular.module("ui.bootstrap.buttons",[]).constant("uibButtonConfig",{activeClass:"active",toggleEvent:"click"}).controller("UibButtonsController",["uibButtonConfig",function(a){this.activeClass=a.activeClass||"active",this.toggleEvent=a.toggleEvent||"click"}]).directive("uibBtnRadio",function(){return{require:["uibBtnRadio","ngModel"],controller:"UibButtonsController",controllerAs:"buttons",link:function(a,b,c,d){var e=d[0],f=d[1];b.find("input").css({display:"none"}),f.$render=function(){b.toggleClass(e.activeClass,angular.equals(f.$modelValue,a.$eval(c.uibBtnRadio)))},b.on(e.toggleEvent,function(){if(!c.disabled){var d=b.hasClass(e.activeClass);(!d||angular.isDefined(c.uncheckable))&&a.$apply(function(){f.$setViewValue(d?null:a.$eval(c.uibBtnRadio)),f.$render()})}})}}}).directive("uibBtnCheckbox",function(){return{require:["uibBtnCheckbox","ngModel"],controller:"UibButtonsController",controllerAs:"button",link:function(a,b,c,d){function e(){return g(c.btnCheckboxTrue,!0)}function f(){return g(c.btnCheckboxFalse,!1)}function g(b,c){return angular.isDefined(b)?a.$eval(b):c}var h=d[0],i=d[1];b.find("input").css({display:"none"}),i.$render=function(){b.toggleClass(h.activeClass,angular.equals(i.$modelValue,e()))},b.on(h.toggleEvent,function(){c.disabled||a.$apply(function(){i.$setViewValue(b.hasClass(h.activeClass)?f():e()),i.$render()})})}}}),angular.module("ui.bootstrap.buttons").value("$buttonsSuppressWarning",!1).controller("ButtonsController",["$controller","$log","$buttonsSuppressWarning",function(a,b,c){c||b.warn("ButtonsController is now deprecated. Use UibButtonsController instead."),angular.extend(this,a("UibButtonsController"))}]).directive("btnRadio",["$log","$buttonsSuppressWarning",function(a,b){return{require:["btnRadio","ngModel"],controller:"ButtonsController",controllerAs:"buttons",link:function(c,d,e,f){b||a.warn("btn-radio is now deprecated. Use uib-btn-radio instead.");var g=f[0],h=f[1];d.find("input").css({display:"none"}),h.$render=function(){d.toggleClass(g.activeClass,angular.equals(h.$modelValue,c.$eval(e.btnRadio)))},d.bind(g.toggleEvent,function(){if(!e.disabled){var a=d.hasClass(g.activeClass);(!a||angular.isDefined(e.uncheckable))&&c.$apply(function(){h.$setViewValue(a?null:c.$eval(e.btnRadio)),h.$render()})}})}}}]).directive("btnCheckbox",["$document","$log","$buttonsSuppressWarning",function(a,b,c){return{require:["btnCheckbox","ngModel"],controller:"ButtonsController",controllerAs:"button",link:function(d,e,f,g){function h(){return j(f.btnCheckboxTrue,!0)}function i(){return j(f.btnCheckboxFalse,!1)}function j(a,b){var c=d.$eval(a);return angular.isDefined(c)?c:b}c||b.warn("btn-checkbox is now deprecated. Use uib-btn-checkbox instead.");var k=g[0],l=g[1];e.find("input").css({display:"none"}),l.$render=function(){e.toggleClass(k.activeClass,angular.equals(l.$modelValue,h()))},e.bind(k.toggleEvent,function(){f.disabled||d.$apply(function(){l.$setViewValue(e.hasClass(k.activeClass)?i():h()),l.$render()})}),e.on("keypress",function(b){f.disabled||32!==b.which||a[0].activeElement!==e[0]||d.$apply(function(){l.$setViewValue(e.hasClass(k.activeClass)?i():h()),l.$render()})})}}}]),angular.module("ui.bootstrap.carousel",[]).controller("UibCarouselController",["$scope","$element","$interval","$animate",function(a,b,c,d){function e(b,c,e){s||(angular.extend(b,{direction:e,active:!0}),angular.extend(m.currentSlide||{},{direction:e,active:!1}),d.enabled()&&!a.noTransition&&!a.$currentTransition&&b.$element&&m.slides.length>1&&(b.$element.data(q,b.direction),m.currentSlide&&m.currentSlide.$element&&m.currentSlide.$element.data(q,b.direction),a.$currentTransition=!0,o?d.on("addClass",b.$element,function(b,c){"close"===c&&(a.$currentTransition=null,d.off("addClass",b))}):b.$element.one("$animate:close",function(){a.$currentTransition=null})),m.currentSlide=b,r=c,g())}function f(a){if(angular.isUndefined(n[a].index))return n[a];var b;n.length;for(b=0;b0&&(k=c(i,b))}function h(){k&&(c.cancel(k),k=null)}function i(){var b=+a.interval;l&&!isNaN(b)&&b>0&&n.length?a.next():a.pause()}function j(b){b.length||(a.$currentTransition=null)}var k,l,m=this,n=m.slides=a.slides=[],o=angular.version.minor>=4,p="uib-noTransition",q="uib-slideDirection",r=-1;m.currentSlide=null;var s=!1;m.select=a.select=function(b,c){var d=a.indexOfSlide(b);void 0===c&&(c=d>m.getCurrentIndex()?"next":"prev"),b&&b!==m.currentSlide&&!a.$currentTransition&&e(b,d,c)},a.$on("$destroy",function(){s=!0}),m.getCurrentIndex=function(){return m.currentSlide&&angular.isDefined(m.currentSlide.index)?+m.currentSlide.index:r},a.indexOfSlide=function(a){return angular.isDefined(a.index)?+a.index:n.indexOf(a)},a.next=function(){var b=(m.getCurrentIndex()+1)%n.length;return 0===b&&a.noWrap()?void a.pause():m.select(f(b),"next")},a.prev=function(){var b=m.getCurrentIndex()-1<0?n.length-1:m.getCurrentIndex()-1;return a.noWrap()&&b===n.length-1?void a.pause():m.select(f(b),"prev")},a.isActive=function(a){return m.currentSlide===a},a.$watch("interval",g),a.$watchCollection("slides",j),a.$on("$destroy",h),a.play=function(){l||(l=!0,g())},a.pause=function(){a.noPause||(l=!1,h())},m.addSlide=function(b,c){b.$element=c,n.push(b),1===n.length||b.active?(m.select(n[n.length-1]),1===n.length&&a.play()):b.active=!1},m.removeSlide=function(a){angular.isDefined(a.index)&&n.sort(function(a,b){return+a.index>+b.index});var b=n.indexOf(a);n.splice(b,1),n.length>0&&a.active?b>=n.length?m.select(n[b-1]):m.select(n[b]):r>b&&r--,0===n.length&&(m.currentSlide=null)},a.$watch("noTransition",function(a){b.data(p,a)})}]).directive("uibCarousel",[function(){return{transclude:!0,replace:!0,controller:"UibCarouselController",controllerAs:"carousel",require:"carousel",templateUrl:function(a,b){return b.templateUrl||"template/carousel/carousel.html"},scope:{interval:"=",noTransition:"=",noPause:"=",noWrap:"&"}}}]).directive("uibSlide",function(){return{require:"^uibCarousel",restrict:"EA",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/carousel/slide.html"},scope:{active:"=?",actual:"=?",index:"=?"},link:function(a,b,c,d){d.addSlide(a,b),a.$on("$destroy",function(){d.removeSlide(a)}),a.$watch("active",function(b){b&&d.select(a)})}}}).animation(".item",["$injector","$animate",function(a,b){function c(a,b,c){a.removeClass(b),c&&c()}var d="uib-noTransition",e="uib-slideDirection",f=null;return a.has("$animateCss")&&(f=a.get("$animateCss")),{beforeAddClass:function(a,g,h){if("active"==g&&a.parent()&&a.parent().parent()&&!a.parent().parent().data(d)){var i=!1,j=a.data(e),k="next"==j?"left":"right",l=c.bind(this,a,k+" "+j,h);return a.addClass(j),f?f(a,{addClass:k}).start().done(l):b.addClass(a,k).then(function(){i||l(),h()}),function(){i=!0}}h()},beforeRemoveClass:function(a,g,h){if("active"===g&&a.parent()&&a.parent().parent()&&!a.parent().parent().data(d)){var i=!1,j=a.data(e),k="next"==j?"left":"right",l=c.bind(this,a,k,h);return f?f(a,{addClass:k}).start().done(l):b.addClass(a,k).then(function(){i||l(),h()}),function(){i=!0}}h()}}}]),angular.module("ui.bootstrap.carousel").value("$carouselSuppressWarning",!1).controller("CarouselController",["$scope","$element","$controller","$log","$carouselSuppressWarning",function(a,b,c,d,e){e||d.warn("CarouselController is now deprecated. Use UibCarouselController instead."),angular.extend(this,c("UibCarouselController",{$scope:a,$element:b}))}]).directive("carousel",["$log","$carouselSuppressWarning",function(a,b){return{transclude:!0,replace:!0,controller:"CarouselController",controllerAs:"carousel",require:"carousel",templateUrl:function(a,b){return b.templateUrl||"template/carousel/carousel.html"},scope:{interval:"=",noTransition:"=",noPause:"=",noWrap:"&"},link:function(){b||a.warn("carousel is now deprecated. Use uib-carousel instead.")}}}]).directive("slide",["$log","$carouselSuppressWarning",function(a,b){return{require:"^carousel",transclude:!0,replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/carousel/slide.html"},scope:{active:"=?",actual:"=?",index:"=?"},link:function(c,d,e,f){b||a.warn("slide is now deprecated. Use uib-slide instead."),f.addSlide(c,d),c.$on("$destroy",function(){f.removeSlide(c)}),c.$watch("active",function(a){a&&f.select(c)})}}}]),angular.module("ui.bootstrap.dateparser",[]).service("uibDateParser",["$log","$locale","orderByFilter",function(a,b,c){function d(a){var b=[],d=a.split("");return angular.forEach(g,function(c,e){var f=a.indexOf(e);if(f>-1){a=a.split(""),d[f]="("+c.regex+")",a[f]="$";for(var g=f+1,h=f+e.length;h>g;g++)d[g]="",a[g]="$";a=a.join(""),b.push({index:f,apply:c.apply})}}),{regex:new RegExp("^"+d.join("")+"$"),map:c(b,"index")}}function e(a,b,c){return 1>c?!1:1===b&&c>28?29===c&&(a%4===0&&a%100!==0||a%400===0):3===b||5===b||8===b||10===b?31>c:!0}var f,g,h=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;this.init=function(){f=b.id,this.parsers={},g={yyyy:{regex:"\\d{4}",apply:function(a){this.year=+a}},yy:{regex:"\\d{2}",apply:function(a){this.year=+a+2e3}},y:{regex:"\\d{1,4}",apply:function(a){this.year=+a}},MMMM:{regex:b.DATETIME_FORMATS.MONTH.join("|"),apply:function(a){this.month=b.DATETIME_FORMATS.MONTH.indexOf(a)}},MMM:{regex:b.DATETIME_FORMATS.SHORTMONTH.join("|"),apply:function(a){this.month=b.DATETIME_FORMATS.SHORTMONTH.indexOf(a)}},MM:{regex:"0[1-9]|1[0-2]",apply:function(a){this.month=a-1}},M:{regex:"[1-9]|1[0-2]",apply:function(a){this.month=a-1}},dd:{regex:"[0-2][0-9]{1}|3[0-1]{1}",apply:function(a){this.date=+a}},d:{regex:"[1-2]?[0-9]{1}|3[0-1]{1}",apply:function(a){this.date=+a}},EEEE:{regex:b.DATETIME_FORMATS.DAY.join("|")},EEE:{regex:b.DATETIME_FORMATS.SHORTDAY.join("|")},HH:{regex:"(?:0|1)[0-9]|2[0-3]",apply:function(a){this.hours=+a}},hh:{regex:"0[0-9]|1[0-2]",apply:function(a){this.hours=+a}},H:{regex:"1?[0-9]|2[0-3]",apply:function(a){this.hours=+a}},h:{regex:"[0-9]|1[0-2]",apply:function(a){this.hours=+a}},mm:{regex:"[0-5][0-9]",apply:function(a){this.minutes=+a}},m:{regex:"[0-9]|[1-5][0-9]",apply:function(a){this.minutes=+a}},sss:{regex:"[0-9][0-9][0-9]",apply:function(a){this.milliseconds=+a}},ss:{regex:"[0-5][0-9]",apply:function(a){this.seconds=+a}},s:{regex:"[0-9]|[1-5][0-9]",apply:function(a){this.seconds=+a}},a:{regex:b.DATETIME_FORMATS.AMPMS.join("|"),apply:function(a){12===this.hours&&(this.hours=0),"PM"===a&&(this.hours+=12)}}}},this.init(),this.parse=function(c,g,i){if(!angular.isString(c)||!g)return c;g=b.DATETIME_FORMATS[g]||g,g=g.replace(h,"\\$&"),b.id!==f&&this.init(),this.parsers[g]||(this.parsers[g]=d(g));var j=this.parsers[g],k=j.regex,l=j.map,m=c.match(k);if(m&&m.length){var n,o;angular.isDate(i)&&!isNaN(i.getTime())?n={year:i.getFullYear(),month:i.getMonth(),date:i.getDate(),hours:i.getHours(),minutes:i.getMinutes(),seconds:i.getSeconds(),milliseconds:i.getMilliseconds()}:(i&&a.warn("dateparser:","baseDate is not a valid date"),n={year:1900,month:0,date:1,hours:0,minutes:0,seconds:0,milliseconds:0});for(var p=1,q=m.length;q>p;p++){var r=l[p-1];r.apply&&r.apply.call(n,m[p])}return e(n.year,n.month,n.date)&&(angular.isDate(i)&&!isNaN(i.getTime())?(o=new Date(i),o.setFullYear(n.year,n.month,n.date,n.hours,n.minutes,n.seconds,n.milliseconds||0)):o=new Date(n.year,n.month,n.date,n.hours,n.minutes,n.seconds,n.milliseconds||0)),o}}}]),angular.module("ui.bootstrap.dateparser").value("$dateParserSuppressWarning",!1).service("dateParser",["$log","$dateParserSuppressWarning","uibDateParser",function(a,b,c){b||a.warn("dateParser is now deprecated. Use uibDateParser instead."),angular.extend(this,c)}]),angular.module("ui.bootstrap.position",[]).factory("$uibPosition",["$document","$window",function(a,b){function c(a,c){return a.currentStyle?a.currentStyle[c]:b.getComputedStyle?b.getComputedStyle(a)[c]:a.style[c]}function d(a){return"static"===(c(a,"position")||"static")}var e=function(b){for(var c=a[0],e=b.offsetParent||c;e&&e!==c&&d(e);)e=e.offsetParent;return e||c};return{position:function(b){var c=this.offset(b),d={top:0,left:0},f=e(b[0]);f!=a[0]&&(d=this.offset(angular.element(f)),d.top+=f.clientTop-f.scrollTop,d.left+=f.clientLeft-f.scrollLeft);var g=b[0].getBoundingClientRect();return{width:g.width||b.prop("offsetWidth"),height:g.height||b.prop("offsetHeight"),top:c.top-d.top,left:c.left-d.left}},offset:function(c){var d=c[0].getBoundingClientRect();return{width:d.width||c.prop("offsetWidth"),height:d.height||c.prop("offsetHeight"),top:d.top+(b.pageYOffset||a[0].documentElement.scrollTop),left:d.left+(b.pageXOffset||a[0].documentElement.scrollLeft)}},positionElements:function(a,b,c,d){var e,f,g,h,i=c.split("-"),j=i[0],k=i[1]||"center";e=d?this.offset(a):this.position(a),f=b.prop("offsetWidth"),g=b.prop("offsetHeight");var l={center:function(){return e.left+e.width/2-f/2},left:function(){return e.left},right:function(){return e.left+e.width}},m={center:function(){return e.top+e.height/2-g/2},top:function(){return e.top},bottom:function(){return e.top+e.height}};switch(j){case"right":h={top:m[k](),left:l[j]()};break;case"left":h={top:m[k](),left:e.left-f};break;case"bottom":h={top:m[j](),left:l[k]()};break;default:h={top:e.top-g,left:l[k]()}}return h}}}]),angular.module("ui.bootstrap.position").value("$positionSuppressWarning",!1).service("$position",["$log","$positionSuppressWarning","$uibPosition",function(a,b,c){b||a.warn("$position is now deprecated. Use $uibPosition instead."),angular.extend(this,c)}]),angular.module("ui.bootstrap.datepicker",["ui.bootstrap.dateparser","ui.bootstrap.position"]).value("$datepickerSuppressError",!1).constant("uibDatepickerConfig",{formatDay:"dd",formatMonth:"MMMM",formatYear:"yyyy",formatDayHeader:"EEE",formatDayTitle:"MMMM yyyy",formatMonthTitle:"yyyy",datepickerMode:"day",minMode:"day",maxMode:"year",showWeeks:!0,startingDay:0,yearRange:20,minDate:null,maxDate:null,shortcutPropagation:!1}).controller("UibDatepickerController",["$scope","$attrs","$parse","$interpolate","$log","dateFilter","uibDatepickerConfig","$datepickerSuppressError",function(a,b,c,d,e,f,g,h){var i=this,j={$setViewValue:angular.noop};this.modes=["day","month","year"],angular.forEach(["formatDay","formatMonth","formatYear","formatDayHeader","formatDayTitle","formatMonthTitle","showWeeks","startingDay","yearRange","shortcutPropagation"],function(c,e){i[c]=angular.isDefined(b[c])?6>e?d(b[c])(a.$parent):a.$parent.$eval(b[c]):g[c]}),angular.forEach(["minDate","maxDate"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(a){i[d]=a?new Date(a):null,i.refreshView()}):i[d]=g[d]?new Date(g[d]):null}),angular.forEach(["minMode","maxMode"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(c){i[d]=angular.isDefined(c)?c:b[d],a[d]=i[d],("minMode"==d&&i.modes.indexOf(a.datepickerMode)i.modes.indexOf(i[d]))&&(a.datepickerMode=i[d])}):(i[d]=g[d]||null,a[d]=i[d])}),a.datepickerMode=a.datepickerMode||g.datepickerMode,a.uniqueId="datepicker-"+a.$id+"-"+Math.floor(1e4*Math.random()),angular.isDefined(b.initDate)?(this.activeDate=a.$parent.$eval(b.initDate)||new Date,a.$parent.$watch(b.initDate,function(a){a&&(j.$isEmpty(j.$modelValue)||j.$invalid)&&(i.activeDate=a,i.refreshView())})):this.activeDate=new Date,a.isActive=function(b){return 0===i.compare(b.date,i.activeDate)?(a.activeDateId=b.uid,!0):!1},this.init=function(a){j=a,j.$render=function(){i.render()}},this.render=function(){if(j.$viewValue){var a=new Date(j.$viewValue),b=!isNaN(a);b?this.activeDate=a:h||e.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.')}this.refreshView()},this.refreshView=function(){if(this.element){this._refreshView();var a=j.$viewValue?new Date(j.$viewValue):null;j.$setValidity("dateDisabled",!a||this.element&&!this.isDisabled(a))}},this.createDateObject=function(a,b){var c=j.$viewValue?new Date(j.$viewValue):null;return{date:a,label:f(a,b),selected:c&&0===this.compare(a,c),disabled:this.isDisabled(a),current:0===this.compare(a,new Date),customClass:this.customClass(a)}},this.isDisabled=function(c){return this.minDate&&this.compare(c,this.minDate)<0||this.maxDate&&this.compare(c,this.maxDate)>0||b.dateDisabled&&a.dateDisabled({date:c,mode:a.datepickerMode})},this.customClass=function(b){return a.customClass({date:b,mode:a.datepickerMode})},this.split=function(a,b){for(var c=[];a.length>0;)c.push(a.splice(0,b));return c},a.select=function(b){if(a.datepickerMode===i.minMode){var c=j.$viewValue?new Date(j.$viewValue):new Date(0,0,0,0,0,0,0);c.setFullYear(b.getFullYear(),b.getMonth(),b.getDate()),j.$setViewValue(c),j.$render()}else i.activeDate=b,a.datepickerMode=i.modes[i.modes.indexOf(a.datepickerMode)-1]},a.move=function(a){var b=i.activeDate.getFullYear()+a*(i.step.years||0),c=i.activeDate.getMonth()+a*(i.step.months||0);i.activeDate.setFullYear(b,c,1),i.refreshView()},a.toggleMode=function(b){b=b||1,a.datepickerMode===i.maxMode&&1===b||a.datepickerMode===i.minMode&&-1===b||(a.datepickerMode=i.modes[i.modes.indexOf(a.datepickerMode)+b])},a.keys={13:"enter",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down"};var k=function(){i.element[0].focus()};a.$on("uib:datepicker.focus",k),a.keydown=function(b){var c=a.keys[b.which];if(c&&!b.shiftKey&&!b.altKey)if(b.preventDefault(),i.shortcutPropagation||b.stopPropagation(),"enter"===c||"space"===c){if(i.isDisabled(i.activeDate))return;a.select(i.activeDate)}else!b.ctrlKey||"up"!==c&&"down"!==c?(i.handleKeyDown(c,b),i.refreshView()):a.toggleMode("up"===c?1:-1)}}]).controller("UibDaypickerController",["$scope","$element","dateFilter",function(a,b,c){function d(a,b){return 1!==b||a%4!==0||a%100===0&&a%400!==0?f[b]:29}function e(a){var b=new Date(a);b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1}var f=[31,28,31,30,31,30,31,31,30,31,30,31];this.step={months:1},this.element=b,this.init=function(b){angular.extend(b,this),a.showWeeks=b.showWeeks,b.refreshView()},this.getDates=function(a,b){for(var c,d=new Array(b),e=new Date(a),f=0;b>f;)c=new Date(e),d[f++]=c,e.setDate(e.getDate()+1);return d},this._refreshView=function(){var b=this.activeDate.getFullYear(),d=this.activeDate.getMonth(),f=new Date(this.activeDate);f.setFullYear(b,d,1);var g=this.startingDay-f.getDay(),h=g>0?7-g:-g,i=new Date(f);h>0&&i.setDate(-h+1);for(var j=this.getDates(i,42),k=0;42>k;k++)j[k]=angular.extend(this.createDateObject(j[k],this.formatDay),{secondary:j[k].getMonth()!==d,uid:a.uniqueId+"-"+k});a.labels=new Array(7);for(var l=0;7>l;l++)a.labels[l]={abbr:c(j[l].date,this.formatDayHeader),full:c(j[l].date,"EEEE")};if(a.title=c(this.activeDate,this.formatDayTitle),a.rows=this.split(j,7),a.showWeeks){a.weekNumbers=[];for(var m=(11-this.startingDay)%7,n=a.rows.length,o=0;n>o;o++)a.weekNumbers.push(e(a.rows[o][m].date))}},this.compare=function(a,b){return new Date(a.getFullYear(),a.getMonth(),a.getDate())-new Date(b.getFullYear(),b.getMonth(),b.getDate())},this.handleKeyDown=function(a,b){var c=this.activeDate.getDate();if("left"===a)c-=1;else if("up"===a)c-=7;else if("right"===a)c+=1;else if("down"===a)c+=7;else if("pageup"===a||"pagedown"===a){var e=this.activeDate.getMonth()+("pageup"===a?-1:1);this.activeDate.setMonth(e,1),c=Math.min(d(this.activeDate.getFullYear(),this.activeDate.getMonth()),c)}else"home"===a?c=1:"end"===a&&(c=d(this.activeDate.getFullYear(),this.activeDate.getMonth()));this.activeDate.setDate(c)}}]).controller("UibMonthpickerController",["$scope","$element","dateFilter",function(a,b,c){this.step={years:1},this.element=b,this.init=function(a){angular.extend(a,this),a.refreshView()},this._refreshView=function(){for(var b,d=new Array(12),e=this.activeDate.getFullYear(),f=0;12>f;f++)b=new Date(this.activeDate),b.setFullYear(e,f,1),d[f]=angular.extend(this.createDateObject(b,this.formatMonth),{uid:a.uniqueId+"-"+f});a.title=c(this.activeDate,this.formatMonthTitle),a.rows=this.split(d,3)},this.compare=function(a,b){return new Date(a.getFullYear(),a.getMonth())-new Date(b.getFullYear(),b.getMonth())},this.handleKeyDown=function(a,b){var c=this.activeDate.getMonth();if("left"===a)c-=1;else if("up"===a)c-=3;else if("right"===a)c+=1;else if("down"===a)c+=3;else if("pageup"===a||"pagedown"===a){var d=this.activeDate.getFullYear()+("pageup"===a?-1:1);this.activeDate.setFullYear(d)}else"home"===a?c=0:"end"===a&&(c=11);this.activeDate.setMonth(c)}}]).controller("UibYearpickerController",["$scope","$element","dateFilter",function(a,b,c){function d(a){return parseInt((a-1)/e,10)*e+1}var e;this.element=b,this.yearpickerInit=function(){e=this.yearRange,this.step={years:e}},this._refreshView=function(){for(var b,c=new Array(e),f=0,g=d(this.activeDate.getFullYear());e>f;f++)b=new Date(this.activeDate),b.setFullYear(g+f,0,1),c[f]=angular.extend(this.createDateObject(b,this.formatYear),{uid:a.uniqueId+"-"+f});a.title=[c[0].label,c[e-1].label].join(" - "),a.rows=this.split(c,5)},this.compare=function(a,b){return a.getFullYear()-b.getFullYear()},this.handleKeyDown=function(a,b){var c=this.activeDate.getFullYear();"left"===a?c-=1:"up"===a?c-=5:"right"===a?c+=1:"down"===a?c+=5:"pageup"===a||"pagedown"===a?c+=("pageup"===a?-1:1)*this.step.years:"home"===a?c=d(this.activeDate.getFullYear()):"end"===a&&(c=d(this.activeDate.getFullYear())+e-1),this.activeDate.setFullYear(c)}}]).directive("uibDatepicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/datepicker.html"},scope:{datepickerMode:"=?",dateDisabled:"&",customClass:"&",shortcutPropagation:"&?"},require:["uibDatepicker","^ngModel"],controller:"UibDatepickerController",controllerAs:"datepicker",link:function(a,b,c,d){var e=d[0],f=d[1];e.init(f)}}}).directive("uibDaypicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/day.html"},require:["^?uibDatepicker","uibDaypicker","^?datepicker"],controller:"UibDaypickerController",link:function(a,b,c,d){var e=d[0]||d[2],f=d[1];f.init(e)}}}).directive("uibMonthpicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/month.html"},require:["^?uibDatepicker","uibMonthpicker","^?datepicker"],controller:"UibMonthpickerController",link:function(a,b,c,d){var e=d[0]||d[2],f=d[1];f.init(e)}}}).directive("uibYearpicker",function(){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/year.html"},require:["^?uibDatepicker","uibYearpicker","^?datepicker"],controller:"UibYearpickerController",link:function(a,b,c,d){var e=d[0]||d[2];angular.extend(e,d[1]),e.yearpickerInit(),e.refreshView()}}}).constant("uibDatepickerPopupConfig",{datepickerPopup:"yyyy-MM-dd",datepickerPopupTemplateUrl:"template/datepicker/popup.html",datepickerTemplateUrl:"template/datepicker/datepicker.html",html5Types:{date:"yyyy-MM-dd","datetime-local":"yyyy-MM-ddTHH:mm:ss.sss",month:"yyyy-MM"},currentText:"Today",clearText:"Clear",closeText:"Done",closeOnDateSelection:!0,appendToBody:!1,showButtonBar:!0,onOpenFocus:!0}).controller("UibDatepickerPopupController",["$scope","$element","$attrs","$compile","$parse","$document","$rootScope","$uibPosition","dateFilter","uibDateParser","uibDatepickerPopupConfig","$timeout",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(a){return a.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()})}function n(b){if(angular.isNumber(b)&&(b=new Date(b)),b){if(angular.isDate(b)&&!isNaN(b))return b;if(angular.isString(b)){var c=j.parse(b,r,a.date);return isNaN(c)?void 0:c}return void 0}return null}function o(a,b){var d=a||b;if(!c.ngRequired&&!d)return!0;if(angular.isNumber(d)&&(d=new Date(d)),d){if(angular.isDate(d)&&!isNaN(d))return!0;if(angular.isString(d)){var e=j.parse(d,r);return!isNaN(e)}return!1}return!0}function p(c){var d=A[0],e=b[0].contains(c.target),f=void 0!==d.contains&&d.contains(c.target);!a.isOpen||e||f||a.$apply(function(){a.isOpen=!1})}function q(c){27===c.which&&a.isOpen?(c.preventDefault(),c.stopPropagation(),a.$apply(function(){a.isOpen=!1}),b[0].focus()):40!==c.which||a.isOpen||(c.preventDefault(),c.stopPropagation(),a.$apply(function(){a.isOpen=!0}))}var r,s,t,u,v,w,x,y,z,A,B={},C=!1;a.watchData={},this.init=function(h){if(z=h,s=angular.isDefined(c.closeOnDateSelection)?a.$parent.$eval(c.closeOnDateSelection):k.closeOnDateSelection, +t=angular.isDefined(c.datepickerAppendToBody)?a.$parent.$eval(c.datepickerAppendToBody):k.appendToBody,u=angular.isDefined(c.onOpenFocus)?a.$parent.$eval(c.onOpenFocus):k.onOpenFocus,v=angular.isDefined(c.datepickerPopupTemplateUrl)?c.datepickerPopupTemplateUrl:k.datepickerPopupTemplateUrl,w=angular.isDefined(c.datepickerTemplateUrl)?c.datepickerTemplateUrl:k.datepickerTemplateUrl,a.showButtonBar=angular.isDefined(c.showButtonBar)?a.$parent.$eval(c.showButtonBar):k.showButtonBar,k.html5Types[c.type]?(r=k.html5Types[c.type],C=!0):(r=c.datepickerPopup||c.uibDatepickerPopup||k.datepickerPopup,c.$observe("uibDatepickerPopup",function(a,b){var c=a||k.datepickerPopup;if(c!==r&&(r=c,z.$modelValue=null,!r))throw new Error("uibDatepickerPopup must have a date format specified.")})),!r)throw new Error("uibDatepickerPopup must have a date format specified.");if(C&&c.datepickerPopup)throw new Error("HTML5 date input types do not support custom formats.");if(x=angular.element("
        "),x.attr({"ng-model":"date","ng-change":"dateSelection(date)","template-url":v}),y=angular.element(x.children()[0]),y.attr("template-url",w),C&&"month"===c.type&&(y.attr("datepicker-mode",'"month"'),y.attr("min-mode","month")),c.datepickerOptions){var l=a.$parent.$eval(c.datepickerOptions);l&&l.initDate&&(a.initDate=l.initDate,y.attr("init-date","initDate"),delete l.initDate),angular.forEach(l,function(a,b){y.attr(m(b),a)})}angular.forEach(["minMode","maxMode","minDate","maxDate","datepickerMode","initDate","shortcutPropagation"],function(b){if(c[b]){var d=e(c[b]);if(a.$parent.$watch(d,function(c){a.watchData[b]=c,("minDate"===b||"maxDate"===b)&&(B[b]=new Date(c))}),y.attr(m(b),"watchData."+b),"datepickerMode"===b){var f=d.assign;a.$watch("watchData."+b,function(b,c){angular.isFunction(f)&&b!==c&&f(a.$parent,b)})}}}),c.dateDisabled&&y.attr("date-disabled","dateDisabled({ date: date, mode: mode })"),c.showWeeks&&y.attr("show-weeks",c.showWeeks),c.customClass&&y.attr("custom-class","customClass({ date: date, mode: mode })"),C?z.$formatters.push(function(b){return a.date=b,b}):(z.$$parserName="date",z.$validators.date=o,z.$parsers.unshift(n),z.$formatters.push(function(b){return a.date=b,z.$isEmpty(b)?b:i(b,r)})),z.$viewChangeListeners.push(function(){a.date=j.parse(z.$viewValue,r,a.date)}),b.bind("keydown",q),A=d(x)(a),x.remove(),t?f.find("body").append(A):b.after(A),a.$on("$destroy",function(){a.isOpen===!0&&(g.$$phase||a.$apply(function(){a.isOpen=!1})),A.remove(),b.unbind("keydown",q),f.unbind("click",p)})},a.getText=function(b){return a[b+"Text"]||k[b+"Text"]},a.isDisabled=function(b){return"today"===b&&(b=new Date),a.watchData.minDate&&a.compare(b,B.minDate)<0||a.watchData.maxDate&&a.compare(b,B.maxDate)>0},a.compare=function(a,b){return new Date(a.getFullYear(),a.getMonth(),a.getDate())-new Date(b.getFullYear(),b.getMonth(),b.getDate())},a.dateSelection=function(c){angular.isDefined(c)&&(a.date=c);var d=a.date?i(a.date,r):null;b.val(d),z.$setViewValue(d),s&&(a.isOpen=!1,b[0].focus())},a.keydown=function(c){27===c.which&&(a.isOpen=!1,b[0].focus())},a.select=function(b){if("today"===b){var c=new Date;angular.isDate(a.date)?(b=new Date(a.date),b.setFullYear(c.getFullYear(),c.getMonth(),c.getDate())):b=new Date(c.setHours(0,0,0,0))}a.dateSelection(b)},a.close=function(){a.isOpen=!1,b[0].focus()},a.$watch("isOpen",function(c){c?(a.position=t?h.offset(b):h.position(b),a.position.top=a.position.top+b.prop("offsetHeight"),l(function(){u&&a.$broadcast("uib:datepicker.focus"),f.bind("click",p)},0,!1)):f.unbind("click",p)})}]).directive("uibDatepickerPopup",function(){return{require:["ngModel","uibDatepickerPopup"],controller:"UibDatepickerPopupController",scope:{isOpen:"=?",currentText:"@",clearText:"@",closeText:"@",dateDisabled:"&",customClass:"&"},link:function(a,b,c,d){var e=d[0],f=d[1];f.init(e)}}}).directive("uibDatepickerPopupWrap",function(){return{replace:!0,transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/popup.html"}}}),angular.module("ui.bootstrap.datepicker").value("$datepickerSuppressWarning",!1).controller("DatepickerController",["$scope","$attrs","$parse","$interpolate","$log","dateFilter","uibDatepickerConfig","$datepickerSuppressError","$datepickerSuppressWarning",function(a,b,c,d,e,f,g,h,i){i||e.warn("DatepickerController is now deprecated. Use UibDatepickerController instead.");var j=this,k={$setViewValue:angular.noop};this.modes=["day","month","year"],angular.forEach(["formatDay","formatMonth","formatYear","formatDayHeader","formatDayTitle","formatMonthTitle","showWeeks","startingDay","yearRange","shortcutPropagation"],function(c,e){j[c]=angular.isDefined(b[c])?6>e?d(b[c])(a.$parent):a.$parent.$eval(b[c]):g[c]}),angular.forEach(["minDate","maxDate"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(a){j[d]=a?new Date(a):null,j.refreshView()}):j[d]=g[d]?new Date(g[d]):null}),angular.forEach(["minMode","maxMode"],function(d){b[d]?a.$parent.$watch(c(b[d]),function(c){j[d]=angular.isDefined(c)?c:b[d],a[d]=j[d],("minMode"==d&&j.modes.indexOf(a.datepickerMode)j.modes.indexOf(j[d]))&&(a.datepickerMode=j[d])}):(j[d]=g[d]||null,a[d]=j[d])}),a.datepickerMode=a.datepickerMode||g.datepickerMode,a.uniqueId="datepicker-"+a.$id+"-"+Math.floor(1e4*Math.random()),angular.isDefined(b.initDate)?(this.activeDate=a.$parent.$eval(b.initDate)||new Date,a.$parent.$watch(b.initDate,function(a){a&&(k.$isEmpty(k.$modelValue)||k.$invalid)&&(j.activeDate=a,j.refreshView())})):this.activeDate=new Date,a.isActive=function(b){return 0===j.compare(b.date,j.activeDate)?(a.activeDateId=b.uid,!0):!1},this.init=function(a){k=a,k.$render=function(){j.render()}},this.render=function(){if(k.$viewValue){var a=new Date(k.$viewValue),b=!isNaN(a);b?this.activeDate=a:h||e.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.')}this.refreshView()},this.refreshView=function(){if(this.element){this._refreshView();var a=k.$viewValue?new Date(k.$viewValue):null;k.$setValidity("dateDisabled",!a||this.element&&!this.isDisabled(a))}},this.createDateObject=function(a,b){var c=k.$viewValue?new Date(k.$viewValue):null;return{date:a,label:f(a,b),selected:c&&0===this.compare(a,c),disabled:this.isDisabled(a),current:0===this.compare(a,new Date),customClass:this.customClass(a)}},this.isDisabled=function(c){return this.minDate&&this.compare(c,this.minDate)<0||this.maxDate&&this.compare(c,this.maxDate)>0||b.dateDisabled&&a.dateDisabled({date:c,mode:a.datepickerMode})},this.customClass=function(b){return a.customClass({date:b,mode:a.datepickerMode})},this.split=function(a,b){for(var c=[];a.length>0;)c.push(a.splice(0,b));return c},this.fixTimeZone=function(a){var b=a.getHours();a.setHours(23===b?b+2:0)},a.select=function(b){if(a.datepickerMode===j.minMode){var c=k.$viewValue?new Date(k.$viewValue):new Date(0,0,0,0,0,0,0);c.setFullYear(b.getFullYear(),b.getMonth(),b.getDate()),k.$setViewValue(c),k.$render()}else j.activeDate=b,a.datepickerMode=j.modes[j.modes.indexOf(a.datepickerMode)-1]},a.move=function(a){var b=j.activeDate.getFullYear()+a*(j.step.years||0),c=j.activeDate.getMonth()+a*(j.step.months||0);j.activeDate.setFullYear(b,c,1),j.refreshView()},a.toggleMode=function(b){b=b||1,a.datepickerMode===j.maxMode&&1===b||a.datepickerMode===j.minMode&&-1===b||(a.datepickerMode=j.modes[j.modes.indexOf(a.datepickerMode)+b])},a.keys={13:"enter",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down"};var l=function(){j.element[0].focus()};a.$on("uib:datepicker.focus",l),a.keydown=function(b){var c=a.keys[b.which];if(c&&!b.shiftKey&&!b.altKey)if(b.preventDefault(),j.shortcutPropagation||b.stopPropagation(),"enter"===c||"space"===c){if(j.isDisabled(j.activeDate))return;a.select(j.activeDate)}else!b.ctrlKey||"up"!==c&&"down"!==c?(j.handleKeyDown(c,b),j.refreshView()):a.toggleMode("up"===c?1:-1)}}]).directive("datepicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/datepicker.html"},scope:{datepickerMode:"=?",dateDisabled:"&",customClass:"&",shortcutPropagation:"&?"},require:["datepicker","^ngModel"],controller:"DatepickerController",controllerAs:"datepicker",link:function(c,d,e,f){b||a.warn("datepicker is now deprecated. Use uib-datepicker instead.");var g=f[0],h=f[1];g.init(h)}}}]).directive("daypicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:"template/datepicker/day.html",require:["^datepicker","daypicker"],controller:"UibDaypickerController",link:function(c,d,e,f){b||a.warn("daypicker is now deprecated. Use uib-daypicker instead.");var g=f[0],h=f[1];h.init(g)}}}]).directive("monthpicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:"template/datepicker/month.html",require:["^datepicker","monthpicker"],controller:"UibMonthpickerController",link:function(c,d,e,f){b||a.warn("monthpicker is now deprecated. Use uib-monthpicker instead.");var g=f[0],h=f[1];h.init(g)}}}]).directive("yearpicker",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,templateUrl:"template/datepicker/year.html",require:["^datepicker","yearpicker"],controller:"UibYearpickerController",link:function(c,d,e,f){b||a.warn("yearpicker is now deprecated. Use uib-yearpicker instead.");var g=f[0];angular.extend(g,f[1]),g.yearpickerInit(),g.refreshView()}}}]).directive("datepickerPopup",["$log","$datepickerSuppressWarning",function(a,b){return{require:["ngModel","datepickerPopup"],controller:"UibDatepickerPopupController",scope:{isOpen:"=?",currentText:"@",clearText:"@",closeText:"@",dateDisabled:"&",customClass:"&"},link:function(c,d,e,f){b||a.warn("datepicker-popup is now deprecated. Use uib-datepicker-popup instead.");var g=f[0],h=f[1];h.init(g)}}}]).directive("datepickerPopupWrap",["$log","$datepickerSuppressWarning",function(a,b){return{replace:!0,transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/datepicker/popup.html"},link:function(){b||a.warn("datepicker-popup-wrap is now deprecated. Use uib-datepicker-popup-wrap instead.")}}}]),angular.module("ui.bootstrap.dropdown",["ui.bootstrap.position"]).constant("uibDropdownConfig",{openClass:"open"}).service("uibDropdownService",["$document","$rootScope",function(a,b){var c=null;this.open=function(b){c||(a.bind("click",d),a.bind("keydown",e)),c&&c!==b&&(c.isOpen=!1),c=b},this.close=function(b){c===b&&(c=null,a.unbind("click",d),a.unbind("keydown",e))};var d=function(a){if(c&&(!a||"disabled"!==c.getAutoClose())){var d=c.getToggleElement();if(!(a&&d&&d[0].contains(a.target))){var e=c.getDropdownElement();a&&"outsideClick"===c.getAutoClose()&&e&&e[0].contains(a.target)||(c.isOpen=!1,b.$$phase||c.$apply())}}},e=function(a){27===a.which?(c.focusToggleElement(),d()):c.isKeynavEnabled()&&/(38|40)/.test(a.which)&&c.isOpen&&(a.preventDefault(),a.stopPropagation(),c.focusDropdownEntry(a.which))}}]).controller("UibDropdownController",["$scope","$element","$attrs","$parse","uibDropdownConfig","uibDropdownService","$animate","$uibPosition","$document","$compile","$templateRequest",function(a,b,c,d,e,f,g,h,i,j,k){var l,m,n=this,o=a.$new(),p=e.openClass,q=angular.noop,r=c.onToggle?d(c.onToggle):angular.noop,s=!1,t=!1;b.addClass("dropdown"),this.init=function(){c.isOpen&&(m=d(c.isOpen),q=m.assign,a.$watch(m,function(a){o.isOpen=!!a})),s=angular.isDefined(c.dropdownAppendToBody),t=angular.isDefined(c.uibKeyboardNav),s&&n.dropdownMenu&&(i.find("body").append(n.dropdownMenu),b.on("$destroy",function(){n.dropdownMenu.remove()}))},this.toggle=function(a){return o.isOpen=arguments.length?!!a:!o.isOpen},this.isOpen=function(){return o.isOpen},o.getToggleElement=function(){return n.toggleElement},o.getAutoClose=function(){return c.autoClose||"always"},o.getElement=function(){return b},o.isKeynavEnabled=function(){return t},o.focusDropdownEntry=function(a){var c=n.dropdownMenu?angular.element(n.dropdownMenu).find("a"):angular.element(b).find("ul").eq(0).find("a");switch(a){case 40:angular.isNumber(n.selectedOption)?n.selectedOption=n.selectedOption===c.length-1?n.selectedOption:n.selectedOption+1:n.selectedOption=0;break;case 38:angular.isNumber(n.selectedOption)?n.selectedOption=0===n.selectedOption?0:n.selectedOption-1:n.selectedOption=c.length-1}c[n.selectedOption].focus()},o.getDropdownElement=function(){return n.dropdownMenu},o.focusToggleElement=function(){n.toggleElement&&n.toggleElement[0].focus()},o.$watch("isOpen",function(c,d){if(s&&n.dropdownMenu){var e=h.positionElements(b,n.dropdownMenu,"bottom-left",!0),i={top:e.top+"px",display:c?"block":"none"},m=n.dropdownMenu.hasClass("dropdown-menu-right");m?(i.left="auto",i.right=window.innerWidth-(e.left+b.prop("offsetWidth"))+"px"):(i.left=e.left+"px",i.right="auto"),n.dropdownMenu.css(i)}if(g[c?"addClass":"removeClass"](b,p).then(function(){angular.isDefined(c)&&c!==d&&r(a,{open:!!c})}),c)n.dropdownMenuTemplateUrl&&k(n.dropdownMenuTemplateUrl).then(function(a){l=o.$new(),j(a.trim())(l,function(a){var b=a;n.dropdownMenu.replaceWith(b),n.dropdownMenu=b})}),o.focusToggleElement(),f.open(o);else{if(n.dropdownMenuTemplateUrl){l&&l.$destroy();var t=angular.element('');n.dropdownMenu.replaceWith(t),n.dropdownMenu=t}f.close(o),n.selectedOption=null}angular.isFunction(q)&&q(a,c)}),a.$on("$locationChangeSuccess",function(){"disabled"!==o.getAutoClose()&&(o.isOpen=!1)});var u=a.$on("$destroy",function(){o.$destroy()});o.$on("$destroy",u)}]).directive("uibDropdown",function(){return{controller:"UibDropdownController",link:function(a,b,c,d){d.init()}}}).directive("uibDropdownMenu",function(){return{restrict:"AC",require:"?^uibDropdown",link:function(a,b,c,d){if(d&&!angular.isDefined(c.dropdownNested)){b.addClass("dropdown-menu");var e=c.templateUrl;e&&(d.dropdownMenuTemplateUrl=e),d.dropdownMenu||(d.dropdownMenu=b)}}}}).directive("uibKeyboardNav",function(){return{restrict:"A",require:"?^uibDropdown",link:function(a,b,c,d){b.bind("keydown",function(a){if(-1!==[38,40].indexOf(a.which)){a.preventDefault(),a.stopPropagation();var b=d.dropdownMenu.find("a");switch(a.which){case 40:angular.isNumber(d.selectedOption)?d.selectedOption=d.selectedOption===b.length-1?d.selectedOption:d.selectedOption+1:d.selectedOption=0;break;case 38:angular.isNumber(d.selectedOption)?d.selectedOption=0===d.selectedOption?0:d.selectedOption-1:d.selectedOption=b.length-1}b[d.selectedOption].focus()}})}}}).directive("uibDropdownToggle",function(){return{require:"?^uibDropdown",link:function(a,b,c,d){if(d){b.addClass("dropdown-toggle"),d.toggleElement=b;var e=function(e){e.preventDefault(),b.hasClass("disabled")||c.disabled||a.$apply(function(){d.toggle()})};b.bind("click",e),b.attr({"aria-haspopup":!0,"aria-expanded":!1}),a.$watch(d.isOpen,function(a){b.attr("aria-expanded",!!a)}),a.$on("$destroy",function(){b.unbind("click",e)})}}}}),angular.module("ui.bootstrap.dropdown").value("$dropdownSuppressWarning",!1).service("dropdownService",["$log","$dropdownSuppressWarning","uibDropdownService",function(a,b,c){b||a.warn("dropdownService is now deprecated. Use uibDropdownService instead."),angular.extend(this,c)}]).controller("DropdownController",["$scope","$element","$attrs","$parse","uibDropdownConfig","uibDropdownService","$animate","$uibPosition","$document","$compile","$templateRequest","$log","$dropdownSuppressWarning",function(a,b,c,d,e,f,g,h,i,j,k,l,m){m||l.warn("DropdownController is now deprecated. Use UibDropdownController instead.");var n,o,p=this,q=a.$new(),r=e.openClass,s=angular.noop,t=c.onToggle?d(c.onToggle):angular.noop,u=!1,v=!1;b.addClass("dropdown"),this.init=function(){c.isOpen&&(o=d(c.isOpen),s=o.assign,a.$watch(o,function(a){q.isOpen=!!a})),u=angular.isDefined(c.dropdownAppendToBody),v=angular.isDefined(c.uibKeyboardNav),u&&p.dropdownMenu&&(i.find("body").append(p.dropdownMenu),b.on("$destroy",function(){p.dropdownMenu.remove()}))},this.toggle=function(a){return q.isOpen=arguments.length?!!a:!q.isOpen},this.isOpen=function(){return q.isOpen},q.getToggleElement=function(){return p.toggleElement},q.getAutoClose=function(){return c.autoClose||"always"},q.getElement=function(){return b},q.isKeynavEnabled=function(){return v},q.focusDropdownEntry=function(a){var c=p.dropdownMenu?angular.element(p.dropdownMenu).find("a"):angular.element(b).find("ul").eq(0).find("a");switch(a){case 40:angular.isNumber(p.selectedOption)?p.selectedOption=p.selectedOption===c.length-1?p.selectedOption:p.selectedOption+1:p.selectedOption=0;break;case 38:angular.isNumber(p.selectedOption)?p.selectedOption=0===p.selectedOption?0:p.selectedOption-1:p.selectedOption=c.length-1}c[p.selectedOption].focus()},q.getDropdownElement=function(){return p.dropdownMenu},q.focusToggleElement=function(){p.toggleElement&&p.toggleElement[0].focus()},q.$watch("isOpen",function(c,d){if(u&&p.dropdownMenu){var e=h.positionElements(b,p.dropdownMenu,"bottom-left",!0),i={top:e.top+"px",display:c?"block":"none"},l=p.dropdownMenu.hasClass("dropdown-menu-right");l?(i.left="auto",i.right=window.innerWidth-(e.left+b.prop("offsetWidth"))+"px"):(i.left=e.left+"px",i.right="auto"),p.dropdownMenu.css(i)}if(g[c?"addClass":"removeClass"](b,r).then(function(){angular.isDefined(c)&&c!==d&&t(a,{open:!!c})}),c)p.dropdownMenuTemplateUrl&&k(p.dropdownMenuTemplateUrl).then(function(a){n=q.$new(),j(a.trim())(n,function(a){var b=a;p.dropdownMenu.replaceWith(b),p.dropdownMenu=b})}),q.focusToggleElement(),f.open(q);else{if(p.dropdownMenuTemplateUrl){n&&n.$destroy();var m=angular.element('');p.dropdownMenu.replaceWith(m),p.dropdownMenu=m}f.close(q),p.selectedOption=null}angular.isFunction(s)&&s(a,c)}),a.$on("$locationChangeSuccess",function(){"disabled"!==q.getAutoClose()&&(q.isOpen=!1)});var w=a.$on("$destroy",function(){q.$destroy()});q.$on("$destroy",w)}]).directive("dropdown",["$log","$dropdownSuppressWarning",function(a,b){return{controller:"DropdownController",link:function(c,d,e,f){b||a.warn("dropdown is now deprecated. Use uib-dropdown instead."),f.init()}}}]).directive("dropdownMenu",["$log","$dropdownSuppressWarning",function(a,b){return{restrict:"AC",require:"?^dropdown",link:function(c,d,e,f){if(f&&!angular.isDefined(e.dropdownNested)){b||a.warn("dropdown-menu is now deprecated. Use uib-dropdown-menu instead."),d.addClass("dropdown-menu");var g=e.templateUrl;g&&(f.dropdownMenuTemplateUrl=g),f.dropdownMenu||(f.dropdownMenu=d)}}}}]).directive("keyboardNav",["$log","$dropdownSuppressWarning",function(a,b){return{restrict:"A",require:"?^dropdown",link:function(c,d,e,f){b||a.warn("keyboard-nav is now deprecated. Use uib-keyboard-nav instead."),d.bind("keydown",function(a){if(-1!==[38,40].indexOf(a.which)){a.preventDefault(),a.stopPropagation();var b=f.dropdownMenu.find("a");switch(a.which){case 40:angular.isNumber(f.selectedOption)?f.selectedOption=f.selectedOption===b.length-1?f.selectedOption:f.selectedOption+1:f.selectedOption=0;break;case 38:angular.isNumber(f.selectedOption)?f.selectedOption=0===f.selectedOption?0:f.selectedOption-1:f.selectedOption=b.length-1}b[f.selectedOption].focus()}})}}}]).directive("dropdownToggle",["$log","$dropdownSuppressWarning",function(a,b){return{require:"?^dropdown",link:function(c,d,e,f){if(b||a.warn("dropdown-toggle is now deprecated. Use uib-dropdown-toggle instead."),f){d.addClass("dropdown-toggle"),f.toggleElement=d;var g=function(a){a.preventDefault(),d.hasClass("disabled")||e.disabled||c.$apply(function(){f.toggle()})};d.bind("click",g),d.attr({"aria-haspopup":!0,"aria-expanded":!1}),c.$watch(f.isOpen,function(a){d.attr("aria-expanded",!!a)}),c.$on("$destroy",function(){d.unbind("click",g)})}}}}]),angular.module("ui.bootstrap.stackedMap",[]).factory("$$stackedMap",function(){return{createNew:function(){var a=[];return{add:function(b,c){a.push({key:b,value:c})},get:function(b){for(var c=0;c0&&(b=u.top().value,b.modalDomEl.toggleClass(b.windowTopClass||"",a))}function m(){if(q&&-1==j()){var a=r;n(q,r,function(){a=null}),q=void 0,r=void 0}}function n(b,c,d){function e(){e.done||(e.done=!0,p?p(b,{event:"leave"}).start().then(function(){b.remove()}):a.leave(b),c.$destroy(),d&&d())}var g,h=null,i=function(){return g||(g=f.defer(),h=g.promise),function(){g.resolve()}};return c.$broadcast(w.NOW_CLOSING_EVENT,i),f.when(h).then(e)}function o(a,b,c){return!a.value.modalScope.$broadcast("modal.closing",b,c).defaultPrevented}var p=null;g.has("$animateCss")&&(p=g.get("$animateCss"));var q,r,s,t="modal-open",u=i.createNew(),v=h.createNew(),w={NOW_CLOSING_EVENT:"modal.stack.now-closing"},x=0,y="a[href], area[href], input:not([disabled]), button:not([disabled]),select:not([disabled]), textarea:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable=true]";return e.$watch(j,function(a){r&&(r.index=a)}),c.bind("keydown",function(a){if(a.isDefaultPrevented())return a;var b=u.top();if(b&&b.value.keyboard)switch(a.which){case 27:a.preventDefault(),e.$apply(function(){w.dismiss(b.key,"escape key press")});break;case 9:w.loadFocusElementList(b);var c=!1;a.shiftKey?w.isFocusInFirstItem(a)&&(c=w.focusLastFocusableElement()):w.isFocusInLastItem(a)&&(c=w.focusFirstFocusableElement()),c&&(a.preventDefault(),a.stopPropagation())}}),w.open=function(a,b){var f=c[0].activeElement,g=b.openedClass||t;l(!1),u.add(a,{deferred:b.deferred,renderDeferred:b.renderDeferred,modalScope:b.scope,backdrop:b.backdrop,keyboard:b.keyboard,openedClass:b.openedClass,windowTopClass:b.windowTopClass}),v.put(g,a);var h=c.find("body").eq(0),i=j();if(i>=0&&!q){r=e.$new(!0),r.index=i;var k=angular.element('
        ');k.attr("backdrop-class",b.backdropClass),b.animation&&k.attr("modal-animation","true"),q=d(k)(r),h.append(q)}var m=angular.element('
        ');m.attr({"template-url":b.windowTemplateUrl,"window-class":b.windowClass,"window-top-class":b.windowTopClass,size:b.size,index:u.length()-1,animate:"animate"}).html(b.content),b.animation&&m.attr("modal-animation","true");var n=d(m)(b.scope);u.top().value.modalDomEl=n,u.top().value.modalOpener=f,h.append(n),h.addClass(g),w.clearFocusListCache()},w.close=function(a,b){var c=u.get(a);return c&&o(c,b,!0)?(c.value.modalScope.$$uibDestructionScheduled=!0,c.value.deferred.resolve(b),k(a,c.value.modalOpener),!0):!c},w.dismiss=function(a,b){var c=u.get(a);return c&&o(c,b,!1)?(c.value.modalScope.$$uibDestructionScheduled=!0,c.value.deferred.reject(b),k(a,c.value.modalOpener),!0):!c},w.dismissAll=function(a){for(var b=this.getTop();b&&this.dismiss(b.key,a);)b=this.getTop()},w.getTop=function(){return u.top()},w.modalRendered=function(a){var b=u.get(a);b&&b.value.renderDeferred.resolve()},w.focusFirstFocusableElement=function(){return s.length>0?(s[0].focus(),!0):!1},w.focusLastFocusableElement=function(){return s.length>0?(s[s.length-1].focus(),!0):!1},w.isFocusInFirstItem=function(a){return s.length>0?(a.target||a.srcElement)==s[0]:!1},w.isFocusInLastItem=function(a){return s.length>0?(a.target||a.srcElement)==s[s.length-1]:!1},w.clearFocusListCache=function(){s=[],x=0},w.loadFocusElementList=function(a){if((void 0===s||!s.length)&&a){var b=a.value.modalDomEl;b&&b.length&&(s=b[0].querySelectorAll(y))}},w}]).provider("$uibModal",function(){var a={options:{animation:!0,backdrop:!0,keyboard:!0},$get:["$injector","$rootScope","$q","$templateRequest","$controller","$uibModalStack","$modalSuppressWarning","$log",function(b,c,d,e,f,g,h,i){function j(a){return a.template?d.when(a.template):e(angular.isFunction(a.templateUrl)?a.templateUrl():a.templateUrl)}function k(a){var c=[];return angular.forEach(a,function(a){angular.isFunction(a)||angular.isArray(a)?c.push(d.when(b.invoke(a))):angular.isString(a)?c.push(d.when(b.get(a))):c.push(d.when(a))}),c}var l={},m=null;return l.getPromiseChain=function(){return m},l.open=function(b){function e(){return r}var l=d.defer(),n=d.defer(),o=d.defer(),p={result:l.promise,opened:n.promise,rendered:o.promise,close:function(a){return g.close(p,a)},dismiss:function(a){return g.dismiss(p,a)}};if(b=angular.extend({},a.options,b),b.resolve=b.resolve||{},!b.template&&!b.templateUrl)throw new Error("One of template or templateUrl options is required.");var q,r=d.all([j(b)].concat(k(b.resolve)));return q=m=d.all([m]).then(e,e).then(function(a){var d=(b.scope||c).$new();d.$close=p.close,d.$dismiss=p.dismiss,d.$on("$destroy",function(){d.$$uibDestructionScheduled||d.$dismiss("$uibUnscheduledDestruction")});var e,j={},k=1;b.controller&&(j.$scope=d,j.$uibModalInstance=p,Object.defineProperty(j,"$modalInstance",{get:function(){return h||i.warn("$modalInstance is now deprecated. Use $uibModalInstance instead."),p}}),angular.forEach(b.resolve,function(b,c){j[c]=a[k++]}),e=f(b.controller,j),b.controllerAs&&(b.bindToController&&angular.extend(e,d),d[b.controllerAs]=e)),g.open(p,{scope:d,deferred:l,renderDeferred:o,content:a[0],animation:b.animation,backdrop:b.backdrop,keyboard:b.keyboard,backdropClass:b.backdropClass,windowTopClass:b.windowTopClass,windowClass:b.windowClass,windowTemplateUrl:b.windowTemplateUrl,size:b.size,openedClass:b.openedClass}),n.resolve(!0)},function(a){n.reject(a),l.reject(a)})["finally"](function(){m===q&&(m=null)}),p},l}]};return a}),angular.module("ui.bootstrap.modal").value("$modalSuppressWarning",!1).directive("modalBackdrop",["$animate","$injector","$modalStack","$log","$modalSuppressWarning",function(a,b,c,d,e){function f(b,f,h){e||d.warn("modal-backdrop is now deprecated. Use uib-modal-backdrop instead."),f.addClass("modal-backdrop"),h.modalInClass&&(g?g(f,{addClass:h.modalInClass}).start():a.addClass(f,h.modalInClass),b.$on(c.NOW_CLOSING_EVENT,function(b,c){var d=c();g?g(f,{removeClass:h.modalInClass}).start().then(d):a.removeClass(f,h.modalInClass).then(d)}))}var g=null;return b.has("$animateCss")&&(g=b.get("$animateCss")),{replace:!0,templateUrl:"template/modal/backdrop.html",compile:function(a,b){return a.addClass(b.backdropClass),f}}}]).directive("modalWindow",["$modalStack","$q","$animate","$injector","$log","$modalSuppressWarning",function(a,b,c,d,e,f){var g=null;return d.has("$animateCss")&&(g=d.get("$animateCss")),{scope:{index:"@"},replace:!0,transclude:!0,templateUrl:function(a,b){return b.templateUrl||"template/modal/window.html"},link:function(d,h,i){f||e.warn("modal-window is now deprecated. Use uib-modal-window instead."),h.addClass(i.windowClass||""),h.addClass(i.windowTopClass||""),d.size=i.size,d.close=function(b){var c=a.getTop();c&&c.value.backdrop&&"static"!==c.value.backdrop&&b.target===b.currentTarget&&(b.preventDefault(),b.stopPropagation(),a.dismiss(c.key,"backdrop click"))},h.on("click",d.close),d.$isRendered=!0;var j=b.defer();i.$observe("modalRender",function(a){"true"==a&&j.resolve()}),j.promise.then(function(){var e=null;i.modalInClass&&(e=g?g(h,{addClass:i.modalInClass}).start():c.addClass(h,i.modalInClass),d.$on(a.NOW_CLOSING_EVENT,function(a,b){var d=b();g?g(h,{removeClass:i.modalInClass}).start().then(d):c.removeClass(h,i.modalInClass).then(d)})),b.when(e).then(function(){var a=h[0].querySelector("[autofocus]");a?a.focus():h[0].focus()});var f=a.getTop();f&&a.modalRendered(f.key)})}}}]).directive("modalAnimationClass",["$log","$modalSuppressWarning",function(a,b){return{compile:function(c,d){b||a.warn("modal-animation-class is now deprecated. Use uib-modal-animation-class instead."),d.modalAnimation&&c.addClass(d.modalAnimationClass)}}}]).directive("modalTransclude",["$log","$modalSuppressWarning",function(a,b){return{link:function(c,d,e,f,g){b||a.warn("modal-transclude is now deprecated. Use uib-modal-transclude instead."),g(c.$parent,function(a){d.empty(),d.append(a)})}}}]).service("$modalStack",["$animate","$timeout","$document","$compile","$rootScope","$q","$injector","$$multiMap","$$stackedMap","$uibModalStack","$log","$modalSuppressWarning",function(a,b,c,d,e,f,g,h,i,j,k,l){l||k.warn("$modalStack is now deprecated. Use $uibModalStack instead."),angular.extend(this,j)}]).provider("$modal",["$uibModalProvider",function(a){angular.extend(this,a),this.$get=["$injector","$log","$modalSuppressWarning",function(b,c,d){return d||c.warn("$modal is now deprecated. Use $uibModal instead."),b.invoke(a.$get)}]}]),angular.module("ui.bootstrap.pagination",[]).controller("UibPaginationController",["$scope","$attrs","$parse",function(a,b,c){var d=this,e={$setViewValue:angular.noop},f=b.numPages?c(b.numPages).assign:angular.noop;this.init=function(g,h){e=g,this.config=h,e.$render=function(){d.render()},b.itemsPerPage?a.$parent.$watch(c(b.itemsPerPage),function(b){d.itemsPerPage=parseInt(b,10), +a.totalPages=d.calculateTotalPages()}):this.itemsPerPage=h.itemsPerPage,a.$watch("totalItems",function(){a.totalPages=d.calculateTotalPages()}),a.$watch("totalPages",function(b){f(a.$parent,b),a.page>b?a.selectPage(b):e.$render()})},this.calculateTotalPages=function(){var b=this.itemsPerPage<1?1:Math.ceil(a.totalItems/this.itemsPerPage);return Math.max(b||0,1)},this.render=function(){a.page=parseInt(e.$viewValue,10)||1},a.selectPage=function(b,c){c&&c.preventDefault();var d=!a.ngDisabled||!c;d&&a.page!==b&&b>0&&b<=a.totalPages&&(c&&c.target&&c.target.blur(),e.$setViewValue(b),e.$render())},a.getText=function(b){return a[b+"Text"]||d.config[b+"Text"]},a.noPrevious=function(){return 1===a.page},a.noNext=function(){return a.page===a.totalPages}}]).constant("uibPaginationConfig",{itemsPerPage:10,boundaryLinks:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0}).directive("uibPagination",["$parse","uibPaginationConfig",function(a,b){return{restrict:"EA",scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@",ngDisabled:"="},require:["uibPagination","?ngModel"],controller:"UibPaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pagination.html"},replace:!0,link:function(c,d,e,f){function g(a,b,c){return{number:a,text:b,active:c}}function h(a,b){var c=[],d=1,e=b,f=angular.isDefined(k)&&b>k;f&&(l?(d=Math.max(a-Math.floor(k/2),1),e=d+k-1,e>b&&(e=b,d=e-k+1)):(d=(Math.ceil(a/k)-1)*k+1,e=Math.min(d+k-1,b)));for(var h=d;e>=h;h++){var i=g(h,h,h===a);c.push(i)}if(f&&!l){if(d>1){var j=g(d-1,"...",!1);c.unshift(j)}if(b>e){var m=g(e+1,"...",!1);c.push(m)}}return c}var i=f[0],j=f[1];if(j){var k=angular.isDefined(e.maxSize)?c.$parent.$eval(e.maxSize):b.maxSize,l=angular.isDefined(e.rotate)?c.$parent.$eval(e.rotate):b.rotate;c.boundaryLinks=angular.isDefined(e.boundaryLinks)?c.$parent.$eval(e.boundaryLinks):b.boundaryLinks,c.directionLinks=angular.isDefined(e.directionLinks)?c.$parent.$eval(e.directionLinks):b.directionLinks,i.init(j,b),e.maxSize&&c.$parent.$watch(a(e.maxSize),function(a){k=parseInt(a,10),i.render()});var m=i.render;i.render=function(){m(),c.page>0&&c.page<=c.totalPages&&(c.pages=h(c.page,c.totalPages))}}}}}]).constant("uibPagerConfig",{itemsPerPage:10,previousText:"« Previous",nextText:"Next »",align:!0}).directive("uibPager",["uibPagerConfig",function(a){return{restrict:"EA",scope:{totalItems:"=",previousText:"@",nextText:"@",ngDisabled:"="},require:["uibPager","?ngModel"],controller:"UibPaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pager.html"},replace:!0,link:function(b,c,d,e){var f=e[0],g=e[1];g&&(b.align=angular.isDefined(d.align)?b.$parent.$eval(d.align):a.align,f.init(g,a))}}}]),angular.module("ui.bootstrap.pagination").value("$paginationSuppressWarning",!1).controller("PaginationController",["$scope","$attrs","$parse","$log","$paginationSuppressWarning",function(a,b,c,d,e){e||d.warn("PaginationController is now deprecated. Use UibPaginationController instead.");var f=this,g={$setViewValue:angular.noop},h=b.numPages?c(b.numPages).assign:angular.noop;this.init=function(d,e){g=d,this.config=e,g.$render=function(){f.render()},b.itemsPerPage?a.$parent.$watch(c(b.itemsPerPage),function(b){f.itemsPerPage=parseInt(b,10),a.totalPages=f.calculateTotalPages()}):this.itemsPerPage=e.itemsPerPage,a.$watch("totalItems",function(){a.totalPages=f.calculateTotalPages()}),a.$watch("totalPages",function(b){h(a.$parent,b),a.page>b?a.selectPage(b):g.$render()})},this.calculateTotalPages=function(){var b=this.itemsPerPage<1?1:Math.ceil(a.totalItems/this.itemsPerPage);return Math.max(b||0,1)},this.render=function(){a.page=parseInt(g.$viewValue,10)||1},a.selectPage=function(b,c){c&&c.preventDefault();var d=!a.ngDisabled||!c;d&&a.page!==b&&b>0&&b<=a.totalPages&&(c&&c.target&&c.target.blur(),g.$setViewValue(b),g.$render())},a.getText=function(b){return a[b+"Text"]||f.config[b+"Text"]},a.noPrevious=function(){return 1===a.page},a.noNext=function(){return a.page===a.totalPages}}]).directive("pagination",["$parse","uibPaginationConfig","$log","$paginationSuppressWarning",function(a,b,c,d){return{restrict:"EA",scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@",ngDisabled:"="},require:["pagination","?ngModel"],controller:"PaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pagination.html"},replace:!0,link:function(e,f,g,h){function i(a,b,c){return{number:a,text:b,active:c}}function j(a,b){var c=[],d=1,e=b,f=angular.isDefined(m)&&b>m;f&&(n?(d=Math.max(a-Math.floor(m/2),1),e=d+m-1,e>b&&(e=b,d=e-m+1)):(d=(Math.ceil(a/m)-1)*m+1,e=Math.min(d+m-1,b)));for(var g=d;e>=g;g++){var h=i(g,g,g===a);c.push(h)}if(f&&!n){if(d>1){var j=i(d-1,"...",!1);c.unshift(j)}if(b>e){var k=i(e+1,"...",!1);c.push(k)}}return c}d||c.warn("pagination is now deprecated. Use uib-pagination instead.");var k=h[0],l=h[1];if(l){var m=angular.isDefined(g.maxSize)?e.$parent.$eval(g.maxSize):b.maxSize,n=angular.isDefined(g.rotate)?e.$parent.$eval(g.rotate):b.rotate;e.boundaryLinks=angular.isDefined(g.boundaryLinks)?e.$parent.$eval(g.boundaryLinks):b.boundaryLinks,e.directionLinks=angular.isDefined(g.directionLinks)?e.$parent.$eval(g.directionLinks):b.directionLinks,k.init(l,b),g.maxSize&&e.$parent.$watch(a(g.maxSize),function(a){m=parseInt(a,10),k.render()});var o=k.render;k.render=function(){o(),e.page>0&&e.page<=e.totalPages&&(e.pages=j(e.page,e.totalPages))}}}}}]).directive("pager",["uibPagerConfig","$log","$paginationSuppressWarning",function(a,b,c){return{restrict:"EA",scope:{totalItems:"=",previousText:"@",nextText:"@",ngDisabled:"="},require:["pager","?ngModel"],controller:"PaginationController",controllerAs:"pagination",templateUrl:function(a,b){return b.templateUrl||"template/pagination/pager.html"},replace:!0,link:function(d,e,f,g){c||b.warn("pager is now deprecated. Use uib-pager instead.");var h=g[0],i=g[1];i&&(d.align=angular.isDefined(f.align)?d.$parent.$eval(f.align):a.align,h.init(i,a))}}}]),angular.module("ui.bootstrap.tooltip",["ui.bootstrap.position","ui.bootstrap.stackedMap"]).provider("$uibTooltip",function(){function a(a){var b=/[A-Z]/g,c="-";return a.replace(b,function(a,b){return(b?c:"")+a.toLowerCase()})}var b={placement:"top",animation:!0,popupDelay:0,popupCloseDelay:0,useContentExp:!1},c={mouseenter:"mouseleave",click:"click",focus:"blur",none:""},d={};this.options=function(a){angular.extend(d,a)},this.setTriggers=function(a){angular.extend(c,a)},this.$get=["$window","$compile","$timeout","$document","$uibPosition","$interpolate","$rootScope","$parse","$$stackedMap",function(e,f,g,h,i,j,k,l,m){var n=m.createNew();return h.on("keypress",function(a){if(27===a.which){var b=n.top();b&&(b.value.close(),n.removeTop(),b=null)}}),function(e,k,m,o){function p(a){var b=(a||o.trigger||m).split(" "),d=b.map(function(a){return c[a]||a});return{show:b,hide:d}}o=angular.extend({},b,d,o);var q=a(e),r=j.startSymbol(),s=j.endSymbol(),t="
        ';return{compile:function(a,b){var c=f(t);return function(a,b,d,f){function j(){L.isOpen?q():m()}function m(){(!K||a.$eval(d[k+"Enable"]))&&(u(),x(),L.popupDelay?F||(F=g(r,L.popupDelay,!1)):r())}function q(){s(),L.popupCloseDelay?G||(G=g(t,L.popupCloseDelay,!1)):t()}function r(){return s(),u(),L.content?(v(),void L.$evalAsync(function(){L.isOpen=!0,y(!0),Q()})):angular.noop}function s(){F&&(g.cancel(F),F=null),H&&(g.cancel(H),H=null)}function t(){s(),u(),L&&L.$evalAsync(function(){L.isOpen=!1,y(!1),L.animation?E||(E=g(w,150,!1)):w()})}function u(){G&&(g.cancel(G),G=null),E&&(g.cancel(E),E=null)}function v(){C||(D=L.$new(),C=c(D,function(a){I?h.find("body").append(a):b.after(a)}),z())}function w(){A(),E=null,C&&(C.remove(),C=null),D&&(D.$destroy(),D=null)}function x(){L.title=d[k+"Title"],O?L.content=O(a):L.content=d[e],L.popupClass=d[k+"Class"],L.placement=angular.isDefined(d[k+"Placement"])?d[k+"Placement"]:o.placement;var b=parseInt(d[k+"PopupDelay"],10),c=parseInt(d[k+"PopupCloseDelay"],10);L.popupDelay=isNaN(b)?o.popupDelay:b,L.popupCloseDelay=isNaN(c)?o.popupCloseDelay:c}function y(b){N&&angular.isFunction(N.assign)&&N.assign(a,b)}function z(){P.length=0,O?(P.push(a.$watch(O,function(a){L.content=a,!a&&L.isOpen&&t()})),P.push(D.$watch(function(){M||(M=!0,D.$$postDigest(function(){M=!1,L&&L.isOpen&&Q()}))}))):P.push(d.$observe(e,function(a){L.content=a,!a&&L.isOpen?t():Q()})),P.push(d.$observe(k+"Title",function(a){L.title=a,L.isOpen&&Q()})),P.push(d.$observe(k+"Placement",function(a){L.placement=a?a:o.placement,L.isOpen&&Q()}))}function A(){P.length&&(angular.forEach(P,function(a){a()}),P.length=0)}function B(){var a=d[k+"Trigger"];R(),J=p(a),"none"!==J.show&&J.show.forEach(function(a,c){a===J.hide[c]?b[0].addEventListener(a,j):a&&(b[0].addEventListener(a,m),J.hide[c].split(" ").forEach(function(a){b[0].addEventListener(a,q)})),b.on("keypress",function(a){27===a.which&&q()})})}var C,D,E,F,G,H,I=angular.isDefined(o.appendToBody)?o.appendToBody:!1,J=p(void 0),K=angular.isDefined(d[k+"Enable"]),L=a.$new(!0),M=!1,N=angular.isDefined(d[k+"IsOpen"])?l(d[k+"IsOpen"]):!1,O=o.useContentExp?l(d[e]):!1,P=[],Q=function(){C&&C.html()&&(H||(H=g(function(){C.css({top:0,left:0});var a=i.positionElements(b,C,L.placement,I);a.top+="px",a.left+="px",a.visibility="visible",C.css(a),H=null},0,!1)))};L.origScope=a,L.isOpen=!1,n.add(L,{close:t}),L.contentExp=function(){return L.content},d.$observe("disabled",function(a){a&&s(),a&&L.isOpen&&t()}),N&&a.$watch(N,function(a){L&&!a===L.isOpen&&j()});var R=function(){J.show.forEach(function(a){b.unbind(a,m)}),J.hide.forEach(function(a){a.split(" ").forEach(function(a){b[0].removeEventListener(a,q)})})};B();var S=a.$eval(d[k+"Animation"]);L.animation=angular.isDefined(S)?!!S:o.animation;var T=a.$eval(d[k+"AppendToBody"]);I=angular.isDefined(T)?T:I,I&&a.$on("$locationChangeSuccess",function(){L.isOpen&&t()}),a.$on("$destroy",function(){s(),u(),R(),w(),n.remove(L),L=null})}}}}}]}).directive("uibTooltipTemplateTransclude",["$animate","$sce","$compile","$templateRequest",function(a,b,c,d){return{link:function(e,f,g){var h,i,j,k=e.$eval(g.tooltipTemplateTranscludeScope),l=0,m=function(){i&&(i.remove(),i=null),h&&(h.$destroy(),h=null),j&&(a.leave(j).then(function(){i=null}),i=j,j=null)};e.$watch(b.parseAsResourceUrl(g.uibTooltipTemplateTransclude),function(b){var g=++l;b?(d(b,!0).then(function(d){if(g===l){var e=k.$new(),i=d,n=c(i)(e,function(b){m(),a.enter(b,f)});h=e,j=n,h.$emit("$includeContentLoaded",b)}},function(){g===l&&(m(),e.$emit("$includeContentError",b))}),e.$emit("$includeContentRequested",b)):m()}),e.$on("$destroy",m)}}}]).directive("uibTooltipClasses",function(){return{restrict:"A",link:function(a,b,c){a.placement&&b.addClass(a.placement),a.popupClass&&b.addClass(a.popupClass),a.animation()&&b.addClass(c.tooltipAnimationClass)}}}).directive("uibTooltipPopup",function(){return{replace:!0,scope:{content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-popup.html",link:function(a,b){b.addClass("tooltip")}}}).directive("uibTooltip",["$uibTooltip",function(a){return a("uibTooltip","tooltip","mouseenter")}]).directive("uibTooltipTemplatePopup",function(){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/tooltip/tooltip-template-popup.html",link:function(a,b){b.addClass("tooltip")}}}).directive("uibTooltipTemplate",["$uibTooltip",function(a){return a("uibTooltipTemplate","tooltip","mouseenter",{useContentExp:!0})}]).directive("uibTooltipHtmlPopup",function(){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-html-popup.html",link:function(a,b){b.addClass("tooltip")}}}).directive("uibTooltipHtml",["$uibTooltip",function(a){return a("uibTooltipHtml","tooltip","mouseenter",{useContentExp:!0})}]),angular.module("ui.bootstrap.tooltip").value("$tooltipSuppressWarning",!1).provider("$tooltip",["$uibTooltipProvider",function(a){angular.extend(this,a),this.$get=["$log","$tooltipSuppressWarning","$injector",function(b,c,d){return c||b.warn("$tooltip is now deprecated. Use $uibTooltip instead."),d.invoke(a.$get)}]}]).directive("tooltipTemplateTransclude",["$animate","$sce","$compile","$templateRequest","$log","$tooltipSuppressWarning",function(a,b,c,d,e,f){return{link:function(g,h,i){f||e.warn("tooltip-template-transclude is now deprecated. Use uib-tooltip-template-transclude instead.");var j,k,l,m=g.$eval(i.tooltipTemplateTranscludeScope),n=0,o=function(){k&&(k.remove(),k=null),j&&(j.$destroy(),j=null),l&&(a.leave(l).then(function(){k=null}),k=l,l=null)};g.$watch(b.parseAsResourceUrl(i.tooltipTemplateTransclude),function(b){var e=++n;b?(d(b,!0).then(function(d){if(e===n){var f=m.$new(),g=d,i=c(g)(f,function(b){o(),a.enter(b,h)});j=f,l=i,j.$emit("$includeContentLoaded",b)}},function(){e===n&&(o(),g.$emit("$includeContentError",b))}),g.$emit("$includeContentRequested",b)):o()}),g.$on("$destroy",o)}}}]).directive("tooltipClasses",["$log","$tooltipSuppressWarning",function(a,b){return{restrict:"A",link:function(c,d,e){b||a.warn("tooltip-classes is now deprecated. Use uib-tooltip-classes instead."),c.placement&&d.addClass(c.placement),c.popupClass&&d.addClass(c.popupClass),c.animation()&&d.addClass(e.tooltipAnimationClass)}}}]).directive("tooltipPopup",["$log","$tooltipSuppressWarning",function(a,b){return{replace:!0,scope:{content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-popup.html",link:function(c,d){b||a.warn("tooltip-popup is now deprecated. Use uib-tooltip-popup instead."),d.addClass("tooltip")}}}]).directive("tooltip",["$tooltip",function(a){return a("tooltip","tooltip","mouseenter")}]).directive("tooltipTemplatePopup",["$log","$tooltipSuppressWarning",function(a,b){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/tooltip/tooltip-template-popup.html",link:function(c,d){b||a.warn("tooltip-template-popup is now deprecated. Use uib-tooltip-template-popup instead."),d.addClass("tooltip")}}}]).directive("tooltipTemplate",["$tooltip",function(a){return a("tooltipTemplate","tooltip","mouseenter",{useContentExp:!0})}]).directive("tooltipHtmlPopup",["$log","$tooltipSuppressWarning",function(a,b){return{replace:!0,scope:{contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-html-popup.html",link:function(c,d){b||a.warn("tooltip-html-popup is now deprecated. Use uib-tooltip-html-popup instead."),d.addClass("tooltip")}}}]).directive("tooltipHtml",["$tooltip",function(a){return a("tooltipHtml","tooltip","mouseenter",{useContentExp:!0})}]),angular.module("ui.bootstrap.popover",["ui.bootstrap.tooltip"]).directive("uibPopoverTemplatePopup",function(){return{replace:!0,scope:{title:"@",contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/popover/popover-template.html",link:function(a,b){b.addClass("popover")}}}).directive("uibPopoverTemplate",["$uibTooltip",function(a){return a("uibPopoverTemplate","popover","click",{useContentExp:!0})}]).directive("uibPopoverHtmlPopup",function(){return{replace:!0,scope:{contentExp:"&",title:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover-html.html",link:function(a,b){b.addClass("popover")}}}).directive("uibPopoverHtml",["$uibTooltip",function(a){return a("uibPopoverHtml","popover","click",{useContentExp:!0})}]).directive("uibPopoverPopup",function(){return{replace:!0,scope:{title:"@",content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover.html",link:function(a,b){b.addClass("popover")}}}).directive("uibPopover",["$uibTooltip",function(a){return a("uibPopover","popover","click")}]),angular.module("ui.bootstrap.popover").value("$popoverSuppressWarning",!1).directive("popoverTemplatePopup",["$log","$popoverSuppressWarning",function(a,b){return{replace:!0,scope:{title:"@",contentExp:"&",placement:"@",popupClass:"@",animation:"&",isOpen:"&",originScope:"&"},templateUrl:"template/popover/popover-template.html",link:function(c,d){b||a.warn("popover-template-popup is now deprecated. Use uib-popover-template-popup instead."),d.addClass("popover")}}}]).directive("popoverTemplate",["$tooltip",function(a){return a("popoverTemplate","popover","click",{useContentExp:!0})}]).directive("popoverHtmlPopup",["$log","$popoverSuppressWarning",function(a,b){return{replace:!0,scope:{contentExp:"&",title:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover-html.html",link:function(c,d){b||a.warn("popover-html-popup is now deprecated. Use uib-popover-html-popup instead."),d.addClass("popover")}}}]).directive("popoverHtml",["$tooltip",function(a){return a("popoverHtml","popover","click",{useContentExp:!0})}]).directive("popoverPopup",["$log","$popoverSuppressWarning",function(a,b){return{replace:!0,scope:{title:"@",content:"@",placement:"@",popupClass:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover.html",link:function(c,d){b||a.warn("popover-popup is now deprecated. Use uib-popover-popup instead."),d.addClass("popover")}}}]).directive("popover",["$tooltip",function(a){return a("popover","popover","click")}]),angular.module("ui.bootstrap.progressbar",[]).constant("uibProgressConfig",{animate:!0,max:100}).controller("UibProgressController",["$scope","$attrs","uibProgressConfig",function(a,b,c){var d=this,e=angular.isDefined(b.animate)?a.$parent.$eval(b.animate):c.animate;this.bars=[],a.max=angular.isDefined(a.max)?a.max:c.max,this.addBar=function(b,c,f){e||c.css({transition:"none"}),this.bars.push(b),b.max=a.max,b.title=f&&angular.isDefined(f.title)?f.title:"progressbar",b.$watch("value",function(a){b.recalculatePercentage()}),b.recalculatePercentage=function(){var a=d.bars.reduce(function(a,b){return b.percent=+(100*b.value/b.max).toFixed(2),a+b.percent},0);a>100&&(b.percent-=a-100)},b.$on("$destroy",function(){c=null,d.removeBar(b)})},this.removeBar=function(a){this.bars.splice(this.bars.indexOf(a),1),this.bars.forEach(function(a){a.recalculatePercentage()})},a.$watch("max",function(b){d.bars.forEach(function(b){b.max=a.max,b.recalculatePercentage()})})}]).directive("uibProgress",function(){return{replace:!0,transclude:!0,controller:"UibProgressController",require:"uibProgress",scope:{max:"=?"},templateUrl:"template/progressbar/progress.html"}}).directive("uibBar",function(){return{replace:!0,transclude:!0,require:"^uibProgress",scope:{value:"=",type:"@"},templateUrl:"template/progressbar/bar.html",link:function(a,b,c,d){d.addBar(a,b,c)}}}).directive("uibProgressbar",function(){return{replace:!0,transclude:!0,controller:"UibProgressController",scope:{value:"=",max:"=?",type:"@"},templateUrl:"template/progressbar/progressbar.html",link:function(a,b,c,d){d.addBar(a,angular.element(b.children()[0]),{title:c.title})}}}),angular.module("ui.bootstrap.progressbar").value("$progressSuppressWarning",!1).controller("ProgressController",["$scope","$attrs","uibProgressConfig","$log","$progressSuppressWarning",function(a,b,c,d,e){e||d.warn("ProgressController is now deprecated. Use UibProgressController instead.");var f=this,g=angular.isDefined(b.animate)?a.$parent.$eval(b.animate):c.animate;this.bars=[],a.max=angular.isDefined(a.max)?a.max:c.max,this.addBar=function(b,c,d){g||c.css({transition:"none"}),this.bars.push(b),b.max=a.max,b.title=d&&angular.isDefined(d.title)?d.title:"progressbar",b.$watch("value",function(a){b.recalculatePercentage()}),b.recalculatePercentage=function(){b.percent=+(100*b.value/b.max).toFixed(2);var a=f.bars.reduce(function(a,b){return a+b.percent},0);a>100&&(b.percent-=a-100)},b.$on("$destroy",function(){c=null,f.removeBar(b)})},this.removeBar=function(a){this.bars.splice(this.bars.indexOf(a),1)},a.$watch("max",function(b){f.bars.forEach(function(b){b.max=a.max,b.recalculatePercentage()})})}]).directive("progress",["$log","$progressSuppressWarning",function(a,b){return{replace:!0,transclude:!0,controller:"ProgressController",require:"progress",scope:{max:"=?",title:"@?"},templateUrl:"template/progressbar/progress.html",link:function(){b||a.warn("progress is now deprecated. Use uib-progress instead.")}}}]).directive("bar",["$log","$progressSuppressWarning",function(a,b){return{replace:!0,transclude:!0,require:"^progress",scope:{value:"=",type:"@"},templateUrl:"template/progressbar/bar.html",link:function(c,d,e,f){b||a.warn("bar is now deprecated. Use uib-bar instead."),f.addBar(c,d)}}}]).directive("progressbar",["$log","$progressSuppressWarning",function(a,b){return{replace:!0,transclude:!0,controller:"ProgressController",scope:{value:"=",max:"=?",type:"@"},templateUrl:"template/progressbar/progressbar.html",link:function(c,d,e,f){b||a.warn("progressbar is now deprecated. Use uib-progressbar instead."),f.addBar(c,angular.element(d.children()[0]),{title:e.title})}}}]),angular.module("ui.bootstrap.rating",[]).constant("uibRatingConfig",{max:5,stateOn:null,stateOff:null,titles:["one","two","three","four","five"]}).controller("UibRatingController",["$scope","$attrs","uibRatingConfig",function(a,b,c){var d={$setViewValue:angular.noop};this.init=function(e){d=e,d.$render=this.render,d.$formatters.push(function(a){return angular.isNumber(a)&&a<<0!==a&&(a=Math.round(a)),a}),this.stateOn=angular.isDefined(b.stateOn)?a.$parent.$eval(b.stateOn):c.stateOn,this.stateOff=angular.isDefined(b.stateOff)?a.$parent.$eval(b.stateOff):c.stateOff;var f=angular.isDefined(b.titles)?a.$parent.$eval(b.titles):c.titles;this.titles=angular.isArray(f)&&f.length>0?f:c.titles;var g=angular.isDefined(b.ratingStates)?a.$parent.$eval(b.ratingStates):new Array(angular.isDefined(b.max)?a.$parent.$eval(b.max):c.max);a.range=this.buildTemplateObjects(g)},this.buildTemplateObjects=function(a){for(var b=0,c=a.length;c>b;b++)a[b]=angular.extend({index:b},{stateOn:this.stateOn,stateOff:this.stateOff,title:this.getTitle(b)},a[b]);return a},this.getTitle=function(a){return a>=this.titles.length?a+1:this.titles[a]},a.rate=function(b){!a.readonly&&b>=0&&b<=a.range.length&&(d.$setViewValue(d.$viewValue===b?0:b),d.$render())},a.enter=function(b){a.readonly||(a.value=b),a.onHover({value:b})},a.reset=function(){a.value=d.$viewValue,a.onLeave()},a.onKeydown=function(b){/(37|38|39|40)/.test(b.which)&&(b.preventDefault(),b.stopPropagation(),a.rate(a.value+(38===b.which||39===b.which?1:-1)))},this.render=function(){a.value=d.$viewValue}}]).directive("uibRating",function(){return{require:["uibRating","ngModel"],scope:{readonly:"=?",onHover:"&",onLeave:"&"},controller:"UibRatingController",templateUrl:"template/rating/rating.html",replace:!0,link:function(a,b,c,d){var e=d[0],f=d[1];e.init(f)}}}),angular.module("ui.bootstrap.rating").value("$ratingSuppressWarning",!1).controller("RatingController",["$scope","$attrs","$controller","$log","$ratingSuppressWarning",function(a,b,c,d,e){e||d.warn("RatingController is now deprecated. Use UibRatingController instead."),angular.extend(this,c("UibRatingController",{$scope:a,$attrs:b}))}]).directive("rating",["$log","$ratingSuppressWarning",function(a,b){return{require:["rating","ngModel"],scope:{readonly:"=?",onHover:"&",onLeave:"&"},controller:"RatingController",templateUrl:"template/rating/rating.html",replace:!0,link:function(c,d,e,f){b||a.warn("rating is now deprecated. Use uib-rating instead.");var g=f[0],h=f[1];g.init(h)}}}]),angular.module("ui.bootstrap.tabs",[]).controller("UibTabsetController",["$scope",function(a){var b=this,c=b.tabs=a.tabs=[];b.select=function(a){angular.forEach(c,function(b){b.active&&b!==a&&(b.active=!1,b.onDeselect(),a.selectCalled=!1)}),a.active=!0,a.selectCalled||(a.onSelect(),a.selectCalled=!0)},b.addTab=function(a){c.push(a),1===c.length&&a.active!==!1?a.active=!0:a.active?b.select(a):a.active=!1},b.removeTab=function(a){var e=c.indexOf(a);if(a.active&&c.length>1&&!d){var f=e==c.length-1?e-1:e+1;b.select(c[f])}c.splice(e,1)};var d;a.$on("$destroy",function(){d=!0})}]).directive("uibTabset",function(){return{restrict:"EA",transclude:!0,replace:!0,scope:{type:"@"},controller:"UibTabsetController",templateUrl:"template/tabs/tabset.html",link:function(a,b,c){a.vertical=angular.isDefined(c.vertical)?a.$parent.$eval(c.vertical):!1,a.justified=angular.isDefined(c.justified)?a.$parent.$eval(c.justified):!1}}}).directive("uibTab",["$parse",function(a){return{require:"^uibTabset",restrict:"EA",replace:!0,templateUrl:"template/tabs/tab.html",transclude:!0,scope:{active:"=?",heading:"@",onSelect:"&select",onDeselect:"&deselect"},controller:function(){},link:function(b,c,d,e,f){b.$watch("active",function(a){a&&e.select(b)}),b.disabled=!1,d.disable&&b.$parent.$watch(a(d.disable),function(a){b.disabled=!!a}),b.select=function(){b.disabled||(b.active=!0)},e.addTab(b),b.$on("$destroy",function(){e.removeTab(b)}),b.$transcludeFn=f}}}]).directive("uibTabHeadingTransclude",function(){return{restrict:"A",require:["?^uibTab","?^tab"],link:function(a,b){a.$watch("headingElement",function(a){a&&(b.html(""),b.append(a))})}}}).directive("uibTabContentTransclude",function(){function a(a){return a.tagName&&(a.hasAttribute("tab-heading")||a.hasAttribute("data-tab-heading")||a.hasAttribute("x-tab-heading")||a.hasAttribute("uib-tab-heading")||a.hasAttribute("data-uib-tab-heading")||a.hasAttribute("x-uib-tab-heading")||"tab-heading"===a.tagName.toLowerCase()||"data-tab-heading"===a.tagName.toLowerCase()||"x-tab-heading"===a.tagName.toLowerCase()||"uib-tab-heading"===a.tagName.toLowerCase()||"data-uib-tab-heading"===a.tagName.toLowerCase()||"x-uib-tab-heading"===a.tagName.toLowerCase())}return{restrict:"A",require:["?^uibTabset","?^tabset"],link:function(b,c,d){var e=b.$eval(d.uibTabContentTransclude);e.$transcludeFn(e.$parent,function(b){angular.forEach(b,function(b){a(b)?e.headingElement=b:c.append(b)})})}}}),angular.module("ui.bootstrap.tabs").value("$tabsSuppressWarning",!1).controller("TabsetController",["$scope","$controller","$log","$tabsSuppressWarning",function(a,b,c,d){d||c.warn("TabsetController is now deprecated. Use UibTabsetController instead."),angular.extend(this,b("UibTabsetController",{$scope:a}))}]).directive("tabset",["$log","$tabsSuppressWarning",function(a,b){return{restrict:"EA",transclude:!0,replace:!0,scope:{type:"@"},controller:"TabsetController",templateUrl:"template/tabs/tabset.html",link:function(c,d,e){b||a.warn("tabset is now deprecated. Use uib-tabset instead."),c.vertical=angular.isDefined(e.vertical)?c.$parent.$eval(e.vertical):!1,c.justified=angular.isDefined(e.justified)?c.$parent.$eval(e.justified):!1}}}]).directive("tab",["$parse","$log","$tabsSuppressWarning",function(a,b,c){return{require:"^tabset",restrict:"EA",replace:!0,templateUrl:"template/tabs/tab.html",transclude:!0,scope:{active:"=?",heading:"@",onSelect:"&select",onDeselect:"&deselect"},controller:function(){},link:function(d,e,f,g,h){c||b.warn("tab is now deprecated. Use uib-tab instead."),d.$watch("active",function(a){a&&g.select(d)}),d.disabled=!1,f.disable&&d.$parent.$watch(a(f.disable),function(a){d.disabled=!!a}),d.select=function(){d.disabled||(d.active=!0)},g.addTab(d),d.$on("$destroy",function(){g.removeTab(d)}),d.$transcludeFn=h}}}]).directive("tabHeadingTransclude",["$log","$tabsSuppressWarning",function(a,b){return{restrict:"A",require:"^tab",link:function(c,d){b||a.warn("tab-heading-transclude is now deprecated. Use uib-tab-heading-transclude instead."),c.$watch("headingElement",function(a){a&&(d.html(""),d.append(a))})}}}]).directive("tabContentTransclude",["$log","$tabsSuppressWarning",function(a,b){function c(a){return a.tagName&&(a.hasAttribute("tab-heading")||a.hasAttribute("data-tab-heading")||a.hasAttribute("x-tab-heading")||"tab-heading"===a.tagName.toLowerCase()||"data-tab-heading"===a.tagName.toLowerCase()||"x-tab-heading"===a.tagName.toLowerCase())}return{restrict:"A",require:"^tabset",link:function(d,e,f){b||a.warn("tab-content-transclude is now deprecated. Use uib-tab-content-transclude instead.");var g=d.$eval(f.tabContentTransclude);g.$transcludeFn(g.$parent,function(a){angular.forEach(a,function(a){c(a)?g.headingElement=a:e.append(a)})})}}}]),angular.module("ui.bootstrap.timepicker",[]).constant("uibTimepickerConfig",{hourStep:1,minuteStep:1,showMeridian:!0,meridians:null,readonlyInput:!1,mousewheel:!0,arrowkeys:!0,showSpinners:!0}).controller("UibTimepickerController",["$scope","$element","$attrs","$parse","$log","$locale","uibTimepickerConfig",function(a,b,c,d,e,f,g){function h(){var b=parseInt(a.hours,10),c=a.showMeridian?b>0&&13>b:b>=0&&24>b;return c?(a.showMeridian&&(12===b&&(b=0),a.meridian===r[1]&&(b+=12)),b):void 0}function i(){var b=parseInt(a.minutes,10);return b>=0&&60>b?b:void 0}function j(a){return angular.isDefined(a)&&a.toString().length<2?"0"+a:a.toString()}function k(a){l(),q.$setViewValue(new Date(p)),m(a)}function l(){q.$setValidity("time",!0),a.invalidHours=!1,a.invalidMinutes=!1}function m(b){var c=p.getHours(),d=p.getMinutes();a.showMeridian&&(c=0===c||12===c?12:c%12),a.hours="h"===b?c:j(c),"m"!==b&&(a.minutes=j(d)),a.meridian=p.getHours()<12?r[0]:r[1]}function n(a,b){var c=new Date(a.getTime()+6e4*b),d=new Date(a);return d.setHours(c.getHours(),c.getMinutes()),d}function o(a){p=n(p,a),k()}var p=new Date,q={$setViewValue:angular.noop},r=angular.isDefined(c.meridians)?a.$parent.$eval(c.meridians):g.meridians||f.DATETIME_FORMATS.AMPMS;a.tabindex=angular.isDefined(c.tabindex)?c.tabindex:0,b.removeAttr("tabindex"),this.init=function(b,d){q=b,q.$render=this.render,q.$formatters.unshift(function(a){return a?new Date(a):null});var e=d.eq(0),f=d.eq(1),h=angular.isDefined(c.mousewheel)?a.$parent.$eval(c.mousewheel):g.mousewheel;h&&this.setupMousewheelEvents(e,f);var i=angular.isDefined(c.arrowkeys)?a.$parent.$eval(c.arrowkeys):g.arrowkeys;i&&this.setupArrowkeyEvents(e,f),a.readonlyInput=angular.isDefined(c.readonlyInput)?a.$parent.$eval(c.readonlyInput):g.readonlyInput,this.setupInputEvents(e,f)};var s=g.hourStep;c.hourStep&&a.$parent.$watch(d(c.hourStep),function(a){s=parseInt(a,10)});var t=g.minuteStep;c.minuteStep&&a.$parent.$watch(d(c.minuteStep),function(a){t=parseInt(a,10)});var u;a.$parent.$watch(d(c.min),function(a){var b=new Date(a);u=isNaN(b)?void 0:b});var v;a.$parent.$watch(d(c.max),function(a){var b=new Date(a);v=isNaN(b)?void 0:b}),a.noIncrementHours=function(){var a=n(p,60*s);return a>v||p>a&&u>a},a.noDecrementHours=function(){var a=n(p,60*-s);return u>a||a>p&&a>v},a.noIncrementMinutes=function(){var a=n(p,t);return a>v||p>a&&u>a},a.noDecrementMinutes=function(){var a=n(p,-t);return u>a||a>p&&a>v},a.noToggleMeridian=function(){return p.getHours()<13?n(p,720)>v:n(p,-720)0};b.bind("mousewheel wheel",function(b){a.$apply(d(b)?a.incrementHours():a.decrementHours()),b.preventDefault()}),c.bind("mousewheel wheel",function(b){a.$apply(d(b)?a.incrementMinutes():a.decrementMinutes()),b.preventDefault()})},this.setupArrowkeyEvents=function(b,c){b.bind("keydown",function(b){38===b.which?(b.preventDefault(),a.incrementHours(),a.$apply()):40===b.which&&(b.preventDefault(), +a.decrementHours(),a.$apply())}),c.bind("keydown",function(b){38===b.which?(b.preventDefault(),a.incrementMinutes(),a.$apply()):40===b.which&&(b.preventDefault(),a.decrementMinutes(),a.$apply())})},this.setupInputEvents=function(b,c){if(a.readonlyInput)return a.updateHours=angular.noop,void(a.updateMinutes=angular.noop);var d=function(b,c){q.$setViewValue(null),q.$setValidity("time",!1),angular.isDefined(b)&&(a.invalidHours=b),angular.isDefined(c)&&(a.invalidMinutes=c)};a.updateHours=function(){var a=h(),b=i();angular.isDefined(a)&&angular.isDefined(b)?(p.setHours(a),u>p||p>v?d(!0):k("h")):d(!0)},b.bind("blur",function(b){!a.invalidHours&&a.hours<10&&a.$apply(function(){a.hours=j(a.hours)})}),a.updateMinutes=function(){var a=i(),b=h();angular.isDefined(a)&&angular.isDefined(b)?(p.setMinutes(a),u>p||p>v?d(void 0,!0):k("m")):d(void 0,!0)},c.bind("blur",function(b){!a.invalidMinutes&&a.minutes<10&&a.$apply(function(){a.minutes=j(a.minutes)})})},this.render=function(){var b=q.$viewValue;isNaN(b)?(q.$setValidity("time",!1),e.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.')):(b&&(p=b),u>p||p>v?(q.$setValidity("time",!1),a.invalidHours=!0,a.invalidMinutes=!0):l(),m())},a.showSpinners=angular.isDefined(c.showSpinners)?a.$parent.$eval(c.showSpinners):g.showSpinners,a.incrementHours=function(){a.noIncrementHours()||o(60*s)},a.decrementHours=function(){a.noDecrementHours()||o(60*-s)},a.incrementMinutes=function(){a.noIncrementMinutes()||o(t)},a.decrementMinutes=function(){a.noDecrementMinutes()||o(-t)},a.toggleMeridian=function(){a.noToggleMeridian()||o(720*(p.getHours()<12?1:-1))}}]).directive("uibTimepicker",function(){return{restrict:"EA",require:["uibTimepicker","?^ngModel"],controller:"UibTimepickerController",controllerAs:"timepicker",replace:!0,scope:{},templateUrl:function(a,b){return b.templateUrl||"template/timepicker/timepicker.html"},link:function(a,b,c,d){var e=d[0],f=d[1];f&&e.init(f,b.find("input"))}}}),angular.module("ui.bootstrap.timepicker").value("$timepickerSuppressWarning",!1).controller("TimepickerController",["$scope","$element","$attrs","$controller","$log","$timepickerSuppressWarning",function(a,b,c,d,e,f){f||e.warn("TimepickerController is now deprecated. Use UibTimepickerController instead."),angular.extend(this,d("UibTimepickerController",{$scope:a,$element:b,$attrs:c}))}]).directive("timepicker",["$log","$timepickerSuppressWarning",function(a,b){return{restrict:"EA",require:["timepicker","?^ngModel"],controller:"TimepickerController",controllerAs:"timepicker",replace:!0,scope:{},templateUrl:function(a,b){return b.templateUrl||"template/timepicker/timepicker.html"},link:function(c,d,e,f){b||a.warn("timepicker is now deprecated. Use uib-timepicker instead.");var g=f[0],h=f[1];h&&g.init(h,d.find("input"))}}}]),angular.module("ui.bootstrap.typeahead",["ui.bootstrap.position"]).factory("uibTypeaheadParser",["$parse",function(a){var b=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;return{parse:function(c){var d=c.match(b);if(!d)throw new Error('Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_" but got "'+c+'".');return{itemName:d[3],source:a(d[4]),viewMapper:a(d[2]||d[1]),modelMapper:a(d[1])}}}}]).controller("UibTypeaheadController",["$scope","$element","$attrs","$compile","$parse","$q","$timeout","$document","$window","$rootScope","$uibPosition","uibTypeaheadParser",function(a,b,c,d,e,f,g,h,i,j,k,l){function m(){K.moveInProgress||(K.moveInProgress=!0,K.$digest()),S&&g.cancel(S),S=g(function(){K.matches.length&&n(),K.moveInProgress=!1},r)}function n(){K.position=C?k.offset(b):k.position(b),K.position.top+=b.prop("offsetHeight")}var o,p,q=[9,13,27,38,40],r=200,s=a.$eval(c.typeaheadMinLength);s||0===s||(s=1);var t,u,v=a.$eval(c.typeaheadWaitMs)||0,w=a.$eval(c.typeaheadEditable)!==!1,x=e(c.typeaheadLoading).assign||angular.noop,y=e(c.typeaheadOnSelect),z=angular.isDefined(c.typeaheadSelectOnBlur)?a.$eval(c.typeaheadSelectOnBlur):!1,A=e(c.typeaheadNoResults).assign||angular.noop,B=c.typeaheadInputFormatter?e(c.typeaheadInputFormatter):void 0,C=c.typeaheadAppendToBody?a.$eval(c.typeaheadAppendToBody):!1,D=c.typeaheadAppendToElementId||!1,E=a.$eval(c.typeaheadFocusFirst)!==!1,F=c.typeaheadSelectOnExact?a.$eval(c.typeaheadSelectOnExact):!1,G=e(c.ngModel),H=e(c.ngModel+"($$$p)"),I=function(b,c){return angular.isFunction(G(a))&&p&&p.$options&&p.$options.getterSetter?H(b,{$$$p:c}):G.assign(b,c)},J=l.parse(c.uibTypeahead),K=a.$new(),L=a.$on("$destroy",function(){K.$destroy()});K.$on("$destroy",L);var M="typeahead-"+K.$id+"-"+Math.floor(1e4*Math.random());b.attr({"aria-autocomplete":"list","aria-expanded":!1,"aria-owns":M});var N=angular.element("
        ");N.attr({id:M,matches:"matches",active:"activeIdx",select:"select(activeIdx)","move-in-progress":"moveInProgress",query:"query",position:"position"}),angular.isDefined(c.typeaheadTemplateUrl)&&N.attr("template-url",c.typeaheadTemplateUrl),angular.isDefined(c.typeaheadPopupTemplateUrl)&&N.attr("popup-template-url",c.typeaheadPopupTemplateUrl);var O=function(){K.matches=[],K.activeIdx=-1,b.attr("aria-expanded",!1)},P=function(a){return M+"-option-"+a};K.$watch("activeIdx",function(a){0>a?b.removeAttr("aria-activedescendant"):b.attr("aria-activedescendant",P(a))});var Q=function(a,b){return K.matches.length>b&&a?a.toUpperCase()===K.matches[b].label.toUpperCase():!1},R=function(c){var d={$viewValue:c};x(a,!0),A(a,!1),f.when(J.source(a,d)).then(function(e){var f=c===o.$viewValue;if(f&&t)if(e&&e.length>0){K.activeIdx=E?0:-1,A(a,!1),K.matches.length=0;for(var g=0;g0?K.activeIdx:K.matches.length)-1,K.$digest()):13===a.which||9===a.which?K.$apply(function(){K.select(K.activeIdx)}):27===a.which&&(a.stopPropagation(),O(),K.$digest())}}),b.bind("blur",function(){z&&K.matches.length&&-1!==K.activeIdx&&!u&&(u=!0,K.$apply(function(){K.select(K.activeIdx)})),t=!1,u=!1});var W=function(a){b[0]!==a.target&&3!==a.which&&0!==K.matches.length&&(O(),j.$$phase||K.$digest())};h.bind("click",W),a.$on("$destroy",function(){h.unbind("click",W),(C||D)&&X.remove(),C&&(angular.element(i).unbind("resize",m),h.find("body").unbind("scroll",m)),N.remove()});var X=d(N)(K);C?h.find("body").append(X):D!==!1?angular.element(h[0].getElementById(D)).append(X):b.after(X),this.init=function(b,c){o=b,p=c,o.$parsers.unshift(function(b){return t=!0,0===s||b&&b.length>=s?v>0?(V(),U(b)):R(b):(x(a,!1),V(),O()),w?b:b?void o.$setValidity("editable",!1):(o.$setValidity("editable",!0),null)}),o.$formatters.push(function(b){var c,d,e={};return w||o.$setValidity("editable",!0),B?(e.$model=b,B(a,e)):(e[J.itemName]=b,c=J.viewMapper(a,e),e[J.itemName]=void 0,d=J.viewMapper(a,e),c!==d?c:b)})}}]).directive("uibTypeahead",function(){return{controller:"UibTypeaheadController",require:["ngModel","^?ngModelOptions","uibTypeahead"],link:function(a,b,c,d){d[2].init(d[0],d[1])}}}).directive("uibTypeaheadPopup",function(){return{scope:{matches:"=",query:"=",active:"=",position:"&",moveInProgress:"=",select:"&"},replace:!0,templateUrl:function(a,b){return b.popupTemplateUrl||"template/typeahead/typeahead-popup.html"},link:function(a,b,c){a.templateUrl=c.templateUrl,a.isOpen=function(){return a.matches.length>0},a.isActive=function(b){return a.active==b},a.selectActive=function(b){a.active=b},a.selectMatch=function(b){a.select({activeIdx:b})}}}}).directive("uibTypeaheadMatch",["$templateRequest","$compile","$parse",function(a,b,c){return{scope:{index:"=",match:"=",query:"="},link:function(d,e,f){var g=c(f.templateUrl)(d.$parent)||"template/typeahead/typeahead-match.html";a(g).then(function(a){b(a.trim())(d,function(a){e.replaceWith(a)})})}}}]).filter("uibTypeaheadHighlight",["$sce","$injector","$log",function(a,b,c){function d(a){return a.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}function e(a){return/<.*>/g.test(a)}var f;return f=b.has("$sanitize"),function(b,g){return!f&&e(b)&&c.warn("Unsafe use of typeahead please use ngSanitize"),b=g?(""+b).replace(new RegExp(d(g),"gi"),"$&"):b,f||(b=a.trustAsHtml(b)),b}}]),angular.module("ui.bootstrap.typeahead").value("$typeaheadSuppressWarning",!1).service("typeaheadParser",["$parse","uibTypeaheadParser","$log","$typeaheadSuppressWarning",function(a,b,c,d){return d||c.warn("typeaheadParser is now deprecated. Use uibTypeaheadParser instead."),b}]).directive("typeahead",["$compile","$parse","$q","$timeout","$document","$window","$rootScope","$uibPosition","typeaheadParser","$log","$typeaheadSuppressWarning",function(a,b,c,d,e,f,g,h,i,j,k){var l=[9,13,27,38,40],m=200;return{require:["ngModel","^?ngModelOptions"],link:function(n,o,p,q){function r(){N.moveInProgress||(N.moveInProgress=!0,N.$digest()),V&&d.cancel(V),V=d(function(){N.matches.length&&s(),N.moveInProgress=!1},m)}function s(){N.position=F?h.offset(o):h.position(o),N.position.top+=o.prop("offsetHeight")}k||j.warn("typeahead is now deprecated. Use uib-typeahead instead.");var t=q[0],u=q[1],v=n.$eval(p.typeaheadMinLength);v||0===v||(v=1);var w,x,y=n.$eval(p.typeaheadWaitMs)||0,z=n.$eval(p.typeaheadEditable)!==!1,A=b(p.typeaheadLoading).assign||angular.noop,B=b(p.typeaheadOnSelect),C=angular.isDefined(p.typeaheadSelectOnBlur)?n.$eval(p.typeaheadSelectOnBlur):!1,D=b(p.typeaheadNoResults).assign||angular.noop,E=p.typeaheadInputFormatter?b(p.typeaheadInputFormatter):void 0,F=p.typeaheadAppendToBody?n.$eval(p.typeaheadAppendToBody):!1,G=p.typeaheadAppendToElementId||!1,H=n.$eval(p.typeaheadFocusFirst)!==!1,I=p.typeaheadSelectOnExact?n.$eval(p.typeaheadSelectOnExact):!1,J=b(p.ngModel),K=b(p.ngModel+"($$$p)"),L=function(a,b){return angular.isFunction(J(n))&&u&&u.$options&&u.$options.getterSetter?K(a,{$$$p:b}):J.assign(a,b)},M=i.parse(p.typeahead),N=n.$new(),O=n.$on("$destroy",function(){N.$destroy()});N.$on("$destroy",O);var P="typeahead-"+N.$id+"-"+Math.floor(1e4*Math.random());o.attr({"aria-autocomplete":"list","aria-expanded":!1,"aria-owns":P});var Q=angular.element("
        ");Q.attr({id:P,matches:"matches",active:"activeIdx",select:"select(activeIdx)","move-in-progress":"moveInProgress",query:"query",position:"position"}),angular.isDefined(p.typeaheadTemplateUrl)&&Q.attr("template-url",p.typeaheadTemplateUrl),angular.isDefined(p.typeaheadPopupTemplateUrl)&&Q.attr("popup-template-url",p.typeaheadPopupTemplateUrl);var R=function(){N.matches=[],N.activeIdx=-1,o.attr("aria-expanded",!1)},S=function(a){return P+"-option-"+a};N.$watch("activeIdx",function(a){0>a?o.removeAttr("aria-activedescendant"):o.attr("aria-activedescendant",S(a))});var T=function(a,b){return N.matches.length>b&&a?a.toUpperCase()===N.matches[b].label.toUpperCase():!1},U=function(a){var b={$viewValue:a};A(n,!0),D(n,!1),c.when(M.source(n,b)).then(function(c){var d=a===t.$viewValue;if(d&&w)if(c&&c.length>0){N.activeIdx=H?0:-1,D(n,!1),N.matches.length=0;for(var e=0;e=v?y>0?(Y(),X(a)):U(a):(A(n,!1),Y(),R()),z?a:a?void t.$setValidity("editable",!1):(t.$setValidity("editable",!0),null)}),t.$formatters.push(function(a){var b,c,d={};return z||t.$setValidity("editable",!0),E?(d.$model=a,E(n,d)):(d[M.itemName]=a,b=M.viewMapper(n,d),d[M.itemName]=void 0,c=M.viewMapper(n,d),b!==c?b:a)}),N.select=function(a){var b,c,e={};x=!0,e[M.itemName]=c=N.matches[a].model,b=M.modelMapper(n,e),L(n,b),t.$setValidity("editable",!0),t.$setValidity("parse",!0),B(n,{$item:c,$model:b,$label:M.viewMapper(n,e)}),R(),N.$eval(p.typeaheadFocusOnSelect)!==!1&&d(function(){o[0].focus()},0,!1)},o.bind("keydown",function(a){if(0!==N.matches.length&&-1!==l.indexOf(a.which)){if(-1===N.activeIdx&&(9===a.which||13===a.which))return R(),void N.$digest();a.preventDefault(),40===a.which?(N.activeIdx=(N.activeIdx+1)%N.matches.length,N.$digest()):38===a.which?(N.activeIdx=(N.activeIdx>0?N.activeIdx:N.matches.length)-1,N.$digest()):13===a.which||9===a.which?N.$apply(function(){N.select(N.activeIdx)}):27===a.which&&(a.stopPropagation(),R(),N.$digest())}}),o.bind("blur",function(){C&&N.matches.length&&-1!==N.activeIdx&&!x&&(x=!0,N.$apply(function(){N.select(N.activeIdx)})),w=!1,x=!1});var Z=function(a){o[0]!==a.target&&3!==a.which&&0!==N.matches.length&&(R(),g.$$phase||N.$digest())};e.bind("click",Z),n.$on("$destroy",function(){e.unbind("click",Z),(F||G)&&$.remove(),F&&(angular.element(f).unbind("resize",r),e.find("body").unbind("scroll",r)),Q.remove()});var $=a(Q)(N);F?e.find("body").append($):G!==!1?angular.element(e[0].getElementById(G)).append($):o.after($)}}}]).directive("typeaheadPopup",["$typeaheadSuppressWarning","$log",function(a,b){return{scope:{matches:"=",query:"=",active:"=",position:"&",moveInProgress:"=",select:"&"},replace:!0,templateUrl:function(a,b){return b.popupTemplateUrl||"template/typeahead/typeahead-popup.html"},link:function(c,d,e){a||b.warn("typeahead-popup is now deprecated. Use uib-typeahead-popup instead."),c.templateUrl=e.templateUrl,c.isOpen=function(){return c.matches.length>0},c.isActive=function(a){return c.active==a},c.selectActive=function(a){c.active=a},c.selectMatch=function(a){c.select({activeIdx:a})}}}}]).directive("typeaheadMatch",["$templateRequest","$compile","$parse","$typeaheadSuppressWarning","$log",function(a,b,c,d,e){return{restrict:"EA",scope:{index:"=",match:"=",query:"="},link:function(f,g,h){d||e.warn("typeahead-match is now deprecated. Use uib-typeahead-match instead.");var i=c(h.templateUrl)(f.$parent)||"template/typeahead/typeahead-match.html";a(i).then(function(a){b(a.trim())(f,function(a){g.replaceWith(a)})})}}}]).filter("typeaheadHighlight",["$sce","$injector","$log","$typeaheadSuppressWarning",function(a,b,c,d){function e(a){return a.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}function f(a){return/<.*>/g.test(a)}var g;return g=b.has("$sanitize"),function(b,h){return d||c.warn("typeaheadHighlight is now deprecated. Use uibTypeaheadHighlight instead."),!g&&f(b)&&c.warn("Unsafe use of typeahead please use ngSanitize"),b=h?(""+b).replace(new RegExp(e(h),"gi"),"$&"):b,g||(b=a.trustAsHtml(b)),b}}]),!angular.$$csp()&&angular.element(document).find("head").prepend(''); \ No newline at end of file diff --git a/bower_components/angular-ui-sortable/sortable.min.js b/bower_components/angular-ui-sortable/sortable.min.js new file mode 100644 index 00000000..83b227e0 --- /dev/null +++ b/bower_components/angular-ui-sortable/sortable.min.js @@ -0,0 +1 @@ +!function(a,b){"use strict";b.module("ui.sortable",[]).value("uiSortableConfig",{}).directive("uiSortable",["uiSortableConfig","$timeout","$log",function(a,c,d){return{require:"?ngModel",link:function(e,f,g,h){function i(a,b){return b&&"function"==typeof b?function(c,d){a(c,d),b(c,d)}:a}function j(a,b){var c=a.sortable("option","helper");return"clone"===c||"function"==typeof c&&b.item.sortable.isCustomHelperUsed()}var k,l={},m={receive:null,remove:null,start:null,stop:null,update:null},n={helper:null};return b.extend(l,a,e.$eval(g.uiSortable)),b.element.fn&&b.element.fn.jquery?(h?(e.$watch(g.ngModel+".length",function(){c(function(){f.data("ui-sortable")&&f.sortable("refresh")})}),m.start=function(a,b){b.item.sortable={index:b.item.index(),cancel:function(){b.item.sortable._isCanceled=!0},isCanceled:function(){return b.item.sortable._isCanceled},isCustomHelperUsed:function(){return!!b.item.sortable._isCustomHelperUsed},_isCanceled:!1,_isCustomHelperUsed:b.item.sortable._isCustomHelperUsed}},m.activate=function(){k=f.contents();var a=f.sortable("option","placeholder");if(a&&a.element&&"function"==typeof a.element){var c=a.element();c=b.element(c);var d=f.find('[class="'+c.attr("class")+'"]');k=k.not(d)}},m.update=function(a,b){b.item.sortable.received||(b.item.sortable.dropindex=b.item.index(),b.item.sortable.droptarget=b.item.parent(),f.sortable("cancel")),j(f,b)&&!b.item.sortable.received&&"parent"===f.sortable("option","appendTo")&&(k=k.not(k.last())),k.appendTo(f),b.item.sortable.received&&(k=null),b.item.sortable.received&&!b.item.sortable.isCanceled()&&e.$apply(function(){h.$modelValue.splice(b.item.sortable.dropindex,0,b.item.sortable.moved)})},m.stop=function(a,b){!b.item.sortable.received&&"dropindex"in b.item.sortable&&!b.item.sortable.isCanceled()?e.$apply(function(){h.$modelValue.splice(b.item.sortable.dropindex,0,h.$modelValue.splice(b.item.sortable.index,1)[0])}):"dropindex"in b.item.sortable&&!b.item.sortable.isCanceled()||j(f,b)||k.appendTo(f),k=null},m.receive=function(a,b){b.item.sortable.received=!0},m.remove=function(a,b){"dropindex"in b.item.sortable||(f.sortable("cancel"),b.item.sortable.cancel()),b.item.sortable.isCanceled()||e.$apply(function(){b.item.sortable.moved=h.$modelValue.splice(b.item.sortable.index,1)[0]})},n.helper=function(a){return a&&"function"==typeof a?function(b,c){var d=a(b,c);return c.sortable._isCustomHelperUsed=c!==d,d}:a},e.$watch(g.uiSortable,function(a){f.data("ui-sortable")&&b.forEach(a,function(a,b){m[b]?("stop"===b&&(a=i(a,function(){e.$apply()})),a=i(m[b],a)):n[b]&&(a=n[b](a)),f.sortable("option",b,a)})},!0),b.forEach(m,function(a,b){l[b]=i(a,l[b])})):d.info("ui.sortable: ngModel not provided!",f),void f.sortable(l)):void d.error("ui.sortable: jQuery should be included before AngularJS!")}}}])}(window,window.angular); \ No newline at end of file diff --git a/bower_components/angular/angular.min.js b/bower_components/angular/angular.min.js new file mode 100644 index 00000000..65223c3b --- /dev/null +++ b/bower_components/angular/angular.min.js @@ -0,0 +1,309 @@ +/* + AngularJS v1.5.2 + (c) 2010-2016 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(N,Q,w){'use strict';function O(a){return function(){var b=arguments[0],d;d="["+(a?a+":":"")+b+"] http://errors.angularjs.org/1.5.2/"+(a?a+"/":"")+b;for(b=1;b").append(a).html();try{return a[0].nodeType===Na?E(d):d.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+E(b)})}catch(c){return E(d)}}function vc(a){try{return decodeURIComponent(a)}catch(b){}} +function wc(a){var b={};p((a||"").split("&"),function(a){var c,e,f;a&&(e=a=a.replace(/\+/g,"%20"),c=a.indexOf("="),-1!==c&&(e=a.substring(0,c),f=a.substring(c+1)),e=vc(e),A(e)&&(f=A(f)?vc(f):!0,sa.call(b,e)?L(b[e])?b[e].push(f):b[e]=[b[e],f]:b[e]=f))});return b}function Rb(a){var b=[];p(a,function(a,c){L(a)?p(a,function(a){b.push(ja(c,!0)+(!0===a?"":"="+ja(a,!0)))}):b.push(ja(c,!0)+(!0===a?"":"="+ja(a,!0)))});return b.length?b.join("&"):""}function qb(a){return ja(a,!0).replace(/%26/gi,"&").replace(/%3D/gi, +"=").replace(/%2B/gi,"+")}function ja(a,b){return encodeURIComponent(a).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,b?"%20":"+")}function ae(a,b){var d,c,e=Oa.length;for(c=0;c/,">"));}b=b||[];b.unshift(["$provide",function(b){b.value("$rootElement",a)}]);d.debugInfoEnabled&&b.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);b.unshift("ng");c=db(b,d.strictDi);c.invoke(["$rootScope", +"$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},e=/^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;N&&e.test(N.name)&&(d.debugInfoEnabled=!0,N.name=N.name.replace(e,""));if(N&&!f.test(N.name))return c();N.name=N.name.replace(f,"");ea.resumeBootstrap=function(a){p(a,function(a){b.push(a)});return c()};H(ea.resumeDeferredBootstrap)&&ea.resumeDeferredBootstrap()}function ce(){N.name="NG_ENABLE_DEBUG_INFO!"+N.name;N.location.reload()} +function de(a){a=ea.element(a).injector();if(!a)throw Da("test");return a.get("$$testability")}function yc(a,b){b=b||"_";return a.replace(ee,function(a,c){return(c?b:"")+a.toLowerCase()})}function fe(){var a;if(!zc){var b=rb();(ra=v(b)?N.jQuery:b?N[b]:w)&&ra.fn.on?(G=ra,S(ra.fn,{scope:Pa.scope,isolateScope:Pa.isolateScope,controller:Pa.controller,injector:Pa.injector,inheritedData:Pa.inheritedData}),a=ra.cleanData,ra.cleanData=function(b){for(var c,e=0,f;null!=(f=b[e]);e++)(c=ra._data(f,"events"))&& +c.$destroy&&ra(f).triggerHandler("$destroy");a(b)}):G=Y;ea.element=G;zc=!0}}function sb(a,b,d){if(!a)throw Da("areq",b||"?",d||"required");return a}function Qa(a,b,d){d&&L(a)&&(a=a[a.length-1]);sb(H(a),b,"not a function, got "+(a&&"object"===typeof a?a.constructor.name||"Object":typeof a));return a}function Ra(a,b){if("hasOwnProperty"===a)throw Da("badname",b);}function Ac(a,b,d){if(!b)return a;b=b.split(".");for(var c,e=a,f=b.length,g=0;g")+c[2];for(c=c[0];c--;)d=d.lastChild;f=bb(f,d.childNodes);d=e.firstChild;d.textContent=""}else f.push(b.createTextNode(a));e.textContent="";e.innerHTML="";p(f,function(a){e.appendChild(a)});return e}function Lc(a, +b){var d=a.parentNode;d&&d.replaceChild(b,a);b.appendChild(a)}function Y(a){if(a instanceof Y)return a;var b;D(a)&&(a=Z(a),b=!0);if(!(this instanceof Y)){if(b&&"<"!=a.charAt(0))throw Ub("nosel");return new Y(a)}if(b){b=Q;var d;a=(d=Jf.exec(a))?[b.createElement(d[1])]:(d=Kc(a,b))?d.childNodes:[]}Mc(this,a)}function Vb(a){return a.cloneNode(!0)}function wb(a,b){b||fb(a);if(a.querySelectorAll)for(var d=a.querySelectorAll("*"),c=0,e=d.length;c=za?!1:"function"===typeof a&&/^(?:class\s|constructor\()/.test(Function.prototype.toString.call(a));return d?(c.unshift(null),new (Function.prototype.bind.apply(a,c))):a.apply(b,c)},instantiate:function(a,b,c){var d=L(a)?a[a.length-1]:a;a=e(a,b,c);a.unshift(null);return new (Function.prototype.bind.apply(d,a))},get:d,annotate:db.$$annotate,has:function(b){return n.hasOwnProperty(b+ +"Provider")||a.hasOwnProperty(b)}}}b=!0===b;var k={},l=[],m=new Sa([],!0),n={$provide:{provider:d(c),factory:d(f),service:d(function(a,b){return f(a,["$injector",function(a){return a.instantiate(b)}])}),value:d(function(a,b){return f(a,ia(b),!1)}),constant:d(function(a,b){Ra(a,"constant");n[a]=b;B[a]=b}),decorator:function(a,b){var c=y.get(a+"Provider"),d=c.$get;c.$get=function(){var a=x.invoke(d,c);return x.invoke(b,null,{$delegate:a})}}}},y=n.$injector=h(n,function(a,b){ea.isString(b)&&l.push(b); +throw Ga("unpr",l.join(" <- "));}),B={},K=h(B,function(a,b){var c=y.get(a+"Provider",b);return x.invoke(c.$get,c,w,a)}),x=K;n.$injectorProvider={$get:ia(K)};var q=g(a),x=K.get("$injector");x.strictDi=b;p(q,function(a){a&&x.invoke(a)});return x}function Te(){var a=!0;this.disableAutoScrolling=function(){a=!1};this.$get=["$window","$location","$rootScope",function(b,d,c){function e(a){var b=null;Array.prototype.some.call(a,function(a){if("a"===pa(a))return b=a,!0});return b}function f(a){if(a){a.scrollIntoView(); +var c;c=g.yOffset;H(c)?c=c():Ob(c)?(c=c[0],c="fixed"!==b.getComputedStyle(c).position?0:c.getBoundingClientRect().bottom):W(c)||(c=0);c&&(a=a.getBoundingClientRect().top,b.scrollBy(0,a-c))}else b.scrollTo(0,0)}function g(a){a=D(a)?a:d.hash();var b;a?(b=h.getElementById(a))?f(b):(b=e(h.getElementsByName(a)))?f(b):"top"===a&&f(null):f(null)}var h=b.document;a&&c.$watch(function(){return d.hash()},function(a,b){a===b&&""===a||Lf(function(){c.$evalAsync(g)})});return g}]}function hb(a,b){if(!a&&!b)return""; +if(!a)return b;if(!b)return a;L(a)&&(a=a.join(" "));L(b)&&(b=b.join(" "));return a+" "+b}function Uf(a){D(a)&&(a=a.split(" "));var b=X();p(a,function(a){a.length&&(b[a]=!0)});return b}function Ha(a){return I(a)?a:{}}function Vf(a,b,d,c){function e(a){try{a.apply(null,ya.call(arguments,1))}finally{if(K--,0===K)for(;x.length;)try{x.pop()()}catch(b){d.error(b)}}}function f(){M=null;g();h()}function g(){a:{try{q=m.state;break a}catch(a){}q=void 0}q=v(q)?null:q;oa(q,T)&&(q=T);T=q}function h(){if(u!==k.url()|| +t!==q)u=k.url(),t=q,p(C,function(a){a(k.url(),q)})}var k=this,l=a.location,m=a.history,n=a.setTimeout,y=a.clearTimeout,B={};k.isMock=!1;var K=0,x=[];k.$$completeOutstandingRequest=e;k.$$incOutstandingRequestCount=function(){K++};k.notifyWhenNoOutstandingRequests=function(a){0===K?a():x.push(a)};var q,t,u=l.href,s=b.find("base"),M=null;g();t=q;k.url=function(b,d,e){v(e)&&(e=null);l!==a.location&&(l=a.location);m!==a.history&&(m=a.history);if(b){var f=t===e;if(u===b&&(!c.history||f))return k;var h= +u&&Ia(u)===Ia(b);u=b;t=e;if(!c.history||h&&f){if(!h||M)M=b;d?l.replace(b):h?(d=l,e=b.indexOf("#"),e=-1===e?"":b.substr(e),d.hash=e):l.href=b;l.href!==b&&(M=b)}else m[d?"replaceState":"pushState"](e,"",b),g(),t=q;return k}return M||l.href.replace(/%27/g,"'")};k.state=function(){return q};var C=[],J=!1,T=null;k.onUrlChange=function(b){if(!J){if(c.history)G(a).on("popstate",f);G(a).on("hashchange",f);J=!0}C.push(b);return b};k.$$applicationDestroyed=function(){G(a).off("hashchange popstate",f)};k.$$checkUrlChange= +h;k.baseHref=function(){var a=s.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};k.defer=function(a,b){var c;K++;c=n(function(){delete B[c];e(a)},b||0);B[c]=!0;return c};k.defer.cancel=function(a){return B[a]?(delete B[a],y(a),e(z),!0):!1}}function $e(){this.$get=["$window","$log","$sniffer","$document",function(a,b,d,c){return new Vf(a,c,b,d)}]}function af(){this.$get=function(){function a(a,c){function e(a){a!=n&&(y?y==a&&(y=a.n):y=a,f(a.n,a.p),f(a,n),n=a,n.n=null)}function f(a, +b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(a in b)throw O("$cacheFactory")("iid",a);var g=0,h=S({},c,{id:a}),k=X(),l=c&&c.capacity||Number.MAX_VALUE,m=X(),n=null,y=null;return b[a]={put:function(a,b){if(!v(b)){if(ll&&this.remove(y.key);return b}},get:function(a){if(l";b=fa.firstChild.attributes;var d=b[0];b.removeNamedItem(d.name);d.value=c;a.attributes.setNamedItem(d)}function $(a,b){try{a.addClass(b)}catch(c){}}function R(a,b,c,d,e){a instanceof G||(a=G(a));for(var f=/\S+/,g=0,h=a.length;g").append(a).html())):c?Pa.clone.call(a):a;if(g)for(var h in g)d.data("$"+h+"Controller",g[h].instance);R.$$addScopeInfo(d, +b);c&&c(d,b);l&&l(b,d,d,f);return d}}function P(a,b,c,d,e,f){function g(a,c,d,e){var f,k,l,m,n,C,u;if(q)for(u=Array(c.length),m=0;ms.priority)break;if(E=s.scope)s.templateUrl||(I(E)?(aa("new/isolated scope",t||C,s,P),t=s):aa("new/isolated scope",t,s,P)),C=C||s;K=s.name;if(!va&&(s.replace&&(s.templateUrl||s.template)||s.transclude&& +!s.$$tlb)){for(E=Q+1;va=a[E++];)if(va.transclude&&!va.$$tlb||va.replace&&(va.templateUrl||va.template)){N=!0;break}va=!0}!s.templateUrl&&s.controller&&(E=s.controller,u=u||X(),aa("'"+K+"' controller",u[K],s,P),u[K]=s);if(E=s.transclude)if(F=!0,s.$$tlb||(aa("transclusion",B,s,P),B=s),"element"==E)M=!0,q=s.priority,ca=P,P=d.$$element=G(R.$$createComment(K,d[K])),b=P[0],ga(f,ya.call(ca,0),b),z=Yb(N,ca,e,q,g&&g.name,{nonTlbTranscludeDirective:B});else{var U=X();ca=G(Vb(b)).contents();if(I(E)){ca=[];var ea= +X(),fa=X();p(E,function(a,b){var c="?"===a.charAt(0);a=c?a.substring(1):a;ea[a]=b;U[b]=null;fa[b]=c});p(P.contents(),function(a){var b=ea[ua(pa(a))];b?(fa[b]=!0,U[b]=U[b]||[],U[b].push(a)):ca.push(a)});p(fa,function(a,b){if(!a)throw la("reqslot",b);});for(var ha in U)U[ha]&&(U[ha]=Yb(N,U[ha],e))}P.empty();z=Yb(N,ca,e,w,w,{needsNewScope:s.$$isolateScope||s.$$newScope});z.$$slots=U}if(s.template)if($=!0,aa("template",J,s,P),J=s,E=H(s.template)?s.template(P,d):s.template,E=ra(E),s.replace){g=s;ca=Tb.test(E)? +Vc(da(s.templateNamespace,Z(E))):[];b=ca[0];if(1!=ca.length||1!==b.nodeType)throw la("tplrt",K,"");ga(f,P,b);Ua={$attr:{}};E=Aa(b,[],Ua);var ka=a.splice(Q+1,a.length-(Q+1));(t||C)&&Wc(E,t,C);a=a.concat(E).concat(ka);W(d,Ua);Ua=a.length}else P.html(E);if(s.templateUrl)$=!0,aa("template",J,s,P),J=s,s.replace&&(g=s),n=Y(a.splice(Q,a.length-Q),P,d,f,F&&z,h,k,{controllerDirectives:u,newScopeDirective:C!==s&&C,newIsolateScopeDirective:t,templateDirective:J,nonTlbTranscludeDirective:B}),Ua=a.length;else if(s.compile)try{D= +s.compile(P,d,z),H(D)?m(null,D,V,ba):D&&m(D.pre,D.post,V,ba)}catch(Wf){c(Wf,ta(P))}s.terminal&&(n.terminal=!0,q=Math.max(q,s.priority))}n.scope=C&&!0===C.scope;n.transcludeOnThisElement=F;n.templateOnThisElement=$;n.transclude=z;l.hasElementTranscludeDirective=M;return n}function ib(a,b,c,d){var e;if(D(b)){var f=b.match(k);b=b.substring(f[0].length);var g=f[1]||f[3],f="?"===f[2];"^^"===g?c=c.parent():e=(e=d&&d[b])&&e.instance;if(!e){var h="$"+b+"Controller";e=g?c.inheritedData(h):c.data(h)}if(!e&& +!f)throw la("ctreq",b,a);}else if(L(b))for(e=[],g=0,f=b.length;gn.priority)&&-1!=n.restrict.indexOf(g)){l&&(n=Pb(n,{$$start:l,$$end:m}));if(!n.$$bindings){var u=n,t=n,J=n.name,s={isolateScope:null,bindToController:null};I(t.scope)&&(!0===t.bindToController?(s.bindToController=d(t.scope,J,!0),s.isolateScope={}):s.isolateScope=d(t.scope,J,!1));I(t.bindToController)&&(s.bindToController=d(t.bindToController, +J,!0));if(I(s.bindToController)){var F=t.controller,$=t.controllerAs;if(!F)throw la("noctrl",J);if(!Tc(F,$))throw la("noident",J);}var T=u.$$bindings=s;I(T.isolateScope)&&(n.$$isolateBindings=T.isolateScope)}b.push(n);k=n}}catch(P){c(P)}}return k}function va(b){if(e.hasOwnProperty(b))for(var c=a.get(b+"Directive"),d=0,f=c.length;d"+b+"";return c.childNodes[0].childNodes;default:return b}}function U(a,b){if("srcdoc"==b)return M.HTML;var c=pa(a);if("xlinkHref"== +b||"form"==c&&"action"==b||"img"!=c&&("src"==b||"ngSrc"==b))return M.RESOURCE_URL}function ea(a,c,d,e,f){var g=U(a,e);f=h[e]||f;var k=b(d,!0,g,f);if(k){if("multiple"===e&&"select"===pa(a))throw la("selmulti",ta(a));c.push({priority:100,compile:function(){return{pre:function(a,c,h){c=h.$$observers||(h.$$observers=X());if(l.test(e))throw la("nodomevents");var m=h[e];m!==d&&(k=m&&b(m,!0,g,f),d=m);k&&(h[e]=k(a),(c[e]||(c[e]=[])).$$inter=!0,(h.$$observers&&h.$$observers[e].$$scope||a).$watch(k,function(a, +b){"class"===e&&a!=b?h.$updateClass(a,b):h.$set(e,a)}))}}}})}}function ga(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g=b)return a;for(;b--;)8===a[b].nodeType&&Yf.call(a,b,1);return a}function Tc(a,b){if(b&&D(b))return b;if(D(a)){var d=Zc.exec(a);if(d)return d[3]}}function bf(){var a={},b=!1;this.has=function(b){return a.hasOwnProperty(b)};this.register= +function(b,c){Ra(b,"controller");I(b)?S(a,b):a[b]=c};this.allowGlobals=function(){b=!0};this.$get=["$injector","$window",function(d,c){function e(a,b,c,d){if(!a||!I(a.$scope))throw O("$controller")("noscp",d,b);a.$scope[b]=c}return function(f,g,h,k){var l,m,n;h=!0===h;k&&D(k)&&(n=k);if(D(f)){k=f.match(Zc);if(!k)throw Zf("ctrlfmt",f);m=k[1];n=n||k[3];f=a.hasOwnProperty(m)?a[m]:Ac(g.$scope,m,!0)||(b?Ac(c,m,!0):w);Qa(f,m,!0)}if(h)return h=(L(f)?f[f.length-1]:f).prototype,l=Object.create(h||null),n&& +e(g,n,l,m||f.name),S(function(){var a=d.invoke(f,l,g,m);a!==l&&(I(a)||H(a))&&(l=a,n&&e(g,n,l,m||f.name));return l},{instance:l,identifier:n});l=d.instantiate(f,g,m);n&&e(g,n,l,m||f.name);return l}}]}function cf(){this.$get=["$window",function(a){return G(a.document)}]}function df(){this.$get=["$log",function(a){return function(b,d){a.error.apply(a,arguments)}}]}function Zb(a){return I(a)?ga(a)?a.toISOString():cb(a):a}function jf(){this.$get=function(){return function(a){if(!a)return"";var b=[];oc(a, +function(a,c){null===a||v(a)||(L(a)?p(a,function(a){b.push(ja(c)+"="+ja(Zb(a)))}):b.push(ja(c)+"="+ja(Zb(a))))});return b.join("&")}}}function kf(){this.$get=function(){return function(a){function b(a,e,f){null===a||v(a)||(L(a)?p(a,function(a,c){b(a,e+"["+(I(a)?c:"")+"]")}):I(a)&&!ga(a)?oc(a,function(a,c){b(a,e+(f?"":"[")+c+(f?"":"]"))}):d.push(ja(e)+"="+ja(Zb(a))))}if(!a)return"";var d=[];b(a,"",!0);return d.join("&")}}}function $b(a,b){if(D(a)){var d=a.replace($f,"").trim();if(d){var c=b("Content-Type"); +(c=c&&0===c.indexOf($c))||(c=(c=d.match(ag))&&bg[c[0]].test(d));c&&(a=tc(d))}}return a}function ad(a){var b=X(),d;D(a)?p(a.split("\n"),function(a){d=a.indexOf(":");var e=E(Z(a.substr(0,d)));a=Z(a.substr(d+1));e&&(b[e]=b[e]?b[e]+", "+a:a)}):I(a)&&p(a,function(a,d){var f=E(d),g=Z(a);f&&(b[f]=b[f]?b[f]+", "+g:g)});return b}function bd(a){var b;return function(d){b||(b=ad(a));return d?(d=b[E(d)],void 0===d&&(d=null),d):b}}function cd(a,b,d,c){if(H(c))return c(a,b,d);p(c,function(c){a=c(a,b,d)});return a} +function hf(){var a=this.defaults={transformResponse:[$b],transformRequest:[function(a){return I(a)&&"[object File]"!==ha.call(a)&&"[object Blob]"!==ha.call(a)&&"[object FormData]"!==ha.call(a)?cb(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ma(ac),put:ma(ac),patch:ma(ac)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",paramSerializer:"$httpParamSerializer"},b=!1;this.useApplyAsync=function(a){return A(a)?(b=!!a,this):b};var d=!0;this.useLegacyPromiseExtensions= +function(a){return A(a)?(d=!!a,this):d};var c=this.interceptors=[];this.$get=["$httpBackend","$$cookieReader","$cacheFactory","$rootScope","$q","$injector",function(e,f,g,h,k,l){function m(b){function c(a){var b=S({},a);b.data=cd(a.data,a.headers,a.status,f.transformResponse);a=a.status;return 200<=a&&300>a?b:k.reject(b)}function e(a,b){var c,d={};p(a,function(a,e){H(a)?(c=a(b),null!=c&&(d[e]=c)):d[e]=a});return d}if(!I(b))throw O("$http")("badreq",b);if(!D(b.url))throw O("$http")("badreq",b.url); +var f=S({method:"get",transformRequest:a.transformRequest,transformResponse:a.transformResponse,paramSerializer:a.paramSerializer},b);f.headers=function(b){var c=a.headers,d=S({},b.headers),f,g,h,c=S({},c.common,c[E(b.method)]);a:for(f in c){g=E(f);for(h in d)if(E(h)===g)continue a;d[f]=c[f]}return e(d,ma(b))}(b);f.method=ub(f.method);f.paramSerializer=D(f.paramSerializer)?l.get(f.paramSerializer):f.paramSerializer;var g=[function(b){var d=b.headers,e=cd(b.data,bd(d),w,b.transformRequest);v(e)&&p(d, +function(a,b){"content-type"===E(b)&&delete d[b]});v(b.withCredentials)&&!v(a.withCredentials)&&(b.withCredentials=a.withCredentials);return n(b,e).then(c,c)},w],h=k.when(f);for(p(K,function(a){(a.request||a.requestError)&&g.unshift(a.request,a.requestError);(a.response||a.responseError)&&g.push(a.response,a.responseError)});g.length;){b=g.shift();var m=g.shift(),h=h.then(b,m)}d?(h.success=function(a){Qa(a,"fn");h.then(function(b){a(b.data,b.status,b.headers,f)});return h},h.error=function(a){Qa(a, +"fn");h.then(null,function(b){a(b.data,b.status,b.headers,f)});return h}):(h.success=dd("success"),h.error=dd("error"));return h}function n(c,d){function g(a,c,d,e){function f(){l(c,a,d,e)}T&&(200<=a&&300>a?T.put(R,[a,c,ad(d),e]):T.remove(R));b?h.$applyAsync(f):(f(),h.$$phase||h.$apply())}function l(a,b,d,e){b=-1<=b?b:0;(200<=b&&300>b?C.resolve:C.reject)({data:a,status:b,headers:bd(d),config:c,statusText:e})}function n(a){l(a.data,a.status,ma(a.headers()),a.statusText)}function K(){var a=m.pendingRequests.indexOf(c); +-1!==a&&m.pendingRequests.splice(a,1)}var C=k.defer(),J=C.promise,T,F,$=c.headers,R=y(c.url,c.paramSerializer(c.params));m.pendingRequests.push(c);J.then(K,K);!c.cache&&!a.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(T=I(c.cache)?c.cache:I(a.cache)?a.cache:B);T&&(F=T.get(R),A(F)?F&&H(F.then)?F.then(n,n):L(F)?l(F[1],F[0],ma(F[2]),F[3]):l(F,200,{},"OK"):T.put(R,J));v(F)&&((F=ed(c.url)?f()[c.xsrfCookieName||a.xsrfCookieName]:w)&&($[c.xsrfHeaderName||a.xsrfHeaderName]=F),e(c.method,R,d, +g,$,c.timeout,c.withCredentials,c.responseType));return J}function y(a,b){0=l&&(u.resolve(q),x(s.$$intervalId),delete g[s.$$intervalId]);t||a.$apply()},k);g[s.$$intervalId]=u;return s}var g={};f.cancel=function(a){return a&&a.$$intervalId in g?(g[a.$$intervalId].reject("canceled"),b.clearInterval(a.$$intervalId),delete g[a.$$intervalId],!0):!1};return f}]}function bc(a){a=a.split("/");for(var b=a.length;b--;)a[b]=qb(a[b]);return a.join("/")}function fd(a,b){var d=wa(a);b.$$protocol=d.protocol;b.$$host=d.hostname; +b.$$port=da(d.port)||dg[d.protocol]||null}function gd(a,b){var d="/"!==a.charAt(0);d&&(a="/"+a);var c=wa(a);b.$$path=decodeURIComponent(d&&"/"===c.pathname.charAt(0)?c.pathname.substring(1):c.pathname);b.$$search=wc(c.search);b.$$hash=decodeURIComponent(c.hash);b.$$path&&"/"!=b.$$path.charAt(0)&&(b.$$path="/"+b.$$path)}function na(a,b){if(0===b.indexOf(a))return b.substr(a.length)}function Ia(a){var b=a.indexOf("#");return-1==b?a:a.substr(0,b)}function jb(a){return a.replace(/(#.+)|#$/,"$1")}function cc(a, +b,d){this.$$html5=!0;d=d||"";fd(a,this);this.$$parse=function(a){var d=na(b,a);if(!D(d))throw Eb("ipthprfx",a,b);gd(d,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=Rb(this.$$search),d=this.$$hash?"#"+qb(this.$$hash):"";this.$$url=bc(this.$$path)+(a?"?"+a:"")+d;this.$$absUrl=b+this.$$url.substr(1)};this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;A(f=na(a,c))?(g=f,g=A(f=na(d,f))?b+(na("/",f)||f):a+g):A(f=na(b,c))?g= +b+f:b==c+"/"&&(g=b);g&&this.$$parse(g);return!!g}}function dc(a,b,d){fd(a,this);this.$$parse=function(c){var e=na(a,c)||na(b,c),f;v(e)||"#"!==e.charAt(0)?this.$$html5?f=e:(f="",v(e)&&(a=c,this.replace())):(f=na(d,e),v(f)&&(f=e));gd(f,this);c=this.$$path;var e=a,g=/^\/[A-Z]:(\/.*)/;0===f.indexOf(e)&&(f=f.replace(e,""));g.exec(f)||(c=(f=g.exec(c))?f[1]:c);this.$$path=c;this.$$compose()};this.$$compose=function(){var b=Rb(this.$$search),e=this.$$hash?"#"+qb(this.$$hash):"";this.$$url=bc(this.$$path)+ +(b?"?"+b:"")+e;this.$$absUrl=a+(this.$$url?d+this.$$url:"")};this.$$parseLinkUrl=function(b,d){return Ia(a)==Ia(b)?(this.$$parse(b),!0):!1}}function hd(a,b,d){this.$$html5=!0;dc.apply(this,arguments);this.$$parseLinkUrl=function(c,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;a==Ia(c)?f=c:(g=na(b,c))?f=a+d+g:b===c+"/"&&(f=b);f&&this.$$parse(f);return!!f};this.$$compose=function(){var b=Rb(this.$$search),e=this.$$hash?"#"+qb(this.$$hash):"";this.$$url=bc(this.$$path)+(b?"?"+b:"")+e;this.$$absUrl= +a+d+this.$$url}}function Fb(a){return function(){return this[a]}}function id(a,b){return function(d){if(v(d))return this[a];this[a]=b(d);this.$$compose();return this}}function nf(){var a="",b={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(b){return A(b)?(a=b,this):a};this.html5Mode=function(a){return Ma(a)?(b.enabled=a,this):I(a)?(Ma(a.enabled)&&(b.enabled=a.enabled),Ma(a.requireBase)&&(b.requireBase=a.requireBase),Ma(a.rewriteLinks)&&(b.rewriteLinks=a.rewriteLinks),this):b}; +this.$get=["$rootScope","$browser","$sniffer","$rootElement","$window",function(d,c,e,f,g){function h(a,b,d){var e=l.url(),f=l.$$state;try{c.url(a,b,d),l.$$state=c.state()}catch(g){throw l.url(e),l.$$state=f,g;}}function k(a,b){d.$broadcast("$locationChangeSuccess",l.absUrl(),a,l.$$state,b)}var l,m;m=c.baseHref();var n=c.url(),y;if(b.enabled){if(!m&&b.requireBase)throw Eb("nobase");y=n.substring(0,n.indexOf("/",n.indexOf("//")+2))+(m||"/");m=e.history?cc:hd}else y=Ia(n),m=dc;var B=y.substr(0,Ia(y).lastIndexOf("/")+ +1);l=new m(y,B,"#"+a);l.$$parseLinkUrl(n,n);l.$$state=c.state();var p=/^\s*(javascript|mailto):/i;f.on("click",function(a){if(b.rewriteLinks&&!a.ctrlKey&&!a.metaKey&&!a.shiftKey&&2!=a.which&&2!=a.button){for(var e=G(a.target);"a"!==pa(e[0]);)if(e[0]===f[0]||!(e=e.parent())[0])return;var h=e.prop("href"),k=e.attr("href")||e.attr("xlink:href");I(h)&&"[object SVGAnimatedString]"===h.toString()&&(h=wa(h.animVal).href);p.test(h)||!h||e.attr("target")||a.isDefaultPrevented()||!l.$$parseLinkUrl(h,k)||(a.preventDefault(), +l.absUrl()!=c.url()&&(d.$apply(),g.angular["ff-684208-preventDefault"]=!0))}});jb(l.absUrl())!=jb(n)&&c.url(l.absUrl(),!0);var x=!0;c.onUrlChange(function(a,b){v(na(B,a))?g.location.href=a:(d.$evalAsync(function(){var c=l.absUrl(),e=l.$$state,f;a=jb(a);l.$$parse(a);l.$$state=b;f=d.$broadcast("$locationChangeStart",a,c,b,e).defaultPrevented;l.absUrl()===a&&(f?(l.$$parse(c),l.$$state=e,h(c,!1,e)):(x=!1,k(c,e)))}),d.$$phase||d.$digest())});d.$watch(function(){var a=jb(c.url()),b=jb(l.absUrl()),f=c.state(), +g=l.$$replace,m=a!==b||l.$$html5&&e.history&&f!==l.$$state;if(x||m)x=!1,d.$evalAsync(function(){var b=l.absUrl(),c=d.$broadcast("$locationChangeStart",b,a,l.$$state,f).defaultPrevented;l.absUrl()===b&&(c?(l.$$parse(a),l.$$state=f):(m&&h(b,g,f===l.$$state?null:l.$$state),k(a,f)))});l.$$replace=!1});return l}]}function of(){var a=!0,b=this;this.debugEnabled=function(b){return A(b)?(a=b,this):a};this.$get=["$window",function(d){function c(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)? +"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=d.console||{},e=b[a]||b.log||z;a=!1;try{a=!!e.apply}catch(k){}return a?function(){var a=[];p(arguments,function(b){a.push(c(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){a&&c.apply(b,arguments)}}()}}]}function Va(a,b){if("__defineGetter__"=== +a||"__defineSetter__"===a||"__lookupGetter__"===a||"__lookupSetter__"===a||"__proto__"===a)throw U("isecfld",b);return a}function eg(a){return a+""}function xa(a,b){if(a){if(a.constructor===a)throw U("isecfn",b);if(a.window===a)throw U("isecwindow",b);if(a.children&&(a.nodeName||a.prop&&a.attr&&a.find))throw U("isecdom",b);if(a===Object)throw U("isecobj",b);}return a}function jd(a,b){if(a){if(a.constructor===a)throw U("isecfn",b);if(a===fg||a===gg||a===hg)throw U("isecff",b);}}function Gb(a,b){if(a&& +(a===(0).constructor||a===(!1).constructor||a==="".constructor||a==={}.constructor||a===[].constructor||a===Function.constructor))throw U("isecaf",b);}function ig(a,b){return"undefined"!==typeof a?a:b}function kd(a,b){return"undefined"===typeof a?b:"undefined"===typeof b?a:a+b}function V(a,b){var d,c;switch(a.type){case r.Program:d=!0;p(a.body,function(a){V(a.expression,b);d=d&&a.expression.constant});a.constant=d;break;case r.Literal:a.constant=!0;a.toWatch=[];break;case r.UnaryExpression:V(a.argument, +b);a.constant=a.argument.constant;a.toWatch=a.argument.toWatch;break;case r.BinaryExpression:V(a.left,b);V(a.right,b);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.left.toWatch.concat(a.right.toWatch);break;case r.LogicalExpression:V(a.left,b);V(a.right,b);a.constant=a.left.constant&&a.right.constant;a.toWatch=a.constant?[]:[a];break;case r.ConditionalExpression:V(a.test,b);V(a.alternate,b);V(a.consequent,b);a.constant=a.test.constant&&a.alternate.constant&&a.consequent.constant;a.toWatch= +a.constant?[]:[a];break;case r.Identifier:a.constant=!1;a.toWatch=[a];break;case r.MemberExpression:V(a.object,b);a.computed&&V(a.property,b);a.constant=a.object.constant&&(!a.computed||a.property.constant);a.toWatch=[a];break;case r.CallExpression:d=a.filter?!b(a.callee.name).$stateful:!1;c=[];p(a.arguments,function(a){V(a,b);d=d&&a.constant;a.constant||c.push.apply(c,a.toWatch)});a.constant=d;a.toWatch=a.filter&&!b(a.callee.name).$stateful?c:[a];break;case r.AssignmentExpression:V(a.left,b);V(a.right, +b);a.constant=a.left.constant&&a.right.constant;a.toWatch=[a];break;case r.ArrayExpression:d=!0;c=[];p(a.elements,function(a){V(a,b);d=d&&a.constant;a.constant||c.push.apply(c,a.toWatch)});a.constant=d;a.toWatch=c;break;case r.ObjectExpression:d=!0;c=[];p(a.properties,function(a){V(a.value,b);d=d&&a.value.constant;a.value.constant||c.push.apply(c,a.value.toWatch)});a.constant=d;a.toWatch=c;break;case r.ThisExpression:a.constant=!1;a.toWatch=[];break;case r.LocalsExpression:a.constant=!1,a.toWatch= +[]}}function ld(a){if(1==a.length){a=a[0].expression;var b=a.toWatch;return 1!==b.length?b:b[0]!==a?b:w}}function md(a){return a.type===r.Identifier||a.type===r.MemberExpression}function nd(a){if(1===a.body.length&&md(a.body[0].expression))return{type:r.AssignmentExpression,left:a.body[0].expression,right:{type:r.NGValueParameter},operator:"="}}function od(a){return 0===a.body.length||1===a.body.length&&(a.body[0].expression.type===r.Literal||a.body[0].expression.type===r.ArrayExpression||a.body[0].expression.type=== +r.ObjectExpression)}function pd(a,b){this.astBuilder=a;this.$filter=b}function qd(a,b){this.astBuilder=a;this.$filter=b}function Hb(a){return"constructor"==a}function ec(a){return H(a.valueOf)?a.valueOf():jg.call(a)}function pf(){var a=X(),b=X(),d={"true":!0,"false":!1,"null":null,undefined:w};this.addLiteral=function(a,b){d[a]=b};this.$get=["$filter",function(c){function e(d,e,g){var y,p,C;g=g||x;switch(typeof d){case "string":C=d=d.trim();var J=g?b:a;y=J[C];if(!y){":"===d.charAt(0)&&":"===d.charAt(1)&& +(p=!0,d=d.substring(2));y=g?K:B;var T=new fc(y);y=(new gc(T,c,y)).parse(d);y.constant?y.$$watchDelegate=m:p?y.$$watchDelegate=y.literal?l:k:y.inputs&&(y.$$watchDelegate=h);g&&(y=f(y));J[C]=y}return n(y,e);case "function":return n(d,e);default:return n(z,e)}}function f(a){function b(c,d,e,f){var g=x;x=!0;try{return a(c,d,e,f)}finally{x=g}}if(!a)return a;b.$$watchDelegate=a.$$watchDelegate;b.assign=f(a.assign);b.constant=a.constant;b.literal=a.literal;for(var c=0;a.inputs&&c=this.promise.$$state.status&&d&&d.length&&a(function(){for(var a,e,f=0,g=d.length;fa)for(b in l++,f)sa.call(e,b)||(u--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,h,k=1p&&(A=4-p,w[A]||(w[A]=[]),w[A].push({msg:H(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):a.exp,newVal:g,oldVal:k}));else if(a===c){B=!1;break a}}catch(G){f(G)}if(!(y=M.$$watchersCount&&M.$$childHead||M!==this&&M.$$nextSibling))for(;M!==this&&!(y=M.$$nextSibling);)M=M.$parent}while(M=y);if((B||u.length)&&!p--)throw t.$$phase=null,d("infdig",b,w);}while(B||u.length); +for(t.$$phase=null;s.length;)try{s.shift()()}catch(D){f(D)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this===t&&h.$$applicationDestroyed();y(this,-this.$$watchersCount);for(var b in this.$$listenerCount)B(this,this.$$listenerCount[b],b);a&&a.$$childHead==this&&(a.$$childHead=this.$$nextSibling);a&&a.$$childTail==this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&& +(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=z;this.$on=this.$watch=this.$watchGroup=function(){return z};this.$$listeners={};this.$$nextSibling=null;l(this)}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a,b){t.$$phase||u.length||h.defer(function(){u.length&&t.$digest()});u.push({scope:this,expression:g(a),locals:b})},$$postDigest:function(a){s.push(a)},$apply:function(a){try{n("$apply");try{return this.$eval(a)}finally{t.$$phase= +null}}catch(b){f(b)}finally{try{t.$digest()}catch(c){throw f(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&M.push(b);a=g(a);q()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,B(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,g=!1,h={name:a,targetScope:e,stopPropagation:function(){g= +!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=bb([h],arguments,1),l,m;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(m=d.length;lza)throw Ba("iequirks");var c=ma(fa);c.isEnabled=function(){return a};c.trustAs=d.trustAs;c.getTrusted=d.getTrusted;c.valueOf=d.valueOf;a||(c.trustAs=c.getTrusted=function(a,b){return b},c.valueOf=Za);c.parseAs=function(a,d){var e=b(d);return e.literal&&e.constant?e:b(d,function(b){return c.getTrusted(a,b)})};var e=c.parseAs,f=c.getTrusted,g=c.trustAs;p(fa,function(a,b){var d=E(b);c[eb("parse_as_"+d)]=function(b){return e(a, +b)};c[eb("get_trusted_"+d)]=function(b){return f(a,b)};c[eb("trust_as_"+d)]=function(b){return g(a,b)}});return c}]}function vf(){this.$get=["$window","$document",function(a,b){var d={},c=da((/android (\d+)/.exec(E((a.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((a.navigator||{}).userAgent),f=b[0]||{},g,h=/^(Moz|webkit|ms)(?=[A-Z])/,k=f.body&&f.body.style,l=!1,m=!1;if(k){for(var n in k)if(l=h.exec(n)){g=l[0];g=g.substr(0,1).toUpperCase()+g.substr(1);break}g||(g="WebkitOpacity"in k&&"webkit"); +l=!!("transition"in k||g+"Transition"in k);m=!!("animation"in k||g+"Animation"in k);!c||l&&m||(l=D(k.webkitTransition),m=D(k.webkitAnimation))}return{history:!(!a.history||!a.history.pushState||4>c||e),hasEvent:function(a){if("input"===a&&11>=za)return!1;if(v(d[a])){var b=f.createElement("div");d[a]="on"+a in b}return d[a]},csp:Ea(),vendorPrefix:g,transitions:l,animations:m,android:c}}]}function xf(){var a;this.httpOptions=function(b){return b?(a=b,this):a};this.$get=["$templateCache","$http","$q", +"$sce",function(b,d,c,e){function f(g,h){f.totalPendingRequests++;D(g)&&b.get(g)||(g=e.getTrustedResourceUrl(g));var k=d.defaults&&d.defaults.transformResponse;L(k)?k=k.filter(function(a){return a!==$b}):k===$b&&(k=null);return d.get(g,S({cache:b,transformResponse:k},a))["finally"](function(){f.totalPendingRequests--}).then(function(a){b.put(g,a.data);return a.data},function(a){if(!h)throw lg("tpload",g,a.status,a.statusText);return c.reject(a)})}f.totalPendingRequests=0;return f}]}function yf(){this.$get= +["$rootScope","$browser","$location",function(a,b,d){return{findBindings:function(a,b,d){a=a.getElementsByClassName("ng-binding");var g=[];p(a,function(a){var c=ea.element(a).data("$binding");c&&p(c,function(c){d?(new RegExp("(^|\\s)"+sd(b)+"(\\s|\\||$)")).test(c)&&g.push(a):-1!=c.indexOf(b)&&g.push(a)})});return g},findModels:function(a,b,d){for(var g=["ng-","data-ng-","ng\\:"],h=0;hc&&(c=e),c+=+a.slice(e+1),a=a.substring(0,e)):0>c&&(c=a.length);for(e=0;a.charAt(e)==ic;e++);if(e==(g=a.length))d=[0],c=1;else{for(g--;a.charAt(g)==ic;)g--;c-=e;d=[];for(f=0;e<=g;e++,f++)d[f]=+a.charAt(e)}c>Cd&&(d=d.splice(0,Cd-1),b=c-1, +c=1);return{d:d,e:b,i:c}}function tg(a,b,d,c){var e=a.d,f=e.length-a.i;b=v(b)?Math.min(Math.max(d,f),c):+b;d=b+a.i;c=e[d];if(0d-1){for(c=0;c>d;c--)e.unshift(0),a.i++;e.unshift(1);a.i++}else e[d-1]++;for(;fh;)k.unshift(0),h++;0b.lgSize&&h.unshift(k.splice(-b.lgSize).join(""));k.length>b.gSize;)h.unshift(k.splice(-b.gSize).join(""));k.length&&h.unshift(k.join(""));k=h.join(d);f.length&&(k+=c+f.join(""));e&&(k+="e+"+e)}return 0>a&&!g?b.negPre+ +k+b.negSuf:b.posPre+k+b.posSuf}function Ib(a,b,d,c){var e="";if(0>a||c&&0>=a)c?a=-a+1:(a=-a,e="-");for(a=""+a;a.length-d)f+=d;0===f&&-12==d&&(f=12);return Ib(f,b,c,e)}}function kb(a,b,d){return function(c,e){var f=c["get"+a](),g=ub((d?"STANDALONE":"")+(b?"SHORT":"")+a);return e[g][f]}}function Dd(a){var b=(new Date(a,0,1)).getDay();return new Date(a,0,(4>=b?5:12)-b)}function Ed(a){return function(b){var d= +Dd(b.getFullYear());b=+new Date(b.getFullYear(),b.getMonth(),b.getDate()+(4-b.getDay()))-+d;b=1+Math.round(b/6048E5);return Ib(b,a)}}function jc(a,b){return 0>=a.getFullYear()?b.ERAS[0]:b.ERAS[1]}function xd(a){function b(a){var b;if(b=a.match(d)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,k=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=da(b[9]+b[10]),g=da(b[9]+b[11]));h.call(a,da(b[1]),da(b[2])-1,da(b[3]));f=da(b[4]||0)-f;g=da(b[5]||0)-g;h=da(b[6]||0);b=Math.round(1E3*parseFloat("0."+ +(b[7]||0)));k.call(a,f,g,h,b)}return a}var d=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,d,f){var g="",h=[],k,l;d=d||"mediumDate";d=a.DATETIME_FORMATS[d]||d;D(c)&&(c=ug.test(c)?da(c):b(c));W(c)&&(c=new Date(c));if(!ga(c)||!isFinite(c.getTime()))return c;for(;d;)(l=vg.exec(d))?(h=bb(h,l,1),d=h.pop()):(h.push(d),d=null);var m=c.getTimezoneOffset();f&&(m=uc(f,m),c=Qb(c,f,!0));p(h,function(b){k=wg[b];g+=k?k(c,a.DATETIME_FORMATS, +m):"''"===b?"'":b.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function ng(){return function(a,b){v(b)&&(b=2);return cb(a,b)}}function og(){return function(a,b,d){b=Infinity===Math.abs(Number(b))?Number(b):da(b);if(isNaN(b))return a;W(a)&&(a=a.toString());if(!L(a)&&!D(a))return a;d=!d||isNaN(d)?0:da(d);d=0>d?Math.max(0,a.length+d):d;return 0<=b?a.slice(d,d+b):0===d?a.slice(b,a.length):a.slice(Math.max(0,d+b),d)}}function zd(a){function b(b,d){d=d?-1:1;return b.map(function(b){var c=1,h=Za; +if(H(b))h=b;else if(D(b)){if("+"==b.charAt(0)||"-"==b.charAt(0))c="-"==b.charAt(0)?-1:1,b=b.substring(1);if(""!==b&&(h=a(b),h.constant))var k=h(),h=function(a){return a[k]}}return{get:h,descending:c*d}})}function d(a){switch(typeof a){case "number":case "boolean":case "string":return!0;default:return!1}}return function(a,e,f){if(null==a)return a;if(!Ca(a))throw O("orderBy")("notarray",a);L(e)||(e=[e]);0===e.length&&(e=["+"]);var g=b(e,f);g.push({get:function(){return{}},descending:f?-1:1});a=Array.prototype.map.call(a, +function(a,b){return{value:a,predicateValues:g.map(function(c){var e=c.get(a);c=typeof e;if(null===e)c="string",e="null";else if("string"===c)e=e.toLowerCase();else if("object"===c)a:{if("function"===typeof e.valueOf&&(e=e.valueOf(),d(e)))break a;if(qc(e)&&(e=e.toString(),d(e)))break a;e=b}return{value:e,type:c}})}});a.sort(function(a,b){for(var c=0,d=0,e=g.length;db||37<=b&&40>=b||m(a,this,this.value)});if(e.hasEvent("paste"))b.on("paste cut",m)}b.on("change",l);if(Hd[g]&&c.$$hasNativeValidators&&g===d.type)b.on("keydown wheel mousedown",function(a){if(!k){var b=this.validity,c=b.badInput,d=b.typeMismatch;k=f.defer(function(){k=null;b.badInput===c&&b.typeMismatch===d||l(a)})}});c.$render=function(){var a=c.$isEmpty(c.$viewValue)? +"":c.$viewValue;b.val()!==a&&b.val(a)}}function Lb(a,b){return function(d,c){var e,f;if(ga(d))return d;if(D(d)){'"'==d.charAt(0)&&'"'==d.charAt(d.length-1)&&(d=d.substring(1,d.length-1));if(xg.test(d))return new Date(d);a.lastIndex=0;if(e=a.exec(d))return e.shift(),f=c?{yyyy:c.getFullYear(),MM:c.getMonth()+1,dd:c.getDate(),HH:c.getHours(),mm:c.getMinutes(),ss:c.getSeconds(),sss:c.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},p(e,function(a,c){c=x};g.$observe("min",function(a){x=y(a);h.$validate()})}if(A(g.max)||g.ngMax){var q;h.$validators.max=function(a){return!n(a)||v(q)||d(a)<=q};g.$observe("max",function(a){q=y(a);h.$validate()})}}}function Id(a,b,d,c){(c.$$hasNativeValidators=I(b[0].validity))&&c.$parsers.push(function(a){var c=b.prop("validity")||{};return c.badInput||c.typeMismatch?w:a})}function Jd(a,b,d,c,e){if(A(c)){a= +a(c);if(!a.constant)throw nb("constexpr",d,c);return a(b)}return e}function lc(a,b){a="ngClass"+a;return["$animate",function(d){function c(a,b){var c=[],d=0;a:for(;d(?:<\/\1>|)$/,Tb=/<|&#?\w+;/,Hf=/<([\w:-]+)/,If=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, +ka={option:[1,'"],thead:[1,"","
        "],col:[2,"","
        "],tr:[2,"","
        "],td:[3,"","
        "],_default:[0,"",""]};ka.optgroup=ka.option;ka.tbody=ka.tfoot=ka.colgroup=ka.caption=ka.thead;ka.th=ka.td;var Pf=Node.prototype.contains||function(a){return!!(this.compareDocumentPosition(a)&16)},Pa=Y.prototype={ready:function(a){function b(){d||(d=!0,a())}var d=!1;"complete"=== +Q.readyState?setTimeout(b):(this.on("DOMContentLoaded",b),Y(N).on("load",b))},toString:function(){var a=[];p(this,function(b){a.push(""+b)});return"["+a.join(", ")+"]"},eq:function(a){return 0<=a?G(this[a]):G(this[this.length+a])},length:0,push:zg,sort:[].sort,splice:[].splice},Db={};p("multiple selected checked disabled readOnly required open".split(" "),function(a){Db[E(a)]=a});var Rc={};p("input select option textarea button form details".split(" "),function(a){Rc[a]=!0});var Yc={ngMinlength:"minlength", +ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};p({data:Wb,removeData:fb,hasData:function(a){for(var b in gb[a.ng339])return!0;return!1},cleanData:function(a){for(var b=0,d=a.length;b/,Sf=/^[^\(]*\(\s*([^\)]*)\)/m,Ag=/,/,Bg=/^\s*(_?)(\S+?)\1\s*$/,Qf=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Ga=O("$injector");db.$$annotate=function(a,b,d){var c;if("function"===typeof a){if(!(c=a.$inject)){c=[];if(a.length){if(b)throw D(d)&&d||(d=a.name||Tf(a)),Ga("strictdi",d); +b=Sc(a);p(b[1].split(Ag),function(a){a.replace(Bg,function(a,b,d){c.push(d)})})}a.$inject=c}}else L(a)?(b=a.length-1,Qa(a[b],"fn"),c=a.slice(0,b)):Qa(a,"fn",!0);return c};var Nd=O("$animate"),We=function(){this.$get=z},Xe=function(){var a=new Sa,b=[];this.$get=["$$AnimateRunner","$rootScope",function(d,c){function e(a,b,c){var d=!1;b&&(b=D(b)?b.split(" "):L(b)?b:[],p(b,function(b){b&&(d=!0,a[b]=c)}));return d}function f(){p(b,function(b){var c=a.get(b);if(c){var d=Uf(b.attr("class")),e="",f="";p(c, +function(a,b){a!==!!d[b]&&(a?e+=(e.length?" ":"")+b:f+=(f.length?" ":"")+b)});p(b,function(a){e&&Bb(a,e);f&&Ab(a,f)});a.remove(b)}});b.length=0}return{enabled:z,on:z,off:z,pin:z,push:function(g,h,k,l){l&&l();k=k||{};k.from&&g.css(k.from);k.to&&g.css(k.to);if(k.addClass||k.removeClass)if(h=k.addClass,l=k.removeClass,k=a.get(g)||{},h=e(k,h,!0),l=e(k,l,!1),h||l)a.put(g,k),b.push(g),1===b.length&&c.$$postDigest(f);g=new d;g.complete();return g}}}]},Ue=["$provide",function(a){var b=this;this.$$registeredAnimations= +Object.create(null);this.register=function(d,c){if(d&&"."!==d.charAt(0))throw Nd("notcsel",d);var e=d+"-animation";b.$$registeredAnimations[d.substr(1)]=e;a.factory(e,c)};this.classNameFilter=function(a){if(1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?a:null)&&/(\s+|\/)ng-animate(\s+|\/)/.test(this.$$classNameFilter.toString()))throw Nd("nongcls","ng-animate");return this.$$classNameFilter};this.$get=["$$animateQueue",function(a){function b(a,c,d){if(d){var h;a:{for(h=0;h <= >= && || ! = |".split(" "),function(a){Mb[a]=!0});var Fg={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},fc=function(a){this.options= +a};fc.prototype={constructor:fc,lex:function(a){this.text=a;this.index=0;for(this.tokens=[];this.index=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<= +a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,b,d){d=d||this.index;b=A(b)?"s "+b+"-"+this.index+" ["+this.text.substring(b,d)+"]":" "+d;throw U("lexerr",a,b,this.text);},readNumber:function(){for(var a="",b=this.index;this.index","<=",">=");)a={type:r.BinaryExpression,operator:b.text,left:a,right:this.additive()};return a},additive:function(){for(var a=this.multiplicative(),b;b=this.expect("+","-");)a={type:r.BinaryExpression,operator:b.text,left:a,right:this.multiplicative()};return a},multiplicative:function(){for(var a=this.unary(),b;b=this.expect("*","/","%");)a={type:r.BinaryExpression,operator:b.text,left:a,right:this.unary()};return a},unary:function(){var a;return(a=this.expect("+", +"-","!"))?{type:r.UnaryExpression,operator:a.text,prefix:!0,argument:this.unary()}:this.primary()},primary:function(){var a;this.expect("(")?(a=this.filterChain(),this.consume(")")):this.expect("[")?a=this.arrayDeclaration():this.expect("{")?a=this.object():this.selfReferential.hasOwnProperty(this.peek().text)?a=qa(this.selfReferential[this.consume().text]):this.options.literals.hasOwnProperty(this.peek().text)?a={type:r.Literal,value:this.options.literals[this.consume().text]}:this.peek().identifier? +a=this.identifier():this.peek().constant?a=this.constant():this.throwError("not a primary expression",this.peek());for(var b;b=this.expect("(","[",".");)"("===b.text?(a={type:r.CallExpression,callee:a,arguments:this.parseArguments()},this.consume(")")):"["===b.text?(a={type:r.MemberExpression,object:a,property:this.expression(),computed:!0},this.consume("]")):"."===b.text?a={type:r.MemberExpression,object:a,property:this.identifier(),computed:!1}:this.throwError("IMPOSSIBLE");return a},filter:function(a){a= +[a];for(var b={type:r.CallExpression,callee:this.identifier(),arguments:a,filter:!0};this.expect(":");)a.push(this.expression());return b},parseArguments:function(){var a=[];if(")"!==this.peekToken().text){do a.push(this.expression());while(this.expect(","))}return a},identifier:function(){var a=this.consume();a.identifier||this.throwError("is not a valid identifier",a);return{type:r.Identifier,name:a.text}},constant:function(){return{type:r.Literal,value:this.consume().value}},arrayDeclaration:function(){var a= +[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break;a.push(this.expression())}while(this.expect(","))}this.consume("]");return{type:r.ArrayExpression,elements:a}},object:function(){var a=[],b;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;b={type:r.Property,kind:"init"};this.peek().constant?b.key=this.constant():this.peek().identifier?b.key=this.identifier():this.throwError("invalid key",this.peek());this.consume(":");b.value=this.expression();a.push(b)}while(this.expect(",")) +}this.consume("}");return{type:r.ObjectExpression,properties:a}},throwError:function(a,b){throw U("syntax",b.text,a,b.index+1,this.text,this.text.substring(b.index));},consume:function(a){if(0===this.tokens.length)throw U("ueoe",this.text);var b=this.expect(a);b||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return b},peekToken:function(){if(0===this.tokens.length)throw U("ueoe",this.text);return this.tokens[0]},peek:function(a,b,d,c){return this.peekAhead(0,a,b,d,c)},peekAhead:function(a, +b,d,c,e){if(this.tokens.length>a){a=this.tokens[a];var f=a.text;if(f===b||f===d||f===c||f===e||!(b||d||c||e))return a}return!1},expect:function(a,b,d,c){return(a=this.peek(a,b,d,c))?(this.tokens.shift(),a):!1},selfReferential:{"this":{type:r.ThisExpression},$locals:{type:r.LocalsExpression}}};pd.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.state={nextId:0,filters:{},expensiveChecks:b,fn:{vars:[],body:[],own:{}},assign:{vars:[],body:[],own:{}},inputs:[]};V(c,d.$filter); +var e="",f;this.stage="assign";if(f=nd(c))this.state.computing="assign",e=this.nextId(),this.recurse(f,e),this.return_(e),e="fn.assign="+this.generateFunction("assign","s,v,l");f=ld(c.body);d.stage="inputs";p(f,function(a,b){var c="fn"+b;d.state[c]={vars:[],body:[],own:{}};d.state.computing=c;var e=d.nextId();d.recurse(a,e);d.return_(e);d.state.inputs.push(c);a.watchId=b});this.state.computing="fn";this.stage="main";this.recurse(c);e='"'+this.USE+" "+this.STRICT+'";\n'+this.filterPrefix()+"var fn="+ +this.generateFunction("fn","s,l,a,i")+e+this.watchFns()+"return fn;";e=(new Function("$filter","ensureSafeMemberName","ensureSafeObject","ensureSafeFunction","getStringValue","ensureSafeAssignContext","ifDefined","plus","text",e))(this.$filter,Va,xa,jd,eg,Gb,ig,kd,a);this.state=this.stage=w;e.literal=od(c);e.constant=c.constant;return e},USE:"use",STRICT:"strict",watchFns:function(){var a=[],b=this.state.inputs,d=this;p(b,function(b){a.push("var "+b+"="+d.generateFunction(b,"s"))});b.length&&a.push("fn.inputs=["+ +b.join(",")+"];");return a.join("")},generateFunction:function(a,b){return"function("+b+"){"+this.varsPrefix(a)+this.body(a)+"};"},filterPrefix:function(){var a=[],b=this;p(this.state.filters,function(d,c){a.push(d+"=$filter("+b.escape(c)+")")});return a.length?"var "+a.join(",")+";":""},varsPrefix:function(a){return this.state[a].vars.length?"var "+this.state[a].vars.join(",")+";":""},body:function(a){return this.state[a].body.join("")},recurse:function(a,b,d,c,e,f){var g,h,k=this,l,m;c=c||z;if(!f&& +A(a.watchId))b=b||this.nextId(),this.if_("i",this.lazyAssign(b,this.computedMember("i",a.watchId)),this.lazyRecurse(a,b,d,c,e,!0));else switch(a.type){case r.Program:p(a.body,function(b,c){k.recurse(b.expression,w,w,function(a){h=a});c!==a.body.length-1?k.current().body.push(h,";"):k.return_(h)});break;case r.Literal:m=this.escape(a.value);this.assign(b,m);c(m);break;case r.UnaryExpression:this.recurse(a.argument,w,w,function(a){h=a});m=a.operator+"("+this.ifDefined(h,0)+")";this.assign(b,m);c(m); +break;case r.BinaryExpression:this.recurse(a.left,w,w,function(a){g=a});this.recurse(a.right,w,w,function(a){h=a});m="+"===a.operator?this.plus(g,h):"-"===a.operator?this.ifDefined(g,0)+a.operator+this.ifDefined(h,0):"("+g+")"+a.operator+"("+h+")";this.assign(b,m);c(m);break;case r.LogicalExpression:b=b||this.nextId();k.recurse(a.left,b);k.if_("&&"===a.operator?b:k.not(b),k.lazyRecurse(a.right,b));c(b);break;case r.ConditionalExpression:b=b||this.nextId();k.recurse(a.test,b);k.if_(b,k.lazyRecurse(a.alternate, +b),k.lazyRecurse(a.consequent,b));c(b);break;case r.Identifier:b=b||this.nextId();d&&(d.context="inputs"===k.stage?"s":this.assign(this.nextId(),this.getHasOwnProperty("l",a.name)+"?l:s"),d.computed=!1,d.name=a.name);Va(a.name);k.if_("inputs"===k.stage||k.not(k.getHasOwnProperty("l",a.name)),function(){k.if_("inputs"===k.stage||"s",function(){e&&1!==e&&k.if_(k.not(k.nonComputedMember("s",a.name)),k.lazyAssign(k.nonComputedMember("s",a.name),"{}"));k.assign(b,k.nonComputedMember("s",a.name))})},b&& +k.lazyAssign(b,k.nonComputedMember("l",a.name)));(k.state.expensiveChecks||Hb(a.name))&&k.addEnsureSafeObject(b);c(b);break;case r.MemberExpression:g=d&&(d.context=this.nextId())||this.nextId();b=b||this.nextId();k.recurse(a.object,g,w,function(){k.if_(k.notNull(g),function(){e&&1!==e&&k.addEnsureSafeAssignContext(g);if(a.computed)h=k.nextId(),k.recurse(a.property,h),k.getStringValue(h),k.addEnsureSafeMemberName(h),e&&1!==e&&k.if_(k.not(k.computedMember(g,h)),k.lazyAssign(k.computedMember(g,h),"{}")), +m=k.ensureSafeObject(k.computedMember(g,h)),k.assign(b,m),d&&(d.computed=!0,d.name=h);else{Va(a.property.name);e&&1!==e&&k.if_(k.not(k.nonComputedMember(g,a.property.name)),k.lazyAssign(k.nonComputedMember(g,a.property.name),"{}"));m=k.nonComputedMember(g,a.property.name);if(k.state.expensiveChecks||Hb(a.property.name))m=k.ensureSafeObject(m);k.assign(b,m);d&&(d.computed=!1,d.name=a.property.name)}},function(){k.assign(b,"undefined")});c(b)},!!e);break;case r.CallExpression:b=b||this.nextId();a.filter? +(h=k.filter(a.callee.name),l=[],p(a.arguments,function(a){var b=k.nextId();k.recurse(a,b);l.push(b)}),m=h+"("+l.join(",")+")",k.assign(b,m),c(b)):(h=k.nextId(),g={},l=[],k.recurse(a.callee,h,g,function(){k.if_(k.notNull(h),function(){k.addEnsureSafeFunction(h);p(a.arguments,function(a){k.recurse(a,k.nextId(),w,function(a){l.push(k.ensureSafeObject(a))})});g.name?(k.state.expensiveChecks||k.addEnsureSafeObject(g.context),m=k.member(g.context,g.name,g.computed)+"("+l.join(",")+")"):m=h+"("+l.join(",")+ +")";m=k.ensureSafeObject(m);k.assign(b,m)},function(){k.assign(b,"undefined")});c(b)}));break;case r.AssignmentExpression:h=this.nextId();g={};if(!md(a.left))throw U("lval");this.recurse(a.left,w,g,function(){k.if_(k.notNull(g.context),function(){k.recurse(a.right,h);k.addEnsureSafeObject(k.member(g.context,g.name,g.computed));k.addEnsureSafeAssignContext(g.context);m=k.member(g.context,g.name,g.computed)+a.operator+h;k.assign(b,m);c(b||m)})},1);break;case r.ArrayExpression:l=[];p(a.elements,function(a){k.recurse(a, +k.nextId(),w,function(a){l.push(a)})});m="["+l.join(",")+"]";this.assign(b,m);c(m);break;case r.ObjectExpression:l=[];p(a.properties,function(a){k.recurse(a.value,k.nextId(),w,function(b){l.push(k.escape(a.key.type===r.Identifier?a.key.name:""+a.key.value)+":"+b)})});m="{"+l.join(",")+"}";this.assign(b,m);c(m);break;case r.ThisExpression:this.assign(b,"s");c("s");break;case r.LocalsExpression:this.assign(b,"l");c("l");break;case r.NGValueParameter:this.assign(b,"v"),c("v")}},getHasOwnProperty:function(a, +b){var d=a+"."+b,c=this.current().own;c.hasOwnProperty(d)||(c[d]=this.nextId(!1,a+"&&("+this.escape(b)+" in "+a+")"));return c[d]},assign:function(a,b){if(a)return this.current().body.push(a,"=",b,";"),a},filter:function(a){this.state.filters.hasOwnProperty(a)||(this.state.filters[a]=this.nextId(!0));return this.state.filters[a]},ifDefined:function(a,b){return"ifDefined("+a+","+this.escape(b)+")"},plus:function(a,b){return"plus("+a+","+b+")"},return_:function(a){this.current().body.push("return ", +a,";")},if_:function(a,b,d){if(!0===a)b();else{var c=this.current().body;c.push("if(",a,"){");b();c.push("}");d&&(c.push("else{"),d(),c.push("}"))}},not:function(a){return"!("+a+")"},notNull:function(a){return a+"!=null"},nonComputedMember:function(a,b){return a+"."+b},computedMember:function(a,b){return a+"["+b+"]"},member:function(a,b,d){return d?this.computedMember(a,b):this.nonComputedMember(a,b)},addEnsureSafeObject:function(a){this.current().body.push(this.ensureSafeObject(a),";")},addEnsureSafeMemberName:function(a){this.current().body.push(this.ensureSafeMemberName(a), +";")},addEnsureSafeFunction:function(a){this.current().body.push(this.ensureSafeFunction(a),";")},addEnsureSafeAssignContext:function(a){this.current().body.push(this.ensureSafeAssignContext(a),";")},ensureSafeObject:function(a){return"ensureSafeObject("+a+",text)"},ensureSafeMemberName:function(a){return"ensureSafeMemberName("+a+",text)"},ensureSafeFunction:function(a){return"ensureSafeFunction("+a+",text)"},getStringValue:function(a){this.assign(a,"getStringValue("+a+")")},ensureSafeAssignContext:function(a){return"ensureSafeAssignContext("+ +a+",text)"},lazyRecurse:function(a,b,d,c,e,f){var g=this;return function(){g.recurse(a,b,d,c,e,f)}},lazyAssign:function(a,b){var d=this;return function(){d.assign(a,b)}},stringEscapeRegex:/[^ a-zA-Z0-9]/g,stringEscapeFn:function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)},escape:function(a){if(D(a))return"'"+a.replace(this.stringEscapeRegex,this.stringEscapeFn)+"'";if(W(a))return a.toString();if(!0===a)return"true";if(!1===a)return"false";if(null===a)return"null";if("undefined"=== +typeof a)return"undefined";throw U("esc");},nextId:function(a,b){var d="v"+this.state.nextId++;a||this.current().vars.push(d+(b?"="+b:""));return d},current:function(){return this.state[this.state.computing]}};qd.prototype={compile:function(a,b){var d=this,c=this.astBuilder.ast(a);this.expression=a;this.expensiveChecks=b;V(c,d.$filter);var e,f;if(e=nd(c))f=this.recurse(e);e=ld(c.body);var g;e&&(g=[],p(e,function(a,b){var c=d.recurse(a);a.input=c;g.push(c);a.watchId=b}));var h=[];p(c.body,function(a){h.push(d.recurse(a.expression))}); +e=0===c.body.length?z:1===c.body.length?h[0]:function(a,b){var c;p(h,function(d){c=d(a,b)});return c};f&&(e.assign=function(a,b,c){return f(a,c,b)});g&&(e.inputs=g);e.literal=od(c);e.constant=c.constant;return e},recurse:function(a,b,d){var c,e,f=this,g;if(a.input)return this.inputs(a.input,a.watchId);switch(a.type){case r.Literal:return this.value(a.value,b);case r.UnaryExpression:return e=this.recurse(a.argument),this["unary"+a.operator](e,b);case r.BinaryExpression:return c=this.recurse(a.left), +e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case r.LogicalExpression:return c=this.recurse(a.left),e=this.recurse(a.right),this["binary"+a.operator](c,e,b);case r.ConditionalExpression:return this["ternary?:"](this.recurse(a.test),this.recurse(a.alternate),this.recurse(a.consequent),b);case r.Identifier:return Va(a.name,f.expression),f.identifier(a.name,f.expensiveChecks||Hb(a.name),b,d,f.expression);case r.MemberExpression:return c=this.recurse(a.object,!1,!!d),a.computed||(Va(a.property.name, +f.expression),e=a.property.name),a.computed&&(e=this.recurse(a.property)),a.computed?this.computedMember(c,e,b,d,f.expression):this.nonComputedMember(c,e,f.expensiveChecks,b,d,f.expression);case r.CallExpression:return g=[],p(a.arguments,function(a){g.push(f.recurse(a))}),a.filter&&(e=this.$filter(a.callee.name)),a.filter||(e=this.recurse(a.callee,!0)),a.filter?function(a,c,d,f){for(var n=[],p=0;p":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>b(c,e,f,g);return d?{value:c}:c}},"binary<=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f, +g)<=b(c,e,f,g);return d?{value:c}:c}},"binary>=":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)>=b(c,e,f,g);return d?{value:c}:c}},"binary&&":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)&&b(c,e,f,g);return d?{value:c}:c}},"binary||":function(a,b,d){return function(c,e,f,g){c=a(c,e,f,g)||b(c,e,f,g);return d?{value:c}:c}},"ternary?:":function(a,b,d,c){return function(e,f,g,h){e=a(e,f,g,h)?b(e,f,g,h):d(e,f,g,h);return c?{value:e}:e}},value:function(a,b){return function(){return b?{context:w, +name:w,value:a}:a}},identifier:function(a,b,d,c,e){return function(f,g,h,k){f=g&&a in g?g:f;c&&1!==c&&f&&!f[a]&&(f[a]={});g=f?f[a]:w;b&&xa(g,e);return d?{context:f,name:a,value:g}:g}},computedMember:function(a,b,d,c,e){return function(f,g,h,k){var l=a(f,g,h,k),m,n;null!=l&&(m=b(f,g,h,k),m+="",Va(m,e),c&&1!==c&&(Gb(l),l&&!l[m]&&(l[m]={})),n=l[m],xa(n,e));return d?{context:l,name:m,value:n}:n}},nonComputedMember:function(a,b,d,c,e,f){return function(g,h,k,l){g=a(g,h,k,l);e&&1!==e&&(Gb(g),g&&!g[b]&& +(g[b]={}));h=null!=g?g[b]:w;(d||Hb(b))&&xa(h,f);return c?{context:g,name:b,value:h}:h}},inputs:function(a,b){return function(d,c,e,f){return f?f[b]:a(d,c,e)}}};var gc=function(a,b,d){this.lexer=a;this.$filter=b;this.options=d;this.ast=new r(a,d);this.astCompiler=d.csp?new qd(this.ast,b):new pd(this.ast,b)};gc.prototype={constructor:gc,parse:function(a){return this.astCompiler.compile(a,this.options.expensiveChecks)}};var jg=Object.prototype.valueOf,Ba=O("$sce"),fa={HTML:"html",CSS:"css",URL:"url", +RESOURCE_URL:"resourceUrl",JS:"js"},lg=O("$compile"),aa=Q.createElement("a"),ud=wa(N.location.href);vd.$inject=["$document"];Ic.$inject=["$provide"];var Cd=22,Bd=".",ic="0";wd.$inject=["$locale"];yd.$inject=["$locale"];var wg={yyyy:ba("FullYear",4,0,!1,!0),yy:ba("FullYear",2,0,!0,!0),y:ba("FullYear",1,0,!1,!0),MMMM:kb("Month"),MMM:kb("Month",!0),MM:ba("Month",2,1),M:ba("Month",1,1),LLLL:kb("Month",!1,!0),dd:ba("Date",2),d:ba("Date",1),HH:ba("Hours",2),H:ba("Hours",1),hh:ba("Hours",2,-12),h:ba("Hours", +1,-12),mm:ba("Minutes",2),m:ba("Minutes",1),ss:ba("Seconds",2),s:ba("Seconds",1),sss:ba("Milliseconds",3),EEEE:kb("Day"),EEE:kb("Day",!0),a:function(a,b){return 12>a.getHours()?b.AMPMS[0]:b.AMPMS[1]},Z:function(a,b,d){a=-1*d;return a=(0<=a?"+":"")+(Ib(Math[0=a.getFullYear()?b.ERANAMES[0]:b.ERANAMES[1]}},vg=/((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/, +ug=/^\-?\d+$/;xd.$inject=["$locale"];var pg=ia(E),qg=ia(ub);zd.$inject=["$parse"];var ke=ia({restrict:"E",compile:function(a,b){if(!b.href&&!b.xlinkHref)return function(a,b){if("a"===b[0].nodeName.toLowerCase()){var e="[object SVGAnimatedString]"===ha.call(b.prop("href"))?"xlink:href":"href";b.on("click",function(a){b.attr(e)||a.preventDefault()})}}}}),vb={};p(Db,function(a,b){function d(a,d,e){a.$watch(e[c],function(a){e.$set(b,!!a)})}if("multiple"!=a){var c=ua("ng-"+b),e=d;"checked"===a&&(e=function(a, +b,e){e.ngModel!==e[c]&&d(a,b,e)});vb[c]=function(){return{restrict:"A",priority:100,link:e}}}});p(Yc,function(a,b){vb[b]=function(){return{priority:100,link:function(a,c,e){if("ngPattern"===b&&"/"==e.ngPattern.charAt(0)&&(c=e.ngPattern.match(yg))){e.$set("ngPattern",new RegExp(c[1],c[2]));return}a.$watch(e[b],function(a){e.$set(b,a)})}}}});p(["src","srcset","href"],function(a){var b=ua("ng-"+a);vb[b]=function(){return{priority:99,link:function(d,c,e){var f=a,g=a;"href"===a&&"[object SVGAnimatedString]"=== +ha.call(c.prop("href"))&&(g="xlinkHref",e.$attr[g]="xlink:href",f=null);e.$observe(b,function(b){b?(e.$set(g,b),za&&f&&c.prop(f,e[g])):"href"===a&&e.$set(g,null)})}}}});var Jb={$addControl:z,$$renameControl:function(a,b){a.$name=b},$removeControl:z,$setValidity:z,$setDirty:z,$setPristine:z,$setSubmitted:z};Fd.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var Od=function(a){return["$timeout","$parse",function(b,d){function c(a){return""===a?d('this[""]').assign:d(a).assign||z}return{name:"form", +restrict:a?"EAC":"E",require:["form","^^?form"],controller:Fd,compile:function(d,f){d.addClass(Wa).addClass(ob);var g=f.name?"name":a&&f.ngForm?"ngForm":!1;return{pre:function(a,d,e,f){var n=f[0];if(!("action"in e)){var p=function(b){a.$apply(function(){n.$commitViewValue();n.$setSubmitted()});b.preventDefault()};d[0].addEventListener("submit",p,!1);d.on("$destroy",function(){b(function(){d[0].removeEventListener("submit",p,!1)},0,!1)})}(f[1]||n.$$parentForm).$addControl(n);var r=g?c(n.$name):z;g&& +(r(a,n),e.$observe(g,function(b){n.$name!==b&&(r(a,w),n.$$parentForm.$$renameControl(n,b),r=c(n.$name),r(a,n))}));d.on("$destroy",function(){n.$$parentForm.$removeControl(n);r(a,w);S(n,Jb)})}}}}}]},le=Od(),ye=Od(!0),xg=/^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/,Gg=/^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i,Hg=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i, +Ig=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/,Pd=/^(\d{4,})-(\d{2})-(\d{2})$/,Qd=/^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,mc=/^(\d{4,})-W(\d\d)$/,Rd=/^(\d{4,})-(\d\d)$/,Sd=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,Hd=X();p(["date","datetime-local","month","time","week"],function(a){Hd[a]=!0});var Td={text:function(a,b,d,c,e,f){lb(a,b,d,c,e,f);kc(c)},date:mb("date",Pd,Lb(Pd,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":mb("datetimelocal",Qd,Lb(Qd,"yyyy MM dd HH mm ss sss".split(" ")), +"yyyy-MM-ddTHH:mm:ss.sss"),time:mb("time",Sd,Lb(Sd,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:mb("week",mc,function(a,b){if(ga(a))return a;if(D(a)){mc.lastIndex=0;var d=mc.exec(a);if(d){var c=+d[1],e=+d[2],f=d=0,g=0,h=0,k=Dd(c),e=7*(e-1);b&&(d=b.getHours(),f=b.getMinutes(),g=b.getSeconds(),h=b.getMilliseconds());return new Date(c,0,k.getDate()+e,d,f,g,h)}}return NaN},"yyyy-Www"),month:mb("month",Rd,Lb(Rd,["yyyy","MM"]),"yyyy-MM"),number:function(a,b,d,c,e,f){Id(a,b,d,c);lb(a,b,d,c,e,f);c.$$parserName= +"number";c.$parsers.push(function(a){return c.$isEmpty(a)?null:Ig.test(a)?parseFloat(a):w});c.$formatters.push(function(a){if(!c.$isEmpty(a)){if(!W(a))throw nb("numfmt",a);a=a.toString()}return a});if(A(d.min)||d.ngMin){var g;c.$validators.min=function(a){return c.$isEmpty(a)||v(g)||a>=g};d.$observe("min",function(a){A(a)&&!W(a)&&(a=parseFloat(a,10));g=W(a)&&!isNaN(a)?a:w;c.$validate()})}if(A(d.max)||d.ngMax){var h;c.$validators.max=function(a){return c.$isEmpty(a)||v(h)||a<=h};d.$observe("max",function(a){A(a)&& +!W(a)&&(a=parseFloat(a,10));h=W(a)&&!isNaN(a)?a:w;c.$validate()})}},url:function(a,b,d,c,e,f){lb(a,b,d,c,e,f);kc(c);c.$$parserName="url";c.$validators.url=function(a,b){var d=a||b;return c.$isEmpty(d)||Gg.test(d)}},email:function(a,b,d,c,e,f){lb(a,b,d,c,e,f);kc(c);c.$$parserName="email";c.$validators.email=function(a,b){var d=a||b;return c.$isEmpty(d)||Hg.test(d)}},radio:function(a,b,d,c){v(d.name)&&b.attr("name",++pb);b.on("click",function(a){b[0].checked&&c.$setViewValue(d.value,a&&a.type)});c.$render= +function(){b[0].checked=d.value==c.$viewValue};d.$observe("value",c.$render)},checkbox:function(a,b,d,c,e,f,g,h){var k=Jd(h,a,"ngTrueValue",d.ngTrueValue,!0),l=Jd(h,a,"ngFalseValue",d.ngFalseValue,!1);b.on("click",function(a){c.$setViewValue(b[0].checked,a&&a.type)});c.$render=function(){b[0].checked=c.$viewValue};c.$isEmpty=function(a){return!1===a};c.$formatters.push(function(a){return oa(a,k)});c.$parsers.push(function(a){return a?k:l})},hidden:z,button:z,submit:z,reset:z,file:z},Cc=["$browser", +"$sniffer","$filter","$parse",function(a,b,d,c){return{restrict:"E",require:["?ngModel"],link:{pre:function(e,f,g,h){h[0]&&(Td[E(g.type)]||Td.text)(e,f,g,h[0],b,a,d,c)}}}}],Jg=/^(true|false|\d+)$/,Qe=function(){return{restrict:"A",priority:100,compile:function(a,b){return Jg.test(b.ngValue)?function(a,b,e){e.$set("value",a.$eval(e.ngValue))}:function(a,b,e){a.$watch(e.ngValue,function(a){e.$set("value",a)})}}}},qe=["$compile",function(a){return{restrict:"AC",compile:function(b){a.$$addBindingClass(b); +return function(b,c,e){a.$$addBindingInfo(c,e.ngBind);c=c[0];b.$watch(e.ngBind,function(a){c.textContent=v(a)?"":a})}}}}],se=["$interpolate","$compile",function(a,b){return{compile:function(d){b.$$addBindingClass(d);return function(c,d,f){c=a(d.attr(f.$attr.ngBindTemplate));b.$$addBindingInfo(d,c.expressions);d=d[0];f.$observe("ngBindTemplate",function(a){d.textContent=v(a)?"":a})}}}}],re=["$sce","$parse","$compile",function(a,b,d){return{restrict:"A",compile:function(c,e){var f=b(e.ngBindHtml),g= +b(e.ngBindHtml,function(a){return(a||"").toString()});d.$$addBindingClass(c);return function(b,c,e){d.$$addBindingInfo(c,e.ngBindHtml);b.$watch(g,function(){c.html(a.getTrustedHtml(f(b))||"")})}}}}],Pe=ia({restrict:"A",require:"ngModel",link:function(a,b,d,c){c.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),te=lc("",!0),ve=lc("Odd",0),ue=lc("Even",1),we=La({compile:function(a,b){b.$set("ngCloak",w);a.removeClass("ng-cloak")}}),xe=[function(){return{restrict:"A",scope:!0,controller:"@", +priority:500}}],Hc={},Kg={blur:!0,focus:!0};p("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var b=ua("ng-"+a);Hc[b]=["$parse","$rootScope",function(d,c){return{restrict:"A",compile:function(e,f){var g=d(f[b],null,!0);return function(b,d){d.on(a,function(d){var e=function(){g(b,{$event:d})};Kg[a]&&c.$$phase?b.$evalAsync(e):b.$apply(e)})}}}}]});var Ae=["$animate","$compile",function(a, +b){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(d,c,e,f,g){var h,k,l;d.$watch(e.ngIf,function(d){d?k||g(function(d,f){k=f;d[d.length++]=b.$$createComment("end ngIf",e.ngIf);h={clone:d};a.enter(d,c.parent(),c)}):(l&&(l.remove(),l=null),k&&(k.$destroy(),k=null),h&&(l=tb(h.clone),a.leave(l).then(function(){l=null}),h=null))})}}}],Be=["$templateRequest","$anchorScroll","$animate",function(a,b,d){return{restrict:"ECA",priority:400,terminal:!0, +transclude:"element",controller:ea.noop,compile:function(c,e){var f=e.ngInclude||e.src,g=e.onload||"",h=e.autoscroll;return function(c,e,m,n,p){var r=0,w,x,q,t=function(){x&&(x.remove(),x=null);w&&(w.$destroy(),w=null);q&&(d.leave(q).then(function(){x=null}),x=q,q=null)};c.$watch(f,function(f){var m=function(){!A(h)||h&&!c.$eval(h)||b()},x=++r;f?(a(f,!0).then(function(a){if(!c.$$destroyed&&x===r){var b=c.$new();n.template=a;a=p(b,function(a){t();d.enter(a,null,e).then(m)});w=b;q=a;w.$emit("$includeContentLoaded", +f);c.$eval(g)}},function(){c.$$destroyed||x!==r||(t(),c.$emit("$includeContentError",f))}),c.$emit("$includeContentRequested",f)):(t(),n.template=null)})}}}}],Se=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(b,d,c,e){ha.call(d[0]).match(/SVG/)?(d.empty(),a(Kc(e.template,Q).childNodes)(b,function(a){d.append(a)},{futureParentElement:d})):(d.html(e.template),a(d.contents())(b))}}}],Ce=La({priority:450,compile:function(){return{pre:function(a,b,d){a.$eval(d.ngInit)}}}}), +Oe=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(a,b,d,c){var e=b.attr(d.$attr.ngList)||", ",f="false"!==d.ngTrim,g=f?Z(e):e;c.$parsers.push(function(a){if(!v(a)){var b=[];a&&p(a.split(g),function(a){a&&b.push(f?Z(a):a)});return b}});c.$formatters.push(function(a){return L(a)?a.join(e):w});c.$isEmpty=function(a){return!a||!a.length}}}},ob="ng-valid",Kd="ng-invalid",Wa="ng-pristine",Kb="ng-dirty",Md="ng-pending",nb=O("ngModel"),Lg=["$scope","$exceptionHandler","$attrs", +"$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,b,d,c,e,f,g,h,k,l){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=w;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$error={};this.$$success={};this.$pending=w;this.$name=l(d.name||"",!1)(a);this.$$parentForm=Jb;var m=e(d.ngModel), +n=m.assign,r=m,B=n,K=null,x,q=this;this.$$setOptions=function(a){if((q.$options=a)&&a.getterSetter){var b=e(d.ngModel+"()"),f=e(d.ngModel+"($$$p)");r=function(a){var c=m(a);H(c)&&(c=b(a));return c};B=function(a,b){H(m(a))?f(a,{$$$p:b}):n(a,b)}}else if(!m.assign)throw nb("nonassign",d.ngModel,ta(c));};this.$render=z;this.$isEmpty=function(a){return v(a)||""===a||null===a||a!==a};this.$$updateEmptyClasses=function(a){q.$isEmpty(a)?(f.removeClass(c,"ng-not-empty"),f.addClass(c,"ng-empty")):(f.removeClass(c, +"ng-empty"),f.addClass(c,"ng-not-empty"))};var t=0;Gd({ctrl:this,$element:c,set:function(a,b){a[b]=!0},unset:function(a,b){delete a[b]},$animate:f});this.$setPristine=function(){q.$dirty=!1;q.$pristine=!0;f.removeClass(c,Kb);f.addClass(c,Wa)};this.$setDirty=function(){q.$dirty=!0;q.$pristine=!1;f.removeClass(c,Wa);f.addClass(c,Kb);q.$$parentForm.$setDirty()};this.$setUntouched=function(){q.$touched=!1;q.$untouched=!0;f.setClass(c,"ng-untouched","ng-touched")};this.$setTouched=function(){q.$touched= +!0;q.$untouched=!1;f.setClass(c,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){g.cancel(K);q.$viewValue=q.$$lastCommittedViewValue;q.$render()};this.$validate=function(){if(!W(q.$modelValue)||!isNaN(q.$modelValue)){var a=q.$$rawModelValue,b=q.$valid,c=q.$modelValue,d=q.$options&&q.$options.allowInvalid;q.$$runValidators(a,q.$$lastCommittedViewValue,function(e){d||b===e||(q.$modelValue=e?a:w,q.$modelValue!==c&&q.$$writeModelToScope())})}};this.$$runValidators=function(a,b,c){function d(){var c= +!0;p(q.$validators,function(d,e){var g=d(a,b);c=c&&g;f(e,g)});return c?!0:(p(q.$asyncValidators,function(a,b){f(b,null)}),!1)}function e(){var c=[],d=!0;p(q.$asyncValidators,function(e,g){var h=e(a,b);if(!h||!H(h.then))throw nb("nopromise",h);f(g,w);c.push(h.then(function(){f(g,!0)},function(){d=!1;f(g,!1)}))});c.length?k.all(c).then(function(){g(d)},z):g(!0)}function f(a,b){h===t&&q.$setValidity(a,b)}function g(a){h===t&&c(a)}t++;var h=t;(function(){var a=q.$$parserName||"parse";if(v(x))f(a,null); +else return x||(p(q.$validators,function(a,b){f(b,null)}),p(q.$asyncValidators,function(a,b){f(b,null)})),f(a,x),x;return!0})()?d()?e():g(!1):g(!1)};this.$commitViewValue=function(){var a=q.$viewValue;g.cancel(K);if(q.$$lastCommittedViewValue!==a||""===a&&q.$$hasNativeValidators)q.$$updateEmptyClasses(a),q.$$lastCommittedViewValue=a,q.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var b=q.$$lastCommittedViewValue;if(x=v(b)?w:!0)for(var c=0;ce||c.$isEmpty(b)|| +b.length<=e}}}}},Fc=function(){return{restrict:"A",require:"?ngModel",link:function(a,b,d,c){if(c){var e=0;d.$observe("minlength",function(a){e=da(a)||0;c.$validate()});c.$validators.minlength=function(a,b){return c.$isEmpty(b)||b.length>=e}}}}};N.angular.bootstrap?N.console&&console.log("WARNING: Tried to load angular more than once."):(fe(),he(ea),ea.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM", +"PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:"January February March April May June July August September October November December".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),STANDALONEMONTH:"January February March April May June July August September October November December".split(" "),WEEKENDRANGE:[5, +6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-\u00a4",negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",localeID:"en_US",pluralCat:function(a, +c){var e=a|0,f=c;w===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),G(Q).ready(function(){be(Q,xc)}))})(window,document);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend(''); +//# sourceMappingURL=angular.min.js.map diff --git a/bower_components/jquery-ui/jquery-ui.min.js b/bower_components/jquery-ui/jquery-ui.min.js new file mode 100644 index 00000000..5824d129 --- /dev/null +++ b/bower_components/jquery-ui/jquery-ui.min.js @@ -0,0 +1,13 @@ +/*! jQuery UI - v1.11.4 - 2015-03-11 +* http://jqueryui.com +* Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js +* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ + +(function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)})(function(e){function t(t,s){var n,a,o,r=t.nodeName.toLowerCase();return"area"===r?(n=t.parentNode,a=n.name,t.href&&a&&"map"===n.nodeName.toLowerCase()?(o=e("img[usemap='#"+a+"']")[0],!!o&&i(o)):!1):(/^(input|select|textarea|button|object)$/.test(r)?!t.disabled:"a"===r?t.href||s:s)&&i(t)}function i(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}function s(e){for(var t,i;e.length&&e[0]!==document;){if(t=e.css("position"),("absolute"===t||"relative"===t||"fixed"===t)&&(i=parseInt(e.css("zIndex"),10),!isNaN(i)&&0!==i))return i;e=e.parent()}return 0}function n(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},e.extend(this._defaults,this.regional[""]),this.regional.en=e.extend(!0,{},this.regional[""]),this.regional["en-US"]=e.extend(!0,{},this.regional.en),this.dpDiv=a(e("
        "))}function a(t){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return t.delegate(i,"mouseout",function(){e(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",o)}function o(){e.datepicker._isDisabledDatepicker(v.inline?v.dpDiv.parent()[0]:v.input[0])||(e(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),e(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&e(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&e(this).addClass("ui-datepicker-next-hover"))}function r(t,i){e.extend(t,i);for(var s in i)null==i[s]&&(t[s]=i[s]);return t}function h(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.ui=e.ui||{},e.extend(e.ui,{version:"1.11.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({scrollParent:function(t){var i=this.css("position"),s="absolute"===i,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var t=e(this);return s&&"static"===t.css("position")?!1:n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==i&&a.length?a:e(this[0].ownerDocument||document)},uniqueId:function(){var e=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++e)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(i){return t(i,!isNaN(e.attr(i,"tabindex")))},tabbable:function(i){var s=e.attr(i,"tabindex"),n=isNaN(s);return(n||s>=0)&&t(i,!n)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(t,i){function s(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+i]=function(t){return void 0===t?o["inner"+i].call(this):this.each(function(){e(this).css(a,s(this,t)+"px")})},e.fn["outer"+i]=function(t,n){return"number"!=typeof t?o["outer"+i].call(this,t):this.each(function(){e(this).css(a,s(this,t,!0,n)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),disableSelection:function(){var e="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(e+".ui-disableSelection",function(e){e.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(t){if(void 0!==t)return this.css("zIndex",t);if(this.length)for(var i,s,n=e(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),e.ui.plugin={add:function(t,i,s){var n,a=e.ui[t].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(e,t,i,s){var n,a=e.plugins[t];if(a&&(s||e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)e.options[a[n][0]]&&a[n][1].apply(e.element,i)}};var l=0,u=Array.prototype.slice;e.cleanData=function(t){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=e._data(n,"events"),s&&s.remove&&e(n).triggerHandler("remove")}catch(o){}t(i)}}(e.cleanData),e.widget=function(t,i,s){var n,a,o,r,h={},l=t.split(".")[0];return t=t.split(".")[1],n=l+"-"+t,s||(s=i,i=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[l]=e[l]||{},a=e[l][t],o=e[l][t]=function(e,t){return this._createWidget?(arguments.length&&this._createWidget(e,t),void 0):new o(e,t)},e.extend(o,a,{version:s.version,_proto:e.extend({},s),_childConstructors:[]}),r=new i,r.options=e.widget.extend({},r.options),e.each(s,function(t,s){return e.isFunction(s)?(h[t]=function(){var e=function(){return i.prototype[t].apply(this,arguments)},n=function(e){return i.prototype[t].apply(this,e)};return function(){var t,i=this._super,a=this._superApply;return this._super=e,this._superApply=n,t=s.apply(this,arguments),this._super=i,this._superApply=a,t}}(),void 0):(h[t]=s,void 0)}),o.prototype=e.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||t:t},h,{constructor:o,namespace:l,widgetName:t,widgetFullName:n}),a?(e.each(a._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),e.widget.bridge(t,o),o},e.widget.extend=function(t){for(var i,s,n=u.call(arguments,1),a=0,o=n.length;o>a;a++)for(i in n[a])s=n[a][i],n[a].hasOwnProperty(i)&&void 0!==s&&(t[i]=e.isPlainObject(s)?e.isPlainObject(t[i])?e.widget.extend({},t[i],s):e.widget.extend({},s):s);return t},e.widget.bridge=function(t,i){var s=i.prototype.widgetFullName||t;e.fn[t]=function(n){var a="string"==typeof n,o=u.call(arguments,1),r=this;return a?this.each(function(){var i,a=e.data(this,s);return"instance"===n?(r=a,!1):a?e.isFunction(a[n])&&"_"!==n.charAt(0)?(i=a[n].apply(a,o),i!==a&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):e.error("no such method '"+n+"' for "+t+" widget instance"):e.error("cannot call methods on "+t+" prior to initialization; "+"attempted to call method '"+n+"'")}):(o.length&&(n=e.widget.extend.apply(null,[n].concat(o))),this.each(function(){var t=e.data(this,s);t?(t.option(n||{}),t._init&&t._init()):e.data(this,s,new i(n,this))})),r}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
        ",options:{disabled:!1,create:null},_createWidget:function(t,i){i=e(i||this.defaultElement||this)[0],this.element=e(i),this.uuid=l++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=e(),this.hoverable=e(),this.focusable=e(),i!==this&&(e.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===i&&this.destroy()}}),this.document=e(i.style?i.ownerDocument:i.document||i),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(t,i){var s,n,a,o=t;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof t)if(o={},s=t.split("."),t=s.shift(),s.length){for(n=o[t]=e.widget.extend({},this.options[t]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(t=s.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=i}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=i}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!t),t&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(t,i,s){var n,a=this;"boolean"!=typeof t&&(s=i,i=t,t=!1),s?(i=n=e(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),e.each(s,function(s,o){function r(){return t||a.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||e.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(t,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(i).undelegate(i),this.bindings=e(this.bindings.not(t).get()),this.focusable=e(this.focusable.not(t).get()),this.hoverable=e(this.hoverable.not(t).get())},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,o=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),o=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&e.effects&&e.effects.effect[r]?s[t](n):r!==t&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}}),e.widget;var d=!1;e(document).mouseup(function(){d=!1}),e.widget("ui.mouse",{version:"1.11.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(t){if(!d){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(t),this._mouseDownEvent=t;var i=this,s=1===t.which,n="string"==typeof this.options.cancel&&t.target.nodeName?e(t.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(t)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(t)!==!1,!this._mouseStarted)?(t.preventDefault(),!0):(!0===e.data(t.target,this.widgetName+".preventClickEvent")&&e.removeData(t.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return i._mouseMove(e)},this._mouseUpDelegate=function(e){return i._mouseUp(e)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),t.preventDefault(),d=!0,!0)):!0}},_mouseMove:function(t){if(this._mouseMoved){if(e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button)return this._mouseUp(t);if(!t.which)return this._mouseUp(t)}return(t.which||t.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),d=!1,!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),function(){function t(e,t,i){return[parseFloat(e[0])*(p.test(e[0])?t/100:1),parseFloat(e[1])*(p.test(e[1])?i/100:1)]}function i(t,i){return parseInt(e.css(t,i),10)||0}function s(t){var i=t[0];return 9===i.nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:e.isWindow(i)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var n,a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,d=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,p=/%$/,f=e.fn.position;e.position={scrollbarWidth:function(){if(void 0!==n)return n;var t,i,s=e("
        "),a=s.children()[0];return e("body").append(s),t=a.offsetWidth,s.css("overflow","scroll"),i=a.offsetWidth,t===i&&(i=s[0].clientWidth),s.remove(),n=t-i},getScrollInfo:function(t){var i=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),s=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),n="scroll"===i||"auto"===i&&t.widthi?"left":t>0?"right":"center",vertical:0>a?"top":s>0?"bottom":"middle"};d>m&&m>r(t+i)&&(h.horizontal="center"),c>g&&g>r(s+a)&&(h.vertical="middle"),h.important=o(r(t),r(i))>o(r(s),r(a))?"horizontal":"vertical",n.using.call(this,e,h)}),u.offset(e.extend(M,{using:l}))})},e.ui.position={fit:{left:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=e.left-t.collisionPosition.marginLeft,h=n-r,l=r+t.collisionWidth-a-n;t.collisionWidth>a?h>0&&0>=l?(i=e.left+h+t.collisionWidth-a-n,e.left+=h-i):e.left=l>0&&0>=h?n:h>l?n+a-t.collisionWidth:n:h>0?e.left+=h:l>0?e.left-=l:e.left=o(e.left-r,e.left)},top:function(e,t){var i,s=t.within,n=s.isWindow?s.scrollTop:s.offset.top,a=t.within.height,r=e.top-t.collisionPosition.marginTop,h=n-r,l=r+t.collisionHeight-a-n;t.collisionHeight>a?h>0&&0>=l?(i=e.top+h+t.collisionHeight-a-n,e.top+=h-i):e.top=l>0&&0>=h?n:h>l?n+a-t.collisionHeight:n:h>0?e.top+=h:l>0?e.top-=l:e.top=o(e.top-r,e.top)}},flip:{left:function(e,t){var i,s,n=t.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=e.left-t.collisionPosition.marginLeft,u=l-h,d=l+t.collisionWidth-o-h,c="left"===t.my[0]?-t.elemWidth:"right"===t.my[0]?t.elemWidth:0,p="left"===t.at[0]?t.targetWidth:"right"===t.at[0]?-t.targetWidth:0,f=-2*t.offset[0];0>u?(i=e.left+c+p+f+t.collisionWidth-o-a,(0>i||r(u)>i)&&(e.left+=c+p+f)):d>0&&(s=e.left-t.collisionPosition.marginLeft+c+p+f-h,(s>0||d>r(s))&&(e.left+=c+p+f))},top:function(e,t){var i,s,n=t.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=e.top-t.collisionPosition.marginTop,u=l-h,d=l+t.collisionHeight-o-h,c="top"===t.my[1],p=c?-t.elemHeight:"bottom"===t.my[1]?t.elemHeight:0,f="top"===t.at[1]?t.targetHeight:"bottom"===t.at[1]?-t.targetHeight:0,m=-2*t.offset[1];0>u?(s=e.top+p+f+m+t.collisionHeight-o-a,(0>s||r(u)>s)&&(e.top+=p+f+m)):d>0&&(i=e.top-t.collisionPosition.marginTop+p+f+m-h,(i>0||d>r(i))&&(e.top+=p+f+m))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,i,s,n,o,r=document.getElementsByTagName("body")[0],h=document.createElement("div");t=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&e.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)t.style[o]=s[o];t.appendChild(h),i=r||document.documentElement,i.insertBefore(t,i.firstChild),h.style.cssText="position: absolute; left: 10.7432222px;",n=e(h).offset().left,a=n>10&&11>n,t.innerHTML="",i.removeChild(t)}()}(),e.ui.position,e.widget("ui.accordion",{version:"1.11.4",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),t.collapsible||t.active!==!1&&null!=t.active||(t.active=0),this._processPanels(),0>t.active&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").removeUniqueId(),this._destroyIcons(),e=this.headers.next().removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&e.css("height","")},_setOption:function(e,t){return"active"===e?(this._activate(t),void 0):("event"===e&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),"collapsible"!==e||t||this.options.active!==!1||this._activate(0),"icons"===e&&(this._destroyIcons(),t&&this._createIcons()),"disabled"===e&&(this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)),void 0)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var i=e.ui.keyCode,s=this.headers.length,n=this.headers.index(t.target),a=!1;switch(t.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(t);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(e(t.target).attr("tabIndex",-1),e(a).attr("tabIndex",0),a.focus(),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t=this.options;this._processPanels(),t.active===!1&&t.collapsible===!0||!this.headers.length?(t.active=!1,this.active=e()):t.active===!1?this._activate(0):this.active.length&&!e.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=e()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var e=this.headers,t=this.panels;this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-state-default ui-corner-all"),this.panels=this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide(),t&&(this._off(e.not(this.headers)),this._off(t.not(this.panels)))},_refresh:function(){var t,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var t=e(this),i=t.uniqueId().attr("id"),s=t.next(),n=s.uniqueId().attr("id");t.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(t=n.height(),this.element.siblings(":visible").each(function(){var i=e(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(t-=i.outerHeight(!0))}),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):"auto"===s&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var i=this._findActive(t)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:e.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):e()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&e.each(t.split(" "),function(e,t){i[t]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var i=this.options,s=this.active,n=e(t.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?e():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?e():n,newPanel:r};t.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",t,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?e():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(t){var i=t.newPanel,s=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,t):(s.hide(),i.show(),this._toggleComplete(t)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(e(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(e,t,i){var s,n,a,o=this,r=0,h=e.css("box-sizing"),l=e.length&&(!t.length||e.index()",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},items:"> *",menus:"ul",position:{my:"left-1 top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item":function(e){e.preventDefault()},"click .ui-menu-item":function(t){var i=e(t.target);!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&e(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){if(!this.previousFilter){var i=e(t.currentTarget); +i.siblings(".ui-state-active").removeClass("ui-state-active"),this.focus(t,i)}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var i=this.active||this.element.find(this.options.items).eq(0);t||this.focus(e,i)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){this._closeOnDocumentClick(e)&&this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").removeUniqueId().removeClass("ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){var i,s,n,a,o=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:o=!1,s=this.previousFilter||"",n=String.fromCharCode(t.keyCode),a=!1,clearTimeout(this.filterTimer),n===s?a=!0:n=s+n,i=this._filterMenuItems(n),i=a&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(t.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(t,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}o&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.is("[aria-haspopup='true']")?this.expand(e):this.select(e))},refresh:function(){var t,i,s=this,n=this.options.icons.submenu,a=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),a.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-front").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),i=t.parent(),s=e("").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);i.attr("aria-haspopup","true").prepend(s),t.attr("aria-labelledby",i.attr("id"))}),t=a.add(this.element),i=t.find(this.options.items),i.not(".ui-menu-item").each(function(){var t=e(this);s._isDivider(t)&&t.addClass("ui-widget-content ui-menu-divider")}),i.not(".ui-menu-item, .ui-menu-divider").addClass("ui-menu-item").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(e,t){"icons"===e&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(t.submenu),"disabled"===e&&this.element.toggleClass("ui-state-disabled",!!t).attr("aria-disabled",t),this._super(e,t)},focus:function(e,t){var i,s;this.blur(e,e&&"focus"===e.type),this._scrollIntoView(t),this.active=t.first(),s=this.active.addClass("ui-state-focus").removeClass("ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").addClass("ui-state-active"),e&&"keydown"===e.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=t.children(".ui-menu"),i.length&&e&&/^mouse/.test(e.type)&&this._startOpening(i),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,n=t.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=t.outerHeight(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(e,t){t||clearTimeout(this.timer),this.active&&(this.active.removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active}))},_startOpening:function(e){clearTimeout(this.timer),"true"===e.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(e)},this.delay))},_open:function(t){var i=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(t,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(t),this.activeMenu=s},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find(".ui-state-active").not(".ui-state-focus").removeClass("ui-state-active")},_closeOnDocumentClick:function(t){return!e(t.target).closest(".ui-menu").length},_isDivider:function(e){return!/[^\-\u2014\u2013\s]/.test(e.text())},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,i){var s;this.active&&(s="first"===e||"last"===e?this.active["first"===e?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[e+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[t]()),this.focus(i,s)},nextPage:function(t){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=e(this),0>i.offset().top-s-n}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(t),void 0)},previousPage:function(t){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=e(this),i.offset().top-s+n>0}),this.focus(t,i)):this.focus(t,this.activeMenu.find(this.options.items).first())),void 0):(this.next(t),void 0)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var t,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return t=!0,s=!0,i=!0,void 0;t=!1,s=!1,i=!1;var a=e.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:t=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:t=!0,this._move("nextPage",n);break;case a.UP:t=!0,this._keyEvent("previous",n);break;case a.DOWN:t=!0,this._keyEvent("next",n);break;case a.ENTER:this.menu.active&&(t=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(t)return t=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=e.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(e){return s?(s=!1,e.preventDefault(),void 0):(this._searchTimeout(e),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(e),this._change(e),void 0)}}),this._initSource(),this.menu=e("
      - +
      \ No newline at end of file diff --git a/templates/types/object.html b/templates/types/object.html index 826dfa59..3d650ccd 100644 --- a/templates/types/object.html +++ b/templates/types/object.html @@ -10,5 +10,5 @@ - +
      \ No newline at end of file From 57f13beac08aeca0aeddf77985f295c3e3c1ad0a Mon Sep 17 00:00:00 2001 From: Tomas Cejka Date: Tue, 5 Apr 2016 11:01:05 +0200 Subject: [PATCH 062/113] vagrant: centos7: set selinux context for logs&cache --- install/Vagrantfile | 4 ---- install/centos7/install.sh | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/install/Vagrantfile b/install/Vagrantfile index 771e6832..d1293ff9 100644 --- a/install/Vagrantfile +++ b/install/Vagrantfile @@ -6,10 +6,6 @@ Vagrant.configure(2) do |config| config.vm.network "forwarded_port", guest: 80, host: 2280 - config.vm.provision "shell" do |s| - s.inline = "sed -i 's/SELINUX=\(enforcing\|permissive\)/SELINUX=disabled/g' /etc/selinux/config" - end - config.vm.provision "shell" do |s| s.path = "centos7/install.sh" end diff --git a/install/centos7/install.sh b/install/centos7/install.sh index 6f707daa..f17eedee 100755 --- a/install/centos7/install.sh +++ b/install/centos7/install.sh @@ -65,5 +65,6 @@ service httpd restart service netopeerguid restart cd /var/www/netopeergui php app/console app:install --post=install +chcon -R -t httpd_sys_rw_content_t /var/www/netopeergui/app/{cache,logs} ) From b2e8f32068e95bf6b2a793735316ac2147c6f9d7 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 5 Apr 2016 11:13:07 +0200 Subject: [PATCH 063/113] filters json output to changed and key values only --- js/JSONedit.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/js/JSONedit.js b/js/JSONedit.js index 6df89c9c..55b357f5 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -56,6 +56,33 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) var cleanJson = $filter('json')(jsonData); var jsonObj = angular.fromJson(cleanJson); var removeSchemaNodes = function(obj) { + traverse(obj).forEach(function (element, index, array) { + if (typeof this.key !== "undefined") { + var schemaPath = this.path.slice(0, -1); + var attrPath = this.path.slice(0, -1); + var attrChildPath = this.path.slice(0); // clone an array + schemaPath.push('$@'+this.key); + attrPath.push('@'+this.key); + attrChildPath.push('@'); + var schema = traverse(obj).get(schemaPath); + var attr = traverse(obj).get(attrPath); + var attrChild = traverse(obj).get(attrChildPath); + //if (this.key == 'groups') { + // console.log(attrChildPath); + // console.log(attrChild); + //} + if ((!angular.isUndefined(attr) || !angular.isUndefined(attrChild)) || (!angular.isUndefined(schema) && schema['iskey'] == true)) { + // leave key elements + + } else if (this.key.indexOf('$@') !== -1 || this.key.indexOf('@') !== -1) { + // leave attributes + + } else if (this.notRoot && !angular.isUndefined(this.parent.key) && this.path.toString().indexOf('@') === -1) { + this.delete(true); + } + } + }); + traverse(obj).forEach(function (element, index, array) { if (typeof this.key !== "undefined") { if (this.key.indexOf('$@') !== -1) { From 757eca062202c328eeeaab0d0eedafa77e7539f4 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 5 Apr 2016 11:14:06 +0200 Subject: [PATCH 064/113] call ajax routes using separate ajaxService --- js/JSONedit.js | 34 ++++++++++++++++++---------------- js/services/ajaxService.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 js/services/ajaxService.js diff --git a/js/JSONedit.js b/js/JSONedit.js index 55b357f5..4c9ed6b7 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -2,9 +2,9 @@ var storage = Rhaboo.perishable(window.location.href); var historyIndex = 0, historyUndo = 0; -var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) +var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse', 'NetopeerGUIServices']) - .controller('ConfigurationController', function ($scope, $filter, $http, $window, $timeout, traverse) { + .controller('ConfigurationController', function ($scope, $filter, $http, $window, $timeout, traverse, AjaxService) { storage.write('revisions', []); storage.erase('revisions'); @@ -20,9 +20,14 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) isRedo = false; $scope.reload = function() { - $http.get(window.location.href + '?angular=true').success(function (data) { - $scope.jsonData = data; - }); + + AjaxService.reloadData() + .then(function successCallback(data) { + $scope.jsonData = data.data; + }, function errorCallback(data) { + alert('error'); + console.log('data'); + }); } $scope.reload(); @@ -130,18 +135,15 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse']) $scope.submitConfiguration = function(jsonData) { var cleanJson = cleanupJSON(jsonData); cleanJson = JSON.parse(cleanJson); - $http({ - url: window.location.href + '?angular=true', - method: 'POST', - data: cleanJson - }).then(function successCallback(data) { - $.netopeergui.processResponseData(data.data, function() { - //$scope.reload(); + AjaxService.submitConfiguration(cleanJson) + .then(function successCallback(data) { + $.netopeergui.processResponseData(data.data, function() { + //$scope.reload(); + }); + }, function errorCallback(data) { + alert('error'); + console.log(data); }); - }, function errorCallback(data) { - alert('error'); - console.log('data'); - }); }; } ); \ No newline at end of file diff --git a/js/services/ajaxService.js b/js/services/ajaxService.js new file mode 100644 index 00000000..2544c13f --- /dev/null +++ b/js/services/ajaxService.js @@ -0,0 +1,28 @@ +var services = angular.module('NetopeerGUIServices', []) + +.service('AjaxService', function ($http) { + $http.defaults.cache = true; + + this.reloadData = function() { + return $http({ + url: window.location.href + '?angular=true', + method: 'GET' + }); + }; + + this.loadSchema = function(connIds, filters) { + return $http({ + url: baseURL + '/ajax/schema/', + method: 'POST', + data: {'angular': true, 'connIds': connIds, 'filters': filters} + }); + }; + + this.submitConfiguration = function(cleanJson) { + return $http({ + url: window.location.href + '?angular=true', + method: 'POST', + data: cleanJson + }); + }; +}); \ No newline at end of file From 691dc709b2464991b2ce49be0071a9858fae566a Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 5 Apr 2016 11:16:18 +0200 Subject: [PATCH 065/113] loads schema from ajaxService if not available (for new nodes). Partial bugfix of adding new nodes behaviour. --- js/directives2.js | 133 ++++++++++++++++++++++++------ public/templates.js | 8 +- templates/directives/addItem.html | 26 +++++- 3 files changed, 135 insertions(+), 32 deletions(-) diff --git a/js/directives2.js b/js/directives2.js index 1b1768ad..21ffd113 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -4,7 +4,7 @@ var counts = { object: 0 }; -var NetopeerGUI = angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap', 'configurationTemplates']); +var NetopeerGUI = angular.module('JSONedit', ['ui.sortable', 'ui.bootstrap', 'configurationTemplates', 'NetopeerGUIServices']); NetopeerGUI.directive('ngModelOnblur', function() { // override the default input to update on blur @@ -24,7 +24,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { } }; }) -.directive('json', function($compile, $log) { +.directive('json', function($compile, $log, AjaxService, $cacheFactory, $rootScope) { return { restrict: 'E', scope: { @@ -60,7 +60,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.sortableOptions = { axis: 'y', update: function(e, ui) { - setIetfOperation('replace', scope.$parent.$parent.newkey, scope.$parent.$parent.$parent.$parent.$parent.child); + setIetfOperation('replace', scope.$parent.$parent.newkey, scope.getParents($parent, 4).child); } }; if (scope.$parent.defaultCollapsed === undefined) { @@ -87,20 +87,13 @@ NetopeerGUI.directive('ngModelOnblur', function() { return type === "inet:uri"; }; - var getType = function(key, obj, parent) { - var schema = getSchemaFromKey(key, parent); + var getType = function(key, child, parent) { // get custom yang datatype - var type = Object.prototype.toString.call(obj); - - if (type === "[object Object]") { - return objectName; - } else if(type === "[object Array]"){ - return arrayName; - } + var type = Object.prototype.toString.call(child); var eltype = getEltype(key, parent); - if (eltype === "container") { + if (eltype === "container" || eltype === "list" || type === "[object Object]") { return objectName; } else if (eltype === "leaf-list") { return arrayName; @@ -132,15 +125,51 @@ NetopeerGUI.directive('ngModelOnblur', function() { }; scope.getType = getType; + scope.getEltype = getEltype; scope.log = function(data) { console.log(data); }; - var getSchemaFromKey = function(key, parent) { - if (typeof parent === "undefined" || parent['$@'+key] === "undefined") { - return false; + var getSchemaFromKey = function(key, parent, child) { + if (typeof parent === "undefined" || typeof parent['$@'+key] === "undefined") { + if (typeof key === "undefined" || typeof parent === "undefined") return false; + + var path = scope.getPath(parent, 'key'); + + var parentKey = path.replace('/', '').split(':'); + var ns = parentKey[0] + ":"; + var rootElem = parentKey[1]; + path = path + '/' + key; + + if (angular.isUndefined($rootScope.cache)) { + //try { + $rootScope.cache = $cacheFactory(window.location.href); + //} catch (exception) {}; + } + if (angular.isUndefined($rootScope.cache.get(path))) { + AjaxService.loadSchema([connId], [path]) + .then(function successCallback(data) { + var schema = data.data; + + if (typeof schema === "undefined" || typeof schema['$@'+ns+key] === "undefined") { + return false; + } + // insert loaded schema into current object + if (!angular.isUndefined(child)) { + child['$@'+key] = schema['$@'+ns+key]; + } + parent['$@'+key] = schema['$@'+ns+key]; + $rootScope.cache.put(path, parent['$@'+key]); + return parent['$@'+key]; + }, function errorCallback(data) { + return false; + }); + } else { + return $rootScope.cache.get(path); + } + } else { + return parent['$@'+key]; } - return parent['$@'+key]; }; scope.getSchemaFromKey = getSchemaFromKey; @@ -184,7 +213,15 @@ NetopeerGUI.directive('ngModelOnblur', function() { }; scope.addItem = function(key, obj, parent) { var type = getType(parent.keyName, undefined, obj); - var parentType = getType(parent.$parent.$parent.$parent.$parent.key, obj); + var parentType = objectName; + //if (typeof parent.$parent.$parent !== "undefined") { + parentType = getType(scope.getParents(parent, 4).key, obj); + //} + //console.log(key); + //console.log(obj); + //console.log(parent); + //console.log(type); + //console.log(parentType); if (parentType == "Object") { // check input for key @@ -241,7 +278,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { default: console.log('2not implemented ' + parent.valueType); // TOOD } - setIetfOperation('replace', parent.$parent.$parent.$parent.$parent.key, parent.$parent.$parent.$parent.$parent.$parent.$parent.child); // TODO replace order in array + setIetfOperation('replace', scope.getParents(parent, 4).key, scope.getParents(parent, 6).child); // TODO replace order in array parent.valueName = ""; parent.showAddKey = false; } else { @@ -262,14 +299,28 @@ NetopeerGUI.directive('ngModelOnblur', function() { return !(attr && attr === "remove"); }; - scope.getAvailableNodeNames = function (key, obj, parent) { - console.log(key);console.log(obj);console.log(parent); - var children = parent.$parent.$parent.$parent.$parent.$parent.$parent.child['$@'+ parent.$parent.$parent.$parent.key]['children']; - angular.forEach(obj, function(value, key) { + scope.changeParentKeyName = function(key, child, $parent) { + var val = getType(key, child, $parent); + if (val) { + $parent.valueType = val; + } + }; + + scope.getAvailableNodeNames = function (key, child, parent) { + //console.log(key);console.log(child);console.log(parent); + var parentKeyName = scope.getParents(parent, 4).key; + var children = scope.getParents(parent, 6).child['$@'+ parentKeyName]['children']; + + angular.forEach(child, function(value, key) { if (key.indexOf('@') !== 0 && children.indexOf(key) !== -1) { children.splice(children.indexOf(key), 1); } }); + + angular.forEach(children, function (key, value) { + getSchemaFromKey(key, parent, child); + }); + return children; }; @@ -296,7 +347,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { case 'anydata': if (typeof obj[key] !== "undefined") { if (generateEmpty && typeof obj[key]['@'] === "undefined") { - obj[key]['@'] = {}; // create empty attributes object + try { + obj[key]['@'] = {}; // create empty attributes object + } catch (exception) {}; } if (typeof obj[key]['@'] !== "undefined") { return obj[key]['@']; @@ -306,7 +359,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { case 'leaf-list': case 'anyxml': if (generateEmpty && typeof obj['@'+key] === "undefined") { - obj['@'+key] = {}; // create empty attributes object + try { + obj['@'+key] = {}; // create empty attributes object + } catch (exception) {}; } if (typeof obj['@'+key] !== "undefined") { return obj['@'+key]; @@ -322,6 +377,34 @@ NetopeerGUI.directive('ngModelOnblur', function() { return false; }; + scope.getParents = function(obj, number) { + if (typeof obj === "undefined") return false; + var parent = obj; + + for (var i = 0; i < number; i++) { + if (typeof parent.$parent === "undefined") { + return parent; + } + parent = parent.$parent; + } + return parent; + } + + scope.getPath = function(obj, target) { + if (typeof obj === "undefined") return false; + var parent = obj; + var res = ''; + + while (typeof parent.$parent !== "undefined" && parent.$parent !== null) { + parent = parent.$parent; + //if (typeof parent[target] !== "undefined") console.log(parent[target]); + if (parent.hasOwnProperty(target) && typeof parent[target] !== 'undefined') { + res = '/' + parent[target] + res; + } + } + return res; + } + var getAttribute = function(attr, key, obj) { var node = scope.getAttributesNode(key, obj); if (node !== false && typeof node[attr] !== "undefined") { diff --git a/public/templates.js b/public/templates.js index 32dbb2fc..47cb8159 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ -angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n :\n \n\n \n\n \n \n \n \n \n \n
      "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n"); -$templateCache.put("types/array.html","\n
      \n \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); -$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
      ");}]); \ No newline at end of file +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("types/array.html","\n
      \n \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); +$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n\n \n \n \n \n \n
      "); +$templateCache.put("directives/addItem.html","
      \n \n \n \n :\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n \n \n \n \n
      "); +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index ce125a69..cfbe1ea0 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -1,12 +1,32 @@
      - + + : + + - + + + + + + + + + + + + + + + + + + \n \n \n \n \n \n
      "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n");}]); \ No newline at end of file +$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n \n \n \n \n \n \n \n \n \n
      "); +$templateCache.put("directives/addItem.html","
      \n \n \n \n :\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n \n \n \n \n
      "); +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index cfbe1ea0..3e79c5f4 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -1,4 +1,4 @@ -
      +
      diff --git a/templates/directives/switchItem.html b/templates/directives/switchItem.html index 41ceb315..3bc1b8fd 100644 --- a/templates/directives/switchItem.html +++ b/templates/directives/switchItem.html @@ -18,4 +18,6 @@ {{ val }} + + \ No newline at end of file diff --git a/templates/types/object.html b/templates/types/object.html index 3d650ccd..d81a5cb7 100644 --- a/templates/types/object.html +++ b/templates/types/object.html @@ -1,14 +1,17 @@
      - + {{ key }} - - - + + + + + + + -
      \ No newline at end of file From a65e58b5306f5ba8689079589a4284409add9578 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 13 Apr 2016 19:46:31 +0200 Subject: [PATCH 068/113] graphical improvements for large trees --- css/sass/screen.scss | 24 ++++++++++++++---------- css/stylesheets/screen.css | 23 +++++++++++------------ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/css/sass/screen.scss b/css/sass/screen.scss index f15bc43c..f0728604 100644 --- a/css/sass/screen.scss +++ b/css/sass/screen.scss @@ -26,7 +26,7 @@ $fa-font-path: "../netopeer-gui/bundles/fitmoduledefault/netopeerangular/css/fon } } .addItemKeyInput { font-weight: bold; } - .toggle-control { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } + .toggle-control { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; background: #f0f0f0; } > json > .fa-minus-square-o { display: none; } .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0;display: block; i { display: block; } @@ -53,12 +53,16 @@ $fa-font-path: "../netopeer-gui/bundles/fitmoduledefault/netopeerangular/css/fon /* basic layout */ -.jsonContents { margin-left: 25px; } +.jsonContents { margin-left: 25px; position: relative; + &:before { content: ""; position: absolute; border-left: 1px solid #ccc; z-index: 0; top: 0; bottom: 0; left: -17px; } + li .jsonContents { margin-left: 0px; } + li .jsonContents .jsonContents { margin-left: 25px; } + li .jsonContents .arrayOl .jsonContents { margin-left: 0px; } +} -li .jsonContents { margin-left: 0px; } .jsonView { - .block { clear: both; display: block; margin-bottom: 0.5em; } + .block { clear: both; display: block; margin-top: 0.5em; margin-bottom: 0.5em; } .block, .arrayItem { position: relative; z-index: 1; //> * { position: static; z-index: 2; } &:hover { @@ -74,12 +78,12 @@ li .jsonContents { margin-left: 0px; } &:hover { @include opacity(1); } } } - switch-item { margin-right: 15px; } + //switch-item { margin-right: 15px; } .arrayItem { - .jsonContents { margin-top: -14px; } + //.jsonContents { margin-top: -14px; } } - ol.arrayOl { margin: 0; padding-left: 20px; } - li {clear: both;min-height: 30px; } + //ol.arrayOl { margin: 0; padding-left: 20px; } + li {clear: both; min-height: 26px; } ol.arrayOl { .toggle-control { margin-left: -20px; top: 1.3em; display: none; } //.fa-minus-square-o { top: 7px; } @@ -87,10 +91,10 @@ li .jsonContents { margin-left: 0px; } > li > span > span > json > { .toggle-control { left: -40px; } } - li { color: grey; list-style-type: decimal; + li, li li { color: grey; list-style-type: decimal; input { font-style: normal; } } - ol.arrayOl { margin-top: 25px; + ol.arrayOl { margin-top: 0.5em; &, & + add-item .block { margin-left: 25px; } } } diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css index 038e059c..5dc5dcdf 100644 --- a/css/stylesheets/screen.css +++ b/css/stylesheets/screen.css @@ -1297,7 +1297,7 @@ .jsonView input.keyinput { font-weight: bold; } .jsonView input[type="text"].addItemKeyInput, .jsonView input[type="text"].addItemValueInput { border: 1px solid #ccc; background: white; margin-left: 0; } .jsonView .addItemKeyInput { font-weight: bold; } -.jsonView .toggle-control { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; } +.jsonView .toggle-control { float: left; cursor: pointer; position: relative; top: -1em; right: 22px; margin-right: -15px; background: #f0f0f0; } .jsonView > json > .fa-minus-square-o { display: none; } .jsonView .addObjectItemBtn { background-color: transparent; border-color: transparent; padding: 0; border: 0; display: block; } .jsonView .addObjectItemBtn i { display: block; } @@ -1313,11 +1313,13 @@ /* chevrons */ /* add and delete */ /* basic layout */ -.jsonContents { margin-left: 25px; } +.jsonContents { margin-left: 25px; position: relative; } +.jsonContents:before { content: ""; position: absolute; border-left: 1px solid #ccc; z-index: 0; top: 0; bottom: 0; left: -17px; } +.jsonContents li .jsonContents { margin-left: 0px; } +.jsonContents li .jsonContents .jsonContents { margin-left: 25px; } +.jsonContents li .jsonContents .arrayOl .jsonContents { margin-left: 0px; } -li .jsonContents { margin-left: 0px; } - -.jsonView .block { clear: both; display: block; margin-bottom: 0.5em; } +.jsonView .block { clear: both; display: block; margin-top: 0.5em; margin-bottom: 0.5em; } .jsonView .block, .jsonView .arrayItem { position: relative; z-index: 1; } .jsonView .block:hover:before, .jsonView .arrayItem:hover:before { content: ""; position: absolute; left: -100%; right: 0; background: rgba(0, 0, 0, 0.1); padding: 3px 0px; margin-top: -3px; height: 14px; z-index: 0; } .jsonView .jsonItemDesc { color: grey; cursor: default; line-height: 30px; } @@ -1326,15 +1328,12 @@ li .jsonContents { margin-left: 0px; } .jsonView add-item { display: block; min-height: 20px; } .jsonView add-item .addObjectItemBtn { position: relative; z-index: 10; filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=30); opacity: 0.3; } .jsonView add-item .addObjectItemBtn:hover { filter: progid:DXImageTransform.Microsoft.Alpha(enabled=false); opacity: 1; } -.jsonView switch-item { margin-right: 15px; } -.jsonView .arrayItem .jsonContents { margin-top: -14px; } -.jsonView ol.arrayOl { margin: 0; padding-left: 20px; } -.jsonView li { clear: both; min-height: 30px; } +.jsonView li { clear: both; min-height: 26px; } .jsonView ol.arrayOl .toggle-control { margin-left: -20px; top: 1.3em; display: none; } .jsonView ol.arrayOl > li > span > span > json > .toggle-control { left: -40px; } -.jsonView ol.arrayOl li { color: grey; list-style-type: decimal; } -.jsonView ol.arrayOl li input { font-style: normal; } -.jsonView ol.arrayOl ol.arrayOl { margin-top: 25px; } +.jsonView ol.arrayOl li, .jsonView ol.arrayOl li li { color: grey; list-style-type: decimal; } +.jsonView ol.arrayOl li input, .jsonView ol.arrayOl li li input { font-style: normal; } +.jsonView ol.arrayOl ol.arrayOl { margin-top: 0.5em; } .jsonView ol.arrayOl ol.arrayOl, .jsonView ol.arrayOl ol.arrayOl + add-item .block { margin-left: 25px; } .jsonView li select, .jsonView li button { font-style: normal; } .jsonView ol.arrayOl li *:not(.btn):not(.jsonItemDesc):not(.tooltip-inner) { color: black; } From fdb405401f79459346948e3be7494b778446725a Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 13 Apr 2016 19:52:02 +0200 Subject: [PATCH 069/113] better support for leaf values changes --- js/JSONedit.js | 14 ++++++++++++-- js/directives2.js | 43 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/js/JSONedit.js b/js/JSONedit.js index 698d61c7..1f28351c 100644 --- a/js/JSONedit.js +++ b/js/JSONedit.js @@ -83,18 +83,28 @@ var app = angular.module('NetopeerGUIApp', ['JSONedit', 'ngTraverse', 'NetopeerG // leave attributes } else if (this.notRoot && !angular.isUndefined(this.parent.key) && this.path.toString().indexOf('@') === -1) { - this.delete(true); + //this.delete(true); } } }); + // remove schema nodes traverse(obj).forEach(function (element, index, array) { if (typeof this.key !== "undefined") { - if (this.key.indexOf('$@') !== -1) { + if (this.key.indexOf('$@') !== -1 || this.key.indexOf('netopeergui:status') !== -1) { this.remove(); } } }); + + // remove empty atribute nodes + traverse(obj).forEach(function (element, index, array) { + if (typeof this.key !== "undefined") { + if (this.key.indexOf('@') !== -1 && this.isLeaf) { + this.delete(true); + } + } + }); }; removeSchemaNodes(jsonObj); cleanJson = $filter('json')(jsonObj); diff --git a/js/directives2.js b/js/directives2.js index da8e3384..87116137 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -60,7 +60,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.sortableOptions = { axis: 'y', update: function(e, ui) { - setIetfOperation('replace', scope.$parent.$parent.newkey, scope.getParents($parent, 4).child); + setParentChanged(scope.$parent); + setIetfOperation('replace', scope.$parent.$parent.newkey, scope.getParents($parent, 4).child, scope.$parent); } }; if (scope.$parent.defaultCollapsed === undefined) { @@ -242,7 +243,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { return; } else { removeIetfOperation(parent.keyName, obj, parent); - setIetfOperation('create', key, obj, parent); + setParentChanged(parent); + setIetfOperation('create', key, obj); } } // add item to object @@ -260,6 +262,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { default: console.log('not implemented ' + parent.valueType); // TOOD } + setParentChanged(parent); setIetfOperation('create', parent.keyName, obj); //clean-up parent.keyName = ""; @@ -282,7 +285,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { default: console.log('2not implemented ' + parent.valueType); // TOOD } - setIetfOperation('replace', scope.getParents(parent, 4).key, scope.getParents(parent, 6).child); // TODO replace order in array + setParentChanged(parent); + setIetfOperation('replace', scope.getParents(parent, 4).key, scope.getParents(parent, 6).child, parent); // TODO replace order in array parent.valueName = ""; parent.showAddKey = false; } else { @@ -293,9 +297,10 @@ NetopeerGUI.directive('ngModelOnblur', function() { return isNumber(val) ? parseFloat(val) : val; }; - scope.changeValue = function(val, key, child) { + scope.changeValue = function(val, key, child, parent) { child[key] = val; - setIetfOperation('replace', key, child); + setParentChanged(parent); + setIetfOperation('replace', key, child, parent); }; scope.isVisible = function(key, obj) { @@ -386,7 +391,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { var parent = obj; for (var i = 0; i < number; i++) { - if (typeof parent.$parent === "undefined") { + if (typeof parent.$parent === "undefined" || parent.$parent === null) { return parent; } parent = parent.$parent; @@ -438,10 +443,34 @@ NetopeerGUI.directive('ngModelOnblur', function() { return false; }; - var setIetfOperation = function(operation, key, obj) { + var setIetfOperation = function(operation, key, obj, parent) { + var tmpParent = scope.getParents(parent, 11); + if (tmpParent.hasOwnProperty('key') && typeof scope.getParents(tmpParent, 2)['child'] !== 'undefined') { + if (getAttributeType(tmpParent['key'], scope.getParents(tmpParent, 2)['child']) == 'list') { + key = tmpParent['key']; + obj = scope.getParents(tmpParent, 2)['child']; + if (operation == 'replace') { + operation = 'merge'; + } + } + } setAttribute('ietf-netconf:operation', operation, key, obj); }; + var setParentChanged = function(parent) { + if (typeof parent === "undefined") return false; + var target = 'key'; + while (typeof parent.$parent !== "undefined" && parent.$parent !== null) { + var obj = parent; + parent = parent.$parent; + var parentToSet = scope.getParents(parent, 2); + //console.log(parentToSet); + if (parent.hasOwnProperty(target) && typeof parent[target] !== 'undefined' && typeof parentToSet['child'] !== 'undefined') { + setAttribute('netopeergui:status', 'changed', parent[target], parent['child']); + } + } + }; + var removeIetfOperation = function(key, obj) { unsetAttribute('ietf-netconf:operation', key, obj); }; From 53f0099d6df1edb71ddfe9271fd38801d3e2a434 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 13 Apr 2016 19:52:53 +0200 Subject: [PATCH 070/113] not load schema and other stuff when not in edit mode (for session page for example) --- js/directives2.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/js/directives2.js b/js/directives2.js index 87116137..d927b443 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -92,6 +92,22 @@ NetopeerGUI.directive('ngModelOnblur', function() { // get custom yang datatype var type = Object.prototype.toString.call(child); + if (!scope.jsonEditable) { + if (type === "[object Object]") { + return objectName; + } else if (type === "[object Array]") { + return arrayName; + } else if (type === "Boolean" || type === "[object Boolean]") { + return boolName; + } else if (type === 'enumeration') { + return enumerationName; + } else if (isNumberType(type) || type === "[object Number]") { + return numberName; + } else { + return stringName; + } + } + var eltype = getEltype(key, parent); if (eltype === "container" || eltype === "list" || type === "[object Object]") { @@ -110,6 +126,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { } }; var getEltype = function(key, parent) { + if (!scope.jsonEditable) return; + var schema = getSchemaFromKey(key, parent); // get custom yang datatype var eltype = ''; @@ -131,6 +149,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { }; var getSchemaFromKey = function(key, parent, child) { + if (!scope.jsonEditable) return; + if (typeof parent === "undefined" || typeof parent['$@'+key] === "undefined") { if (typeof key === "undefined" || typeof parent === "undefined") return false; @@ -175,11 +195,15 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.getSchemaFromKey = getSchemaFromKey; scope.isConfig = function(key, parent) { + if (!scope.jsonEditable) return false; + var schema = getSchemaFromKey(key, parent); return (schema && typeof schema['config'] !== "undefined" && schema['config'] === true); }; scope.editBarVisible = function(key, parent) { + if (!scope.jsonEditable) return false; + var eltype = getEltype(key, parent); if (eltype) { return (eltype == "list" || eltype == "leaf-list" || eltype == "container"); From 23e38e9feb5d9ee35752b995f660fff6c473fcfe Mon Sep 17 00:00:00 2001 From: David Alexa Date: Wed, 13 Apr 2016 19:53:31 +0200 Subject: [PATCH 071/113] improvements for list behaviour --- js/directives2.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/js/directives2.js b/js/directives2.js index d927b443..4e7e8e31 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -227,12 +227,14 @@ NetopeerGUI.directive('ngModelOnblur', function() { scope.deleteKey = function(key, obj, parent) { if (getType(key, obj, parent) == "Object") { if( confirm('Delete "'+key+'" and all it contains?') ) { + setParentChanged(parent); setIetfOperation('remove', key, obj); //delete obj[key]; // TODO delete children } } else if (getType(key, obj, parent) == "Array") { if( confirm('Delete "'+obj[key]+'"?') ) { + setParentChanged(parent); setIetfOperation('remove', key, obj); //obj.splice(key, 1); // TODO delete children } @@ -360,8 +362,10 @@ NetopeerGUI.directive('ngModelOnblur', function() { var getAttributeType = function(key, obj) { var eltype = getEltype(key, obj); - if (eltype === "container" || eltype === 'list' || eltype === 'anydata') { + if (eltype === "container" || eltype === 'anydata') { return 'anydata'; + } else if (eltype === 'list') { + return 'list'; } else if (eltype === 'leaf' || eltype === 'anyxml') { return 'anyxml'; } else if (eltype === "leaf-list") { @@ -375,7 +379,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { generateEmpty = false; } var eltype = getAttributeType(key, obj); - + if (eltype == 'list') { + obj = scope.getParents(obj, 2); + } switch (eltype) { case 'anydata': if (typeof obj[key] !== "undefined") { @@ -390,6 +396,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { } break; case 'leaf-list': + case 'list': case 'anyxml': if (generateEmpty && typeof obj['@'+key] === "undefined") { try { From f9efd037058f8d76bbaa993e98a92bd92d604c4b Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 19 Apr 2016 06:53:44 +0200 Subject: [PATCH 072/113] apply styles for select from input --- css/sass/screen.scss | 2 ++ css/stylesheets/screen.css | 1 + 2 files changed, 3 insertions(+) diff --git a/css/sass/screen.scss b/css/sass/screen.scss index f0728604..08bb1e84 100644 --- a/css/sass/screen.scss +++ b/css/sass/screen.scss @@ -15,6 +15,8 @@ $fa-font-path: "../netopeer-gui/bundles/fitmoduledefault/netopeerangular/css/fon .jsonView { padding: 30px 0 0 5px; select.form-control { margin: 0; padding: 0; width: 100px; display: inline; padding-left: 5px; } + input, select { position: relative; z-index: 10; } + input { margin: 0; padding: 0; &.form-control { width: 100px; display: inline; padding-left: 5px; position: relative; z-index: 2; } &[type="text"], &[type="number"] { margin: 0; border: 1px solid #ccc; background: #fff; } diff --git a/css/stylesheets/screen.css b/css/stylesheets/screen.css index 5dc5dcdf..3e2c06ec 100644 --- a/css/stylesheets/screen.css +++ b/css/stylesheets/screen.css @@ -1290,6 +1290,7 @@ /* striped background */ .jsonView { padding: 30px 0 0 5px; } .jsonView select.form-control { margin: 0; padding: 0; width: 100px; display: inline; padding-left: 5px; } +.jsonView input, .jsonView select { position: relative; z-index: 10; } .jsonView input { margin: 0; padding: 0; } .jsonView input.form-control { width: 100px; display: inline; padding-left: 5px; position: relative; z-index: 2; } .jsonView input[type="text"], .jsonView input[type="number"] { margin: 0; border: 1px solid #ccc; background: #fff; } From 4527e3c309e3406770e5e325e17c26523d2ec7f5 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 19 Apr 2016 06:54:43 +0200 Subject: [PATCH 073/113] support for enumeration in typedef, configuration output bugfixes --- js/directives2.js | 32 ++++++++++++++++++++++------ public/templates.js | 4 ++-- templates/directives/addItem.html | 8 +++---- templates/directives/switchItem.html | 2 +- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/js/directives2.js b/js/directives2.js index 4e7e8e31..ca0cd762 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -99,8 +99,6 @@ NetopeerGUI.directive('ngModelOnblur', function() { return arrayName; } else if (type === "Boolean" || type === "[object Boolean]") { return boolName; - } else if (type === 'enumeration') { - return enumerationName; } else if (isNumberType(type) || type === "[object Number]") { return numberName; } else { @@ -110,17 +108,21 @@ NetopeerGUI.directive('ngModelOnblur', function() { var eltype = getEltype(key, parent); - if (eltype === "container" || eltype === "list" || type === "[object Object]") { + if (eltype === "container" || eltype === "list") { if (type === "[object Array]") { return arrayName; } return objectName; - } else if (eltype === "leaf-list" || type === "[object Array]") { + } else if (eltype === "leaf-list") { return arrayName; } else if (type === "Boolean" || type === "[object Boolean]") { return boolName; - } else if (type === 'enumeration') { + } else if (eltype === 'enumeration') { return enumerationName; } else if (isNumberType(type) || type === "[object Number]") { return numberName; + } else if (type === "[object Object]") { + return objectName; + } else if (type === "[object Array]") { + return arrayName; } else { return stringName; } @@ -134,6 +136,9 @@ NetopeerGUI.directive('ngModelOnblur', function() { if (schema && typeof schema['eltype'] !== "undefined") { eltype = schema['eltype']; + if (eltype == 'leaf' && typeof schema['typedef'] !== "undefined") { + eltype = schema['typedef']['type']; + } } return eltype; @@ -215,6 +220,16 @@ NetopeerGUI.directive('ngModelOnblur', function() { var type = getType(key, val, parent); return (type == objectName || type == arrayName); }; + scope.getEnumValues = function(key, child, parent) { + var schema = getSchemaFromKey(key, child); + if (schema && typeof schema['enumval'] !== "undefined") { + return schema['enumval']; + } else if (schema && typeof schema['typedef'] !== "undefined" && typeof schema['typedef']['enumval'] !== "undefined") { + return schema['typedef']['enumval']; + } else { + return []; + } + } scope.toggleCollapse = function() { if (scope.collapsed) { scope.collapsed = false; @@ -243,7 +258,12 @@ NetopeerGUI.directive('ngModelOnblur', function() { } }; scope.addItem = function(key, obj, parent) { - var type = getType(parent.keyName, undefined, obj); + if (typeof parent.valueType == "undefined") { + var type = getType(parent.keyName, undefined, obj); + } else { + var type = parent.ValueType; + } + var parentType = objectName; //if (typeof parent.$parent.$parent !== "undefined") { parentType = getType(scope.getParents(parent, 4).key, obj); diff --git a/public/templates.js b/public/templates.js index 97c2a7c6..b4a1c8f0 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("types/array.html","\n
      \n \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); $templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n \n \n \n \n \n \n \n \n \n
      "); -$templateCache.put("directives/addItem.html","
      \n \n \n \n :\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n \n \n \n \n
      "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n");}]); \ No newline at end of file +$templateCache.put("directives/addItem.html","
      \n \n \n \n :\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n \n \n \n \n
      "); +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index 3e79c5f4..3ea754f8 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -2,12 +2,12 @@ - : - + @@ -26,7 +26,7 @@ - + \n \n \n \n \n \n
      "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n");}]); \ No newline at end of file +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n");}]); \ No newline at end of file diff --git a/templates/directives/switchItem.html b/templates/directives/switchItem.html index c124116a..c1c93455 100644 --- a/templates/directives/switchItem.html +++ b/templates/directives/switchItem.html @@ -7,7 +7,7 @@ {{ val }} - + {{ val }} From 3a048262383524d3a9ab9e175fd30a95cacdc0b0 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 19 Apr 2016 08:55:19 +0200 Subject: [PATCH 076/113] adding new nodes offers possibility to set correct input type for value --- js/directives2.js | 4 +++- public/templates.js | 8 ++++---- templates/directives/addItem.html | 32 +++++++++++++++---------------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/js/directives2.js b/js/directives2.js index 906c4a9b..34dc8ed6 100644 --- a/js/directives2.js +++ b/js/directives2.js @@ -274,6 +274,8 @@ NetopeerGUI.directive('ngModelOnblur', function() { //console.log(type); //console.log(parentType); + type = type || parentType; + if (parentType == "Object") { // check input for key if (parent.keyName == undefined || parent.keyName.length == 0){ @@ -306,7 +308,7 @@ NetopeerGUI.directive('ngModelOnblur', function() { case boolName: obj[parent.keyName] = false; break; default: - console.log('not implemented ' + parent.valueType); // TOOD + console.log('not implemented type: ' + type + ' or parentType ' + parent.valueType); // TOOD } setParentChanged(parent); setIetfOperation('create', parent.keyName, obj); diff --git a/public/templates.js b/public/templates.js index 14d5ea2f..959a6b49 100644 --- a/public/templates.js +++ b/public/templates.js @@ -1,4 +1,4 @@ -angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("types/array.html","\n
      \n \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); -$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n \n \n \n \n \n \n \n \n \n
      "); -$templateCache.put("directives/addItem.html","
      \n \n \n \n :\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n \n \n \n \n
      "); -$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n");}]); \ No newline at end of file +angular.module("configurationTemplates", []).run(["$templateCache", function($templateCache) {$templateCache.put("directives/addItem.html","
      \n \n \n \n :\n \n \n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n \n \n \n \n
      "); +$templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n"); +$templateCache.put("types/array.html","\n
      \n \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); +$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n \n \n \n \n \n \n \n \n \n
      ");}]); \ No newline at end of file diff --git a/templates/directives/addItem.html b/templates/directives/addItem.html index 3ea754f8..3184d949 100644 --- a/templates/directives/addItem.html +++ b/templates/directives/addItem.html @@ -9,24 +9,24 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + \n \n
      \n \n \n \n
      "); $templateCache.put("directives/switchItem.html","\n \n \n\n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n \n \n {{ val }}\n \n\n \n"); $templateCache.put("types/array.html","\n
      \n \n
        \n
      1. \n \n
      2. \n
      \n \n
      "); -$templateCache.put("types/object.html","\n
      \n \n \n {{ key }}\n \n \n \n \n \n \n \n \n \n \n \n
      ");}]); \ No newline at end of file +$templateCache.put("types/object.html","\n
      \n \n \n \n {{ key }}\n \n \n \n \n \n \n \n \n \n \n \n \n
      ");}]); \ No newline at end of file diff --git a/templates/types/object.html b/templates/types/object.html index d81a5cb7..edcd4529 100644 --- a/templates/types/object.html +++ b/templates/types/object.html @@ -1,13 +1,15 @@
      - + - {{ key }} - - - - + + {{ key }} + + + + + From 451330a1fa8632548c38797cec6628d7600dbdd1 Mon Sep 17 00:00:00 2001 From: David Alexa Date: Tue, 3 May 2016 07:40:06 +0200 Subject: [PATCH 080/113] bugfix: show change datastore form, show copy config form, load rpc methods --- .../Resources/netopeerangular | 2 +- .../Resources/public/js/module-default.js | 870 ------------------ .../Resources/public/js/tooltip/gips.js | 71 -- .../Resources/views/Module/section.html.twig | 16 - .../views/Module/showRPCForm.html.twig | 17 +- .../Resources/views/layout.html.twig | 1 + .../Controller/AjaxController.php | 2 +- .../Controller/BaseController.php | 18 +- .../Controller/DefaultController.php | 25 +- .../Controller/ModuleController.php | 62 +- .../Resources/public/js/jquery.netopeergui.js | 2 +- .../Resources/views/layout.html.twig | 13 +- .../Functionality/ConnectionFunctionality.php | 39 +- 13 files changed, 60 insertions(+), 1078 deletions(-) delete mode 100644 src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/tooltip/gips.js diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular index 3a048262..133c9ccf 160000 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/netopeerangular @@ -1 +1 @@ -Subproject commit 3a048262383524d3a9ab9e175fd30a95cacdc0b0 +Subproject commit 133c9ccfc9fc111bb5d8e41614fc1f9759bc45d0 diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/module-default.js b/src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/module-default.js index 63ab77db..b443011d 100644 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/module-default.js +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/module-default.js @@ -7,29 +7,6 @@ $(document).ready(function() { function initModuleDefaultJS() { newNodeFormCnt = 0; - // zobrazime jinak skryte ikonky pro pridavani potomku (novych listu XML) - $(".type-list .edit-bar .sibling, .type-list .edit-bar .remove-child, .type-list .edit-bar .child").show(); - - $('.edit-bar').unbind('click').on('click', '.sibling', function() { - duplicateNode($(this)); - }).on('click', ".remove-child", function() { - removeNode($(this)); - }).on('click', ".create-child", function() { -// generateNode($(this)); - createNode($(this)); - }); - - prepareSortable(); - - // line of XML output - $(".leaf-line").hover(function() { - $(this).addClass("hover"); - }, function() { - $(this).removeClass("hover"); - }); - - prepareTooltipActions(); - $("form[name=formConfigData]").on("change", "input, select", function(event){ formInputChanged = true; }); @@ -41,221 +18,7 @@ function initModuleDefaultJS() { $("form").on("change", ".js-auto-submit-on-change", function() { $(this).parents('form').submit(); }); - - /* when range input type, add number of current value before input */ - $("input[type='range']").each(function(i, e) { - var tmp = $("").attr({ - 'class': 'range-cover-number', - type: 'number', - disabled: 'disabled', - value: e.value - }).text(e.value); - $(e).after(tmp); - $(e).bind('change', function() { - $(e).next('.range-cover-number').val(e.value); - }); - }); - - $("body").on('change', 'input.value', function() { - if (!$(this).parent().hasClass('generated')) { - $(this).parent('.leaf-line').addClass('modified'); - } - }); - - showIconsOnLeafLine(); } - -function prepareTooltipActions() { - // tooltip - $('.tooltip-cover .icon-help').each(function() { - initDefaultTooltip($(this)); - }); -} - -function showIconsOnLeafLine() { - /* - if ($(window).width() < 1550) { - $('.root').delegate(".leaf-line", 'hover', function() { - $(this).find('.icon-bar').fadeToggle(); - }); - } else { - $('.root').undelegate('.leaf-line', hover); - } - */ -} - -function initDefaultTooltip($el) { - $el.gips({ 'theme': 'blue', placement: 'top', animationSpeed: 100, bottom: $el.parent().parent().parent().outerHeight(), text: $el.siblings('.tooltip-description').text() }); -} - -function prepareSortable() { - $(".sortable-node").parent().parent().sortable({ - placeholder: "sortable-placeholder ui-state-highlight", - axis: "y", - items: "> div:has(.sortable-node)", - handle: ".sort-item", - deactivate: function(e, ui) { - var $leafs = $(ui.item).parent().find("> div:has(.sortable-node) .sortable-node"); - - // set new index order - $leafs.each(function(i, elem) { - $(elem).find('input, select').each(function(j, e) { - var s = $(e).attr('name'); - var delimIndex = s.lastIndexOf('|'); - if (delimIndex == -1) { - delimIndex = s.lastIndexOf('['); - } - var newXpath = s.substring(0, s.lastIndexOf('[')) + "[index" + i + "|" + s.substring(delimIndex + 1); - $(e).attr('name', newXpath); - }); - }); - - // move all children of prev sortable node - $(ui.item).nextUntil("div:has(.sortable-node)").each(function(i, e) { - $(e).insertBefore($(ui.item)); - }); - - $(".sortable-placeholder").remove(); - } - }).disableSelection(); -} - -function duplicateNode($elem) { - var $cover = createFormUnderlay($elem); - - var xPath = $elem.attr('rel'), // parent xPath - in anchor attribute rel - level = findLevelValue($elem); - - var $currentParent = $elem.parent().parent(); - var $currentParentLevel = $elem.parents('.level-' + level); - - // generate new form - var $form = generateFormObject('duplicatedNodeForm'); - - // current element clone - with all children - var $newClone = $currentParent.clone(); - $form.html($newClone); - if ($currentParent.is(':first-child')) { - $currentParent.nextAll("*").each(function(i, el) { - $form.append($(el).clone()); - }); - } - - // remove all state nodes (this won't be duplicated) - $form.find('.state').remove(); - - // create hidden input with path to the duplicated node - var $elementWithParentXpath = $("") - .attr({ - type: 'hidden', - name: "duplicatedNodeForm[parent]", - value: xPath - }); - $form.prepend($elementWithParentXpath); - - // we have to modify inputs for all children - $form.children().each(function(i, el) { - modifyInputAttributes(el, i, 'duplicatedNodeForm'); - }); - - // create submit and close button - createSubmitButton($form, "Save changes"); - createCloseButton($cover, $form); - - // append created form into the parent - $currentParentLevel.append($form); - - unwrapCoverForm($currentParentLevel, $cover); - - // finally, initialization of Tooltip on cloned elements - // must be after showing form - $form.find('.tooltip-cover .icon-help').each(function() { - initDefaultTooltip($(this)); - }); - - scrollToGeneratedForm($elem, $form); -} - -function scrollToGeneratedForm($elem, $form) { - var section = $elem.parents("section"); - $(section).animate({ - scrollTop: $(section).scrollTop() + $form.offset().top - $("nav#top").outerHeight() - 100 - }, 1000); -} - -function removeNode($elem) { - var $cover = createFormUnderlay($elem); - - var xPath = $elem.attr('rel'); // parent XPath - from attribute rel - var level = findLevelValue($elem); - var $currentParentLevel = $elem.parents('.level-' + level); - $elem.parents('.leaf-line').addClass('active'); - - // generate new form - var $form = generateFormObject('removeNodeForm'); - - // create hidden input with path to the duplicated node - var $elementWithParentXpath = $("") - .attr({ - type: 'hidden', - name: "removeNodeForm[parent]", - value: xPath - }); - $form.prepend($elementWithParentXpath); - - // create submit and close button - createSubmitButton($form, "Delete record"); - createCloseButton($cover, $form); - - // append created form into the parent - $form.insertAfter($currentParentLevel); - - unwrapCoverForm($currentParentLevel, $cover); - scrollToGeneratedForm($elem, $form); -} - -function generateNode($elem) { - var $cover = createFormUnderlay($elem); - - var rel = $elem.attr('rel').split('_'); // rel[0] - xPath, rel[1] - serialized route params - var level = findLevelValue($elem); - var $currentParentLevel = $elem.parents('.level-' + level); - - var xPath = rel[0]; - var loadUrl = rel[1]; - - // generate new form - var $form = generateFormObject('generateNodeForm'); - - // create hidden input with path to the duplicated node - var $elementWithParentXpath = $("") - .attr({ - type: 'hidden', - name: "generateNodeForm[parent]", - value: xPath - }); - $form.prepend($elementWithParentXpath); - - // load URL with HTML form - var $tmpDiv = $("
      ").addClass('root'); - $tmpDiv.load(document.location.protocol + "//" + document.location.host + loadUrl, function() { - // we have to modify inputs for all children - $tmpDiv.children().each(function(i, el) { - modifyInputAttributes(el, i, 'generatedNodeForm'); - }); - }); - $form.append($tmpDiv); - - // create submit and close button - createSubmitButton($form, "Add information"); - createCloseButton($cover, $form); - - // append created form into the parent - $currentParentLevel.append($form); - unwrapCoverForm($currentParentLevel, $cover); - scrollToGeneratedForm($elem, $form); -} - function createFormUnderlay($elem) { var $cover = findFormUnderlayCover($elem); @@ -302,636 +65,3 @@ function recountFormUnderlayDimensions($cover, minusHeight) { 'margin-left': 0 - parseInt($cover.css('padding-left'), 10) }); } - -function findLevelValue($elem) { - var levelRegex = /level-(\d+)/, // regex for level value - level = $elem.parents('div[class*="level-"]').attr('class'); // parent class for level - - if ( level.match(levelRegex) === null || ( level.match(levelRegex) !== null && isNaN(level.match(levelRegex)[1]) ) ) { - - // level does not have to be by first parent, could be on previous level too - if ( $elem.parents('.leaf-line').parent().length ) { - level = $elem.parents('.leaf-line').parent().attr('class'); - if ( level.match(levelRegex) === null || ( level.match(levelRegex) !== null && isNaN(level.match(levelRegex)[1]) ) ) { - level = 0; - } else { - level = parseInt(level.match(levelRegex)[1], 10); - } - } else { - level = 0; - } - - } else { - level = parseInt(level.match(levelRegex)[1], 10); - } - - return level; -} - -function generateFormObject(formName) { - var $form; - // new form object - if is not created, we will create new one - if ( $(".generatedForm").length !== 0 ) { - $form = $('.generatedForm').last(); - } else { - // vytvorime formular - $form = $("
      ") - .attr({ - action: "", - method: "POST", - name: formName, - 'class': 'generatedForm form' - }); - $form.append($("").attr({ - type: 'hidden', - name: 'formId', - value: new Date().getTime() - })); - $form.append($("
      ", { - 'id': 'modelTreeDump' - })); - } - - return $form; -} - -function modifyInputAttributes(el, newIndex, newInputName) { - // clean edit-bar html - $(el).find('.edit-bar').html(''); - - // find all input in this level - var inputArr = $.merge( $(el).children('input, select'), $(el).children('.config-value-cover').find('input, select')); - // modify every input - inputArr.each(function(i, e) { - // rewrite name to duplicatedNodeForm - if ( $(e).attr('name') ) { - var elName = $(e).attr('name').replace('configDataForm', newInputName); - $(e).attr('name', elName); - - if ( $(e).attr('type') === 'range' ) { - $(e).bind('change', function() { - $(e).next('.range-cover-number').val(e.value); - }); - } - - // check, if default attribute is defined - // if yes, default value will be used instead of current value - if ( $(e).attr('default') !== "" ) { - if ( $(e).attr('type') === 'radio' ) { - if ( $(e).attr('value') === $(e).attr('default') ) { - $(e).parent().parent().find('input[checked=checked]').removeAttr('checked'); - $(e).attr('checked', 'checked'); - } - } else { - if ( $(e).attr('value') !== $(e).attr('default') ) { - $(e).attr('value', $(e).attr('default')); - } - } - } - // we have to remove disabled attribute on input (user should be able to edit this value) - $(e).removeAttr('disabled'); - } - }); - - // recursively find next level of input - if ( $(el).children('.leaf-line, div[class*=level]').length ) { - $(el).children('.leaf-line, div[class*=level]').each(function(j, elem) { - modifyInputAttributes(elem, j, newInputName); - }); - } -} - -function createSubmitButton($form, inputValue) { - // create form submit - if already exists, we will delete - // it and append to the end - if ( $form.children("input[type=submit]").length ) { - $form.children("input[type=submit]").remove(); - } - // show submit button only when no form was appended - if (newNodeFormCnt < 1 || inputValue == "Delete record") { - var $elementSubmit = $("") - .attr({ - type: 'submit', - value: inputValue - }); - $form.append($elementSubmit); - } -} - -function createAppendButton($cover, $form) { - // create commit button (if already exists, delete it) - if ( $form.find('a.append-changes').length ) { - $form.find('a.append-changes').remove(); - } - - var $elementAppend = $("") - .attr({ - class: 'append-changes button grey right' - }) - .text('Append changes'); - $form.append($elementAppend); - - $elementAppend.bind('click', function() { - appendChanges($cover, $form); - }); -} - -// put modified form back into parent tree -function appendChanges($cover, $form) { - // wrap back root form - var $originalForm = $(".old-form").removeClass('old-form'); - var $parentsForm = $form; - $cover.find('.root').wrap($originalForm); - $originalForm.remove(); - - // remove underlay - $('.form-underlay').remove(); - $('.form-cover').remove(); - - // remove unwanted elements from form - $form.children('a, input[type=submit], #modelTreeDump').remove(); - $form.find('.generated').removeClass('generated'); - $form.removeClass('generatedForm').addClass('addedForm'); - - // unbind changes (typeahead callbacks) - $form.find('input.label').unbind('click').unbind('change').unbind('focus'); - - // if we add form to newAddedForm, don't append form, only children - if ($form.parents('form[name*=newNodeForm]').length) { - $parentsForm = $form.parents('form[name*=newNodeForm]'); - - $form.children('input[type=hidden]').remove(); - $form.children().unwrap(); - } else { - $form.data('formIndex', newNodeFormCnt++); - } - - // we have to modify xpath and rel attributes for generated icons and inputs - modifyAllInputsXPath($parentsForm.find('.leaf-line'), true); - - $parentsForm.find('input, select').each(function(i,e) { - var name = $(e).attr('name'); - var modifiedName = name.replace(/newNodeForm(\[[\d+]\])?/, 'newNodeForm['+$parentsForm.data('formIndex')+']'); - $(e).attr('name', modifiedName); - }); - - // disable all get-config inputs - $cover.find('.root').find('input:not([type="hidden"]):not([type="submit"]), select').each(function(i,e) { - if (!$(e).parents('.addedForm').length) { - $(e).attr('disabled', 'true'); - } - }); - $(".js-only-for-append-mode").show(); - - $cover.find('.active').removeClass('active'); - formInputChanged = true; -} - -function createCloseButton($cover, $form) { - // create close button and append at the end of form - if ( $form.children("a.close").length ) { - $form.children("a.close").remove(); - } - var $closeButton = $("Close"); - $form.append($closeButton); - - // bind click and keydown event - $closeButton.bind('click', function() { - wrapCoverForm($cover, $form); - }); - $(document).bind('keydown', function(event) { - if ( event.which === 27 ) { - //event.preventDefault(); - wrapCoverForm($cover, $form); - } - }); - if ($cover.find('.form-underlay')) { - $cover.find('.form-underlay').click(function() { - wrapCoverForm($cover, $form); - }); - } -} - -// wrap unwrapped form back to cover whole tree form -function wrapCoverForm($cover, $form) { - var $originalForm = $(".old-form").removeClass('old-form'); - $cover.find('.root').wrap($originalForm); - $originalForm.remove(); - $form.remove(); - $('.form-underlay').remove(); - $('.form-cover').remove(); - $('.generatedForm').remove(); - $cover.find('.active').removeClass('active'); - - formInputChanged = false; -} - -// unwrap old form (we can't have two forms inside in HTML -// if we want to work properly), so old form will stay -// alone prepending cover - so we can wrap it always back, -// for example while close button is clicked -function unwrapCoverForm($currentParentLevel, $cover) { - if ($(".old-form").length) return; - - var $form = $currentParentLevel.parents('section').find('form').first(); - var $oldForm = $form.clone().addClass('old-form'); - $oldForm.html(''); - $cover.prepend($oldForm); - $form.children('.root').unwrap(); - - recountFormUnderlayDimensions($cover); -} - -function createNode($elem) { - var $cover = createFormUnderlay($elem); - - // we will create cover div - var $coverDiv = $("
      ").addClass('leaf-line').addClass('generated'); - - // generate new form - var $form = generateFormObject('newNodeForm'); - - createNodeElements($elem, $coverDiv, $form); - - // create submit and close button - createSubmitButton($form, "Create new node"); - createAppendButton($cover, $form); - createCloseButton($cover, $form); - - // reload content of model dump tree - if ($("#hiddenModelTreeDump").length) { - reloadModalTreeDumpContent($cover, $form); - } - - var $currentParent = $elem.parent().parent(); - unwrapCoverForm($currentParent, $cover); - if ( !$('.generatedForm').length ) { - scrollToGeneratedForm($elem, $form); - } - - // finally focus on new created elem - $coverDiv.find('input.label').focus(); -} - -function createNodeElements($elem, $coverDiv, $form, childName, childData) { - var level = findLevelValue($elem) + 1; - var xPath = $elem.attr('rel'); // parent XPath - from attribute rel - var $currentParent = $elem.parent().parent(); - var $currentParentLevel = $elem.parents('.level-' + level); - var $editBar = $elem.parent().clone(); // editBar clone - we will modify it below - - // remove last index and replace it with attr name - var parentName = ""; - if ($currentParent.find('.label-cover strong').length) { - parentName = $currentParent.find('.label-cover strong').text(); - } else { - parentName = $currentParent.find('input.label').val(); - } - var lastIndex = xPath.lastIndexOf("*?"); - if (lastIndex == -1) { - lastIndex = xPath.length; - } - var parentXPath = xPath.substring(0, lastIndex) + parentName; - - var uniqueId = generateUniqueId(); - var urlTemplate = $elem.data().typeaheadPath; - var sourceUrl = urlTemplate - .replace("FORMID", $form.find('input[name=formId]').val()) - .replace("XPATH", encodeURIComponent(parentXPath)); - - var labelValue = ""; - var generatedInput = - labelAttributes = - editBarAttributes = false; - - if (childData !== undefined && childName !== undefined) { - labelValue = childName; - generatedInput = childData.valueElem; - labelAttributes = childData.labelAttributes; - editBarAttributes = childData.editBar; - } - - var refreshTooltipData = function($currentInput, labelAttributes) { - // remove old tooltip - $currentInput.parent().find('.tooltip-cover').remove(); - - // if description is defined, show tooltip icon - if (labelAttributes !== undefined && labelAttributes.description !== undefined) { - var $tooltip = $("").addClass('tooltip-cover').addClass('help'); - $tooltip.append($("").addClass('icon-help').text("?")); - $tooltip.append($("").addClass('tooltip-description').text(labelAttributes.description)); - $tooltip.insertBefore($currentInput); - initDefaultTooltip($tooltip.find(".icon-help")); - } - - // if mandatory is defined, show tooltip icon - if (labelAttributes !== undefined && labelAttributes.mandatory !== undefined && labelAttributes.mandatory == "true") { - var $tooltip = $("").addClass('tooltip-cover').addClass('mandatory'); - $tooltip.append($("").addClass('icon-help').text("*")); - $tooltip.append($("").addClass('tooltip-description').text("Mandatory item")); - $tooltip.insertBefore($currentInput); - initDefaultTooltip($tooltip.find(".icon-help")); - } - }; - - var insertValueElement = function($currentInput, valueElem) { - var $newHtml = $(valueElem); - if ($newHtml.prop('tagName') == "INPUT") { - $newHtml.attr('name', $currentInput.attr('name').replace('label', 'value')); - $newHtml.val(''); - if ($newHtml.attr('default') != "") { - $newHtml.val($newHtml.attr('default')); - } - $newHtml.removeAttr('disabled'); - $currentInput.parents('.leaf-line').append($newHtml); - $newHtml.focus(); - } else { - $newHtml.find('input, select').attr('name', $currentInput.attr('name').replace('label', 'value')).removeAttr('disabled'); - $currentInput.parents('.leaf-line').append($newHtml); - $newHtml.find('input, select').not('.label').first().focus(); - } - }; - - var createInputValue = function() { - // input for value - var $elementValue = $("") - .attr({ - name: 'newNodeForm[value' + uniqueId + '_' + xPath + ']', - type: 'text', - 'class': 'value text' - }); - $coverDiv.append($elementValue); - }; - - var appendCoverDivToParent = function() { - if ( $('.generatedForm').length ) { - if ($elem.parent().hasClass('generated')) { - if ( $elem.parent().parent().next('.level-'+String(level)).length ) { - $elem.parent().parent().next('.level-'+String(level)).append($coverDiv); - } else { - $elem.parent().parent().after($("
      ").addClass('level-' + String(level)).addClass('generated').append($coverDiv)); - } - } else { - if ( $form.children('.level-'+String(level)).length ) { - $form.children('.level-'+String(level)).append($coverDiv); - } else { - $currentParent.append($("
      ").addClass('level-' + String(level)).addClass('generated').append($coverDiv)); - } - } - } else { - // create hidden input with path to the duplicated node - var $elementWithParentXpath = $("") - .attr({ - type: 'hidden', - name: "newNodeForm[parent]", - value: xPath - }); - $form.prepend($elementWithParentXpath); - - - $form.append($("
      ").addClass('level-' + String(level)).addClass('generated').append($coverDiv)); - - $elem.parents('.leaf-line').addClass('active'); - $form.insertAfter($currentParent); - } - - // we have to modify xpath and rel attributes for generated icons and inputs - var $originalInput = $coverDiv.find('input.value, input.label'); - var newIndex = getNewIndex($coverDiv); - - modifyInputXPath($originalInput, $coverDiv, newIndex); - }; - - var removeEditBarIcons = function($editBar, $newEditBar, labelAttributes) { - // if is editBar available, replace whole HTML - if ($newEditBar.length) { - if (!$newEditBar.find('.create-child').length) { - $editBar.find('.create-child').remove(); - } - - // leave only remove edit bar action - } else { - $editBar.find('img:not(.remove-child)').remove(); - } - - if (labelAttributes !== undefined && labelAttributes.mandatory !== undefined && labelAttributes.mandatory == "true") { - $editBar.find('.remove-child').remove(); - } - }; - - // input for label name - var $elementName = $("") - .attr({ - name: 'newNodeForm[label' + uniqueId + '_' + xPath + ']', - type: 'text', - 'class': 'label', - 'data-unique-id': uniqueId, - 'data-original-xPath': xPath, - 'data-parrent-xPath': encodeURIComponent(parentXPath), - value: labelValue, - 'autocomplete': 'off' - }).typeahead({ - minLength: 0, - items: 9999, - autoSelect: false, - source: function(query, process) { - $.ajax({ - url: sourceUrl, - data: { - 'typed': query - }, - type: "GET", - dataType: "json", - success: function(data){ - process(data); - } - }) - }, - matcher: function(item) { - if (this.query == typeaheadALLconst) { - return true; - } else if (item.toLowerCase().indexOf(this.query.trim().toLowerCase()) != -1) { - return true; - } - return false; - } - }).change(function() { - var $currentInput = $(this); - - $("ul.typeahead.dropdown-menu").hide(); - $currentInput.blur(); - - $.ajax({ - url: sourceUrl, - data: { - 'label': $(this).val(), - 'command': 'attributesAndValueElem' - }, - type: "GET", - dataType: "json", - success: function(data){ - if (data !== false) { - if (data.labelAttributes !== undefined) { - refreshTooltipData($currentInput, data.labelAttributes); - } - - if (data.children !== false) { - $.each(data.children, function(name, childElem) { - var $icon = $editBar.find('.create-child'); - var $newCoverDiv = $("
      ").addClass('leaf-line').addClass('generated'); - createNodeElements($icon, $newCoverDiv, $form, name, childElem); - modifyAllInputsXPath($newCoverDiv); - }); - } - - // remove undefined icons in edit-bar - if (data.editBar !== undefined) { - var $newEditBar = $(data.editBar); - - removeEditBarIcons($editBar, $newEditBar, data.labelAttributes); - } - - // replace whole value element and change his name attr - if (data.valueElem !== undefined) { - // remove current value element - $currentInput.parents('.leaf-line').find("input.value, .config-value-cover").remove(); - - insertValueElement($currentInput, data.valueElem); - } - $currentInput.blur(); - $currentInput.typeahead('hide'); - $("ul.typeahead.dropdown-menu").remove(); - } - } - }); - }).on('focus', function() { - if ($(this).val() == "") { - $(this).val(typeaheadALLconst); - $(this).typeahead('lookup'); - $(this).val(''); - } - }); - $coverDiv.append($("").addClass('label').append($("").addClass('dots')).append($elementName)); - if (editBarAttributes !== false) removeEditBarIcons($editBar, $(editBarAttributes), labelAttributes); - - // append edit bar to cover - $editBar = bindEditBarModification($editBar, $form); - - $coverDiv.append($editBar); - - if (generatedInput !== false) { - insertValueElement($elementName, generatedInput); - } else { - createInputValue(); - } - appendCoverDivToParent(); - - // must be at the end because of right position compute - if (labelAttributes !== false) refreshTooltipData($elementName, labelAttributes); -} - -function reloadModalTreeDumpContent($cover, $form) { - if (!$(".model-tree-opener").length) { - var $modelOpener = $("", { - 'class': 'model-tree-opener', - html: 'Show model tree' - }).insertBefore($form.find('.close')); - $modelOpener.click(function() { - $("#modelTreeDump").toggle(50, function() { - var minusHeight; - if ($(this).is(":visible")) { - minusHeight = 0; - } else { - minusHeight = $("#modelTreeDump").outerHeight(); - } - recountFormUnderlayDimensions($cover, minusHeight); - }); - $(".model-tree-opener .toToggle").toggle(); - }); - } else { - $(".model-tree-opener").insertBefore($form.find('.close')); - } - $form.find("#modelTreeDump").html($("#hiddenModelTreeDump").html()).appendTo($form); -} - -function modifyInputXPath($inputs, $coverDiv, newIndex) { - $inputs.each(function(i,e) { - var s = $(e).attr('name'); - var newXpath = s.substring(0, s.length - 1) + '--*?' + newIndex + '!]'; - $(e).attr('name', newXpath); - }); - - var $labelInput = $coverDiv.find('input.label'); - var $editBarImg = $coverDiv.find('.edit-bar img'); - var newRel = $editBarImg.attr('rel'); - if ($labelInput.length) { - newRel = $labelInput.data('originalXpath'); - } - - $editBarImg.attr('rel', newRel + '--*?' + newIndex + '!'); -} - -function rewriteOriginalXPath($inputs, newXpath, newIndex) { - $inputs.each(function(i,e) { - var modifiedXPath = newXpath + '--*?' + newIndex + "!"; - $(e).data('originalXpath', modifiedXPath); - $(e).attr('data-original-xpath', modifiedXPath); - }); -} - -function bindEditBarModification($editBar, $form) { - // necessary edit bar modifications - bind all actions - $editBar.addClass('generated'); - $editBar.children("img.sibling, img.sort-item").remove(); - $editBar.children("img.remove-child").on('click', function() { - var confirmBox = confirm("Are you sure you want to delete this element and all his children? This can not be undone!"); - if (confirmBox) { - // remove all children and itself - $(this).parents(".leaf-line").nextAll("div[class*='level-']").remove(); - $(this).parents(".leaf-line").remove(); - } else { - return false; - } - - - modifyAllInputsXPath($form.find('.leaf-line'), true); - }); - $editBar.children("img.create-child").unbind('click').on('click', function() { - createNode($(this)); - }); - - return $editBar; -} - -function modifyAllInputsXPath($leafLines, forceRewriteOriginalXpath) { - $leafLines.each(function() { - var $inputs = $(this).find('input.value, input.label, input.hidden-input-value, select, input[type="radio"]'); - var $labelInput = $(this).find("input.label"); - var $valueInput = $(this).find("input.value, select, input[type='radio'], input.hidden-input-value"); - - var newIndex = getNewIndex($(this)); - - if (forceRewriteOriginalXpath != undefined && forceRewriteOriginalXpath == true) { - var $childrenLeafs = $(this).nextAll("div[class*='level-']").children('.leaf-line'); - rewriteOriginalXPath($childrenLeafs.find('input.label'), $labelInput.data('originalXpath'), newIndex); - modifyAllInputsXPath($childrenLeafs); - } - var newXpath = $labelInput.data('uniqueId') + '_' + $labelInput.data('originalXpath'); - - // recover original uniqueId and xPath and generate new input name - $labelInput.attr('name', 'newNodeForm[label' + newXpath + ']'); - $valueInput.attr('name', 'newNodeForm[value' + newXpath + ']'); - modifyInputXPath($inputs, $(this), newIndex); - }); -} - -function getNewIndex($line) { - var ind = $line.index(); - if ($line.hasClass('leaf-line')) { - ind -= $line.prevAll(":not('.leaf-line')").length; - } - var newIndex = ind + $line.siblings(".is-key").length; - if (newIndex < 1) newIndex = 0; - newIndex++; - return newIndex; -} diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/tooltip/gips.js b/src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/tooltip/gips.js deleted file mode 100644 index fd81384f..00000000 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/public/js/tooltip/gips.js +++ /dev/null @@ -1,71 +0,0 @@ -(function ($) { - $.fn.extend({ - gips: function (options) { - var settings = $.extend({ bottom: '30px', delay: 500, autoHide: false, pause: 5000, animationSpeed: 500, placement: 'top', theme: 'purple', imagePath: 'images/close.png', text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et.' }, options); - return this.each(function () { - var control = $(this); - var iconDirection = 'top'; - if (settings.placement == 'top') - iconDirection = 'bottom'; - if (settings.placement == 'bottom') - iconDirection = 'top'; - if (settings.placement == 'left') - iconDirection = 'right'; - if (settings.placement == 'right') - iconDirection = 'left'; - - var closebtn = ''; - if (!settings.autoHide) - closebtn = 'close'; - var toolTipContainer = $('
      ' + settings.text + '' + - '
      '); - - control.before(toolTipContainer); - var delay = settings.delay; - var toolTip = toolTipContainer; - toolTipHeight = toolTip.outerHeight(); - toolTip.css({display:'none'}).find('div').css({ display: 'none', opacity: 0 }); - var toolTipBody = $('.gips-body', toolTipContainer); - var toolTipIcon = $('.gips-icon', toolTipContainer); - var placement = settings.placement; - var interval; - control.mouseover(function () { - var left = $(this).position().left - parseInt(toolTipIcon.css('margin-left'), 10); - var bottom = settings.bottom; - - toolTipIcon.css('bottom', 0 - toolTipIcon.outerHeight()); - toolTip.css({ left: left, bottom: bottom }); - interval = setTimeout(function () { - showToolTip(toolTip); - }, delay); - }).mouseout(function () { - if (!settings.autoHide) { - clearTimeout(interval); - hideToolTip(toolTip); - } - }).keydown(function () { - clearTimeout(interval); - hideToolTip(toolTip); - }); - - function showToolTip(toolTip) { - //toolTip.fadeIn('slow'); - toolTip.css({ display: '' }).find('div').css('display', '').stop(false, true).animate({ opacity: 1 }, settings.animationSpeed, function () { - if (settings.autoHide) { - setTimeout(function () { - hideToolTip(toolTip); - }, settings.pause); - } - }); - } - function hideToolTip(toolTip) { - // toolTip.fadeOut('slow'); - toolTip.css({ display: 'none' }).find('div').stop(false, true).animate({ opacity: 0 }, settings.animationSpeed, function () { - $(this).css('display', 'none'); - }); - } - - }); - } - }); -})(jQuery); diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig b/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig index 3d80ed45..2093d463 100644 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/section.html.twig @@ -39,22 +39,6 @@ if advised of the possibility of such damage. {% extends 'FITModuleDefaultBundle::layout.html.twig' %} {% block title %}Section {% if sectionName is defined and not(sectionName is empty) %}- {{sectionName}}{% endif %}{% endblock title %} -{% block leftColumnAdditional %} - {% if (hideColumnControl is not defined) or (hideColumnControl is defined and hideColumnControl != true) %} -
      - {% endif %} -{% endblock leftColumnAdditional %} - {% set stateDefined = 'false' %} {% block htmlAdditions %} ng-app="NetopeerGUIApp"{% endblock %} diff --git a/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/showRPCForm.html.twig b/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/showRPCForm.html.twig index 4f6956e1..816c40ac 100644 --- a/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/showRPCForm.html.twig +++ b/src/FIT/Bundle/ModuleDefaultBundle/Resources/views/Module/showRPCForm.html.twig @@ -38,7 +38,7 @@ if advised of the possibility of such damage. {% block modalWindow %}