summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Cresswell <robert.cresswell@outlook.com>2016-05-10 15:01:42 +0100
committerRob Cresswell <robert.cresswell@outlook.com>2016-07-14 09:50:27 -0700
commit830746ff6d09fed0417ab488549604f36829d5b0 (patch)
treec663b9f7d874c1032680032682ea16269172768e
parente0fbf69fb156b995547471d71c5c6a7f88989d47 (diff)
downloadxstatic-angular-smart-table-830746ff6d09fed0417ab488549604f36829d5b0.tar.gz
Update Smart-Table to 1.4.131.4.13
This is the latest release for 1.x. Moving to this version for now, will investigate 2.x later Also adds several missing files so that the package is consistent with the other xstatic packages. Change-Id: Icaa3f5099beb66edc4e83feeb2a9d8e3315a8895
-rw-r--r--.gitignore9
-rw-r--r--.gitreview4
-rw-r--r--LICENSE21
-rw-r--r--MANIFEST.in3
-rw-r--r--PKG-INFO25
-rw-r--r--setup.cfg20
-rw-r--r--setup.py28
-rw-r--r--xstatic/pkg/angular_smart_table/__init__.py4
-rw-r--r--xstatic/pkg/angular_smart_table/data/smart-table.js826
9 files changed, 504 insertions, 436 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b3085b8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.pyc
+*.sw?
+*.sqlite3
+.DS_STORE
+*.egg-info
+.venv
+.tox
+build
+dist
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..b4f7935
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,4 @@
+[gerrit]
+host=review.openstack.org
+port=29418
+project=openstack/xstatic-angular-smart-table.git
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c46b9e6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+Copyright (C) 2014 Laurent Renard.
+
+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/MANIFEST.in b/MANIFEST.in
index c507fb4..af3cdd3 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,5 @@
include README.txt
-recursive-include xstatic/pkg/angular_smart_table *
-
+recursive-include xstatic *
global-exclude *.pyc
global-exclude *.pyo
global-exclude *.orig
diff --git a/PKG-INFO b/PKG-INFO
deleted file mode 100644
index 53e78b9..0000000
--- a/PKG-INFO
+++ /dev/null
@@ -1,25 +0,0 @@
-Metadata-Version: 1.0
-Name: XStatic-smart-table
-Version: 1.4.5.3
-Summary: smart-table 1.4.5 (XStatic packaging standard)
-Home-page: https://github.com/lorenzofox3/Smart-Table
-Author: Richard Jones
-Author-email: r1chardj0n3s@gmail.com
-License: (same as smart-table)
-Description:
- XStatic-smart-table
- -------------------
-
- smart-table javascript library packaged for setuptools (easy_install) / pip.
-
- This package is intended to be used by **any** project that needs these files.
-
- It intentionally does **not** provide any extra code except some metadata
- **nor** has any extra requirements. You MAY use some minimal support code from
- the XStatic base package, if you like.
-
- You can find more info about the xstatic packaging way in the package
- `XStatic`.
-
-Keywords: smart-table angular table angular_smart_table xstatic
-Platform: any
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..fe4580e
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,20 @@
+[metadata]
+name = XStatic-smart-table
+summary = smart-table 1.4.13 (XStatic packaging standard)
+description-file = README.rst
+maintainer = Richard Jones
+maintainer-email = r1chardj0n3s@gmail.com
+home-page = https://github.com/lorenzofox3/Smart-Table
+keywords = smart-table angular table angular_smart_table xstatic
+license = (same as smart-table)
+zip_safe = False
+namespace_packages =
+ xstatic
+ xstatic.pkg
+
+[files]
+packages =
+ xstatic
+
+[bdist_wheel]
+universal = True
diff --git a/setup.py b/setup.py
index d7ecd21..47062a9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,27 +1,17 @@
-
-from xstatic.pkg import angular_smart_table as xs
+from setuptools import setup, find_packages
# The README.txt file should be written in reST so that PyPI can use
# it to generate your project's PyPI page.
long_description = open('README.txt').read()
-from setuptools import setup, find_packages
-
setup(
- name=xs.PACKAGE_NAME,
- version=xs.PACKAGE_VERSION,
- description=xs.DESCRIPTION,
- long_description=long_description,
- classifiers=xs.CLASSIFIERS,
- keywords=xs.KEYWORDS,
- maintainer=xs.MAINTAINER,
- maintainer_email=xs.MAINTAINER_EMAIL,
- license=xs.LICENSE,
- url=xs.HOMEPAGE,
- platforms=xs.PLATFORMS,
+ name='XStatic-smart-table',
+ summary="""smart-table 1.4.13 (XStatic packaging standard)""",
+ description=long_description,
+ maintainer="Richard Jones",
+ maintainer_email='r1chardj0n3s@gmail.com',
+ use_scm_version=True,
+ setup_requires=['setuptools_scm', 'wheel'],
packages=find_packages(),
- namespace_packages=['xstatic', 'xstatic.pkg', ],
- include_package_data=True,
- zip_safe=False,
- install_requires=[],
+ include_package_data=True
)
diff --git a/xstatic/pkg/angular_smart_table/__init__.py b/xstatic/pkg/angular_smart_table/__init__.py
index 32aec65..fd0a5af 100644
--- a/xstatic/pkg/angular_smart_table/__init__.py
+++ b/xstatic/pkg/angular_smart_table/__init__.py
@@ -15,9 +15,9 @@ NAME = __name__.split('.')[-1] # package name (e.g. 'foo' or 'foo_bar')
# please use a all-lowercase valid python
# package name
-VERSION = '1.4.5' # version of the packaged files, please use the upstream
+VERSION = '1.4.13' # version of the packaged files, please use the upstream
# version number
-BUILD = '3' # our package build number, so we can release new builds
+BUILD = '0' # our package build number, so we can release new builds
# with fixes for xstatic stuff.
PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi
diff --git a/xstatic/pkg/angular_smart_table/data/smart-table.js b/xstatic/pkg/angular_smart_table/data/smart-table.js
index d5cd473..9faa7d4 100644
--- a/xstatic/pkg/angular_smart_table/data/smart-table.js
+++ b/xstatic/pkg/angular_smart_table/data/smart-table.js
@@ -1,5 +1,5 @@
/**
-* @version 1.4.5
+* @version 1.4.13
* @license MIT
*/
(function (ng, undefined){
@@ -7,416 +7,466 @@
ng.module('smart-table', []).run(['$templateCache', function ($templateCache) {
$templateCache.put('template/smart-table/pagination.html',
- '<div class="pagination" ng-if="pages.length >= 2"><ul class="pagination">' +
+ '<nav ng-if="pages.length >= 2"><ul class="pagination">' +
'<li ng-repeat="page in pages" ng-class="{active: page==currentPage}"><a ng-click="selectPage(page)">{{page}}</a></li>' +
- '</ul></div>');
+ '</ul></nav>');
}]);
ng.module('smart-table')
- .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController($scope, $parse, $filter, $attrs) {
- var propertyName = $attrs.stTable;
- var displayGetter = $parse(propertyName);
- var displaySetter = displayGetter.assign;
- var safeGetter;
- var orderBy = $filter('orderBy');
- var filter = $filter('filter');
- var safeCopy = copyRefs(displayGetter($scope));
- var tableState = {
- sort: {},
- search: {},
- pagination: {
- start: 0
- }
- };
- var pipeAfterSafeCopy = true;
- var ctrl = this;
- var lastSelected;
-
- function copyRefs(src) {
- return [].concat(src);
+ .constant('stConfig', {
+ pagination: {
+ template: 'template/smart-table/pagination.html',
+ itemsByPage: 10,
+ displayedPages: 5
+ },
+ search: {
+ delay: 400 // ms
+ },
+ select: {
+ mode: 'single',
+ selectedClass: 'st-selected'
+ },
+ sort: {
+ ascentClass: 'st-sort-ascent',
+ descentClass: 'st-sort-descent'
+ }
+ });
+ng.module('smart-table')
+ .controller('stTableController', ['$scope', '$parse', '$filter', '$attrs', function StTableController ($scope, $parse, $filter, $attrs) {
+ var propertyName = $attrs.stTable;
+ var displayGetter = $parse(propertyName);
+ var displaySetter = displayGetter.assign;
+ var safeGetter;
+ var orderBy = $filter('orderBy');
+ var filter = $filter('filter');
+ var safeCopy = copyRefs(displayGetter($scope));
+ var tableState = {
+ sort: {},
+ search: {},
+ pagination: {
+ start: 0
+ }
+ };
+ var filtered;
+ var pipeAfterSafeCopy = true;
+ var ctrl = this;
+ var lastSelected;
+
+ function copyRefs (src) {
+ return src ? [].concat(src) : [];
+ }
+
+ function updateSafeCopy () {
+ safeCopy = copyRefs(safeGetter($scope));
+ if (pipeAfterSafeCopy === true) {
+ ctrl.pipe();
+ }
+ }
+
+ if ($attrs.stSafeSrc) {
+ safeGetter = $parse($attrs.stSafeSrc);
+ $scope.$watch(function () {
+ var safeSrc = safeGetter($scope);
+ return safeSrc ? safeSrc.length : 0;
+
+ }, function (newValue, oldValue) {
+ if (newValue !== safeCopy.length) {
+ updateSafeCopy();
}
-
- function updateSafeCopy() {
- safeCopy = copyRefs(safeGetter($scope));
- if (pipeAfterSafeCopy === true) {
- ctrl.pipe();
- }
+ });
+ $scope.$watch(function () {
+ return safeGetter($scope);
+ }, function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ updateSafeCopy();
}
-
- if ($attrs.stSafeSrc) {
- safeGetter = $parse($attrs.stSafeSrc);
- $scope.$watch(function () {
- var safeSrc = safeGetter($scope);
- return safeSrc ? safeSrc.length : 0;
-
- }, function (newValue, oldValue) {
- if (newValue !== safeCopy.length) {
- updateSafeCopy();
- }
- });
- $scope.$watch(function () {
- return safeGetter($scope);
- }, function (newValue, oldValue) {
- if (newValue !== oldValue) {
- updateSafeCopy();
- }
- });
+ });
+ }
+
+ /**
+ * sort the rows
+ * @param {Function | String} predicate - function or string which will be used as predicate for the sorting
+ * @param [reverse] - if you want to reverse the order
+ */
+ this.sortBy = function sortBy (predicate, reverse) {
+ tableState.sort.predicate = predicate;
+ tableState.sort.reverse = reverse === true;
+
+ if (ng.isFunction(predicate)) {
+ tableState.sort.functionName = predicate.name;
+ } else {
+ delete tableState.sort.functionName;
+ }
+
+ tableState.pagination.start = 0;
+ return this.pipe();
+ };
+
+ /**
+ * search matching rows
+ * @param {String} input - the input string
+ * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties
+ */
+ this.search = function search (input, predicate) {
+ var predicateObject = tableState.search.predicateObject || {};
+ var prop = predicate ? predicate : '$';
+
+ input = ng.isString(input) ? input.trim() : input;
+ predicateObject[prop] = input;
+ // to avoid to filter out null value
+ if (!input) {
+ delete predicateObject[prop];
+ }
+ tableState.search.predicateObject = predicateObject;
+ tableState.pagination.start = 0;
+ return this.pipe();
+ };
+
+ /**
+ * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect)
+ */
+ this.pipe = function pipe () {
+ var pagination = tableState.pagination;
+ var output;
+ filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy;
+ if (tableState.sort.predicate) {
+ filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse);
+ }
+ if (pagination.number !== undefined) {
+ pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1;
+ pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start;
+ output = filtered.slice(pagination.start, pagination.start + parseInt(pagination.number));
+ }
+ displaySetter($scope, output || filtered);
+ };
+
+ /**
+ * select a dataRow (it will add the attribute isSelected to the row object)
+ * @param {Object} row - the row to select
+ * @param {String} [mode] - "single" or "multiple" (multiple by default)
+ */
+ this.select = function select (row, mode) {
+ var rows = safeCopy;
+ var index = rows.indexOf(row);
+ if (index !== -1) {
+ if (mode === 'single') {
+ row.isSelected = row.isSelected !== true;
+ if (lastSelected) {
+ lastSelected.isSelected = false;
+ }
+ lastSelected = row.isSelected === true ? row : undefined;
+ } else {
+ rows[index].isSelected = !rows[index].isSelected;
+ }
+ }
+ };
+
+ /**
+ * take a slice of the current sorted/filtered collection (pagination)
+ *
+ * @param {Number} start - start index of the slice
+ * @param {Number} number - the number of item in the slice
+ */
+ this.slice = function splice (start, number) {
+ tableState.pagination.start = start;
+ tableState.pagination.number = number;
+ return this.pipe();
+ };
+
+ /**
+ * return the current state of the table
+ * @returns {{sort: {}, search: {}, pagination: {start: number}}}
+ */
+ this.tableState = function getTableState () {
+ return tableState;
+ };
+
+ this.getFilteredCollection = function getFilteredCollection () {
+ return filtered || safeCopy;
+ };
+
+ /**
+ * Use a different filter function than the angular FilterFilter
+ * @param filterName the name under which the custom filter is registered
+ */
+ this.setFilterFunction = function setFilterFunction (filterName) {
+ filter = $filter(filterName);
+ };
+
+ /**
+ * Use a different function than the angular orderBy
+ * @param sortFunctionName the name under which the custom order function is registered
+ */
+ this.setSortFunction = function setSortFunction (sortFunctionName) {
+ orderBy = $filter(sortFunctionName);
+ };
+
+ /**
+ * Usually when the safe copy is updated the pipe function is called.
+ * Calling this method will prevent it, which is something required when using a custom pipe function
+ */
+ this.preventPipeOnWatch = function preventPipe () {
+ pipeAfterSafeCopy = false;
+ };
+ }])
+ .directive('stTable', function () {
+ return {
+ restrict: 'A',
+ controller: 'stTableController',
+ link: function (scope, element, attr, ctrl) {
+
+ if (attr.stSetFilter) {
+ ctrl.setFilterFunction(attr.stSetFilter);
}
- /**
- * sort the rows
- * @param {Function | String} predicate - function or string which will be used as predicate for the sorting
- * @param [reverse] - if you want to reverse the order
- */
- this.sortBy = function sortBy(predicate, reverse) {
- tableState.sort.predicate = predicate;
- tableState.sort.reverse = reverse === true;
- tableState.pagination.start = 0;
- return this.pipe();
- };
-
- /**
- * search matching rows
- * @param {String} input - the input string
- * @param {String} [predicate] - the property name against you want to check the match, otherwise it will search on all properties
- */
- this.search = function search(input, predicate) {
- var predicateObject = tableState.search.predicateObject || {};
- var prop = predicate ? predicate : '$';
- predicateObject[prop] = input;
- // to avoid to filter out null value
- if (!input) {
- delete predicateObject[prop];
- }
- tableState.search.predicateObject = predicateObject;
- tableState.pagination.start = 0;
- return this.pipe();
- };
+ if (attr.stSetSort) {
+ ctrl.setSortFunction(attr.stSetSort);
+ }
+ }
+ };
+ });
- /**
- * this will chain the operations of sorting and filtering based on the current table state (sort options, filtering, ect)
- */
- this.pipe = function pipe() {
- var pagination = tableState.pagination;
- var filtered = tableState.search.predicateObject ? filter(safeCopy, tableState.search.predicateObject) : safeCopy;
- if (tableState.sort.predicate) {
- filtered = orderBy(filtered, tableState.sort.predicate, tableState.sort.reverse);
- }
- if (pagination.number !== undefined) {
- pagination.numberOfPages = filtered.length > 0 ? Math.ceil(filtered.length / pagination.number) : 1;
- pagination.start = pagination.start >= filtered.length ? (pagination.numberOfPages - 1) * pagination.number : pagination.start;
- filtered = filtered.slice(pagination.start, pagination.start + pagination.number);
- }
- displaySetter($scope, filtered);
- };
+ng.module('smart-table')
+ .directive('stSearch', ['stConfig', '$timeout', function (stConfig, $timeout) {
+ return {
+ require: '^stTable',
+ scope: {
+ predicate: '=?stSearch'
+ },
+ link: function (scope, element, attr, ctrl) {
+ var tableCtrl = ctrl;
+ var promise = null;
+ var throttle = attr.stDelay || stConfig.search.delay;
+
+ scope.$watch('predicate', function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ ctrl.tableState().search = {};
+ tableCtrl.search(element[0].value || '', newValue);
+ }
+ });
+
+ //table state -> view
+ scope.$watch(function () {
+ return ctrl.tableState().search;
+ }, function (newValue, oldValue) {
+ var predicateExpression = scope.predicate || '$';
+ if (newValue.predicateObject && newValue.predicateObject[predicateExpression] !== element[0].value) {
+ element[0].value = newValue.predicateObject[predicateExpression] || '';
+ }
+ }, true);
+
+ // view -> table state
+ element.bind('input', function (evt) {
+ evt = evt.originalEvent || evt;
+ if (promise !== null) {
+ $timeout.cancel(promise);
+ }
+ promise = $timeout(function () {
+ tableCtrl.search(evt.target.value, scope.predicate || '');
+ promise = null;
+ }, throttle);
+ });
+ }
+ };
+ }]);
- /**
- * select a dataRow (it will add the attribute isSelected to the row object)
- * @param {Object} row - the row to select
- * @param {String} [mode] - "single" or "multiple" (multiple by default)
- */
- this.select = function select(row, mode) {
- var rows = safeCopy;
- var index = rows.indexOf(row);
- if (index !== -1) {
- if (mode === 'single') {
- row.isSelected = row.isSelected !== true;
- if (lastSelected) {
- lastSelected.isSelected = false;
- }
- lastSelected = row.isSelected === true ? row : undefined;
- } else {
- rows[index].isSelected = !rows[index].isSelected;
- }
- }
- };
+ng.module('smart-table')
+ .directive('stSelectRow', ['stConfig', function (stConfig) {
+ return {
+ restrict: 'A',
+ require: '^stTable',
+ scope: {
+ row: '=stSelectRow'
+ },
+ link: function (scope, element, attr, ctrl) {
+ var mode = attr.stSelectMode || stConfig.select.mode;
+ element.bind('click', function () {
+ scope.$apply(function () {
+ ctrl.select(scope.row, mode);
+ });
+ });
+
+ scope.$watch('row.isSelected', function (newValue) {
+ if (newValue === true) {
+ element.addClass(stConfig.select.selectedClass);
+ } else {
+ element.removeClass(stConfig.select.selectedClass);
+ }
+ });
+ }
+ };
+ }]);
- /**
- * take a slice of the current sorted/filtered collection (pagination)
- *
- * @param {Number} start - start index of the slice
- * @param {Number} number - the number of item in the slice
- */
- this.slice = function splice(start, number) {
- tableState.pagination.start = start;
- tableState.pagination.number = number;
- return this.pipe();
- };
+ng.module('smart-table')
+ .directive('stSort', ['stConfig', '$parse', function (stConfig, $parse) {
+ return {
+ restrict: 'A',
+ require: '^stTable',
+ link: function (scope, element, attr, ctrl) {
+
+ var predicate = attr.stSort;
+ var getter = $parse(predicate);
+ var index = 0;
+ var classAscent = attr.stClassAscent || stConfig.sort.ascentClass;
+ var classDescent = attr.stClassDescent || stConfig.sort.descentClass;
+ var stateClasses = [classAscent, classDescent];
+ var sortDefault;
+
+ if (attr.stSortDefault) {
+ sortDefault = scope.$eval(attr.stSortDefault) !== undefined ? scope.$eval(attr.stSortDefault) : attr.stSortDefault;
+ }
- /**
- * return the current state of the table
- * @returns {{sort: {}, search: {}, pagination: {start: number}}}
- */
- this.tableState = function getTableState() {
- return tableState;
- };
+ //view --> table state
+ function sort () {
+ index++;
+ predicate = ng.isFunction(getter(scope)) ? getter(scope) : attr.stSort;
+ if (index % 3 === 0 && attr.stSkipNatural === undefined) {
+ //manual reset
+ index = 0;
+ ctrl.tableState().sort = {};
+ ctrl.tableState().pagination.start = 0;
+ ctrl.pipe();
+ } else {
+ ctrl.sortBy(predicate, index % 2 === 0);
+ }
+ }
- /**
- * Use a different filter function than the angular FilterFilter
- * @param filterName the name under which the custom filter is registered
- */
- this.setFilterFunction = function setFilterFunction(filterName) {
- filter = $filter(filterName);
- };
+ element.bind('click', function sortClick () {
+ if (predicate) {
+ scope.$apply(sort);
+ }
+ });
- /**
- *User a different function than the angular orderBy
- * @param sortFunctionName the name under which the custom order function is registered
- */
- this.setSortFunction = function setSortFunction(sortFunctionName) {
- orderBy = $filter(sortFunctionName);
- };
+ if (sortDefault) {
+ index = sortDefault === 'reverse' ? 1 : 0;
+ sort();
+ }
- /**
- * Usually when the safe copy is updated the pipe function is called.
- * Calling this method will prevent it, which is something required when using a custom pipe function
- */
- this.preventPipeOnWatch = function preventPipe() {
- pipeAfterSafeCopy = false;
- };
- }])
- .directive('stTable', function () {
- return {
- restrict: 'A',
- controller: 'stTableController',
- link: function (scope, element, attr, ctrl) {
-
- if (attr.stSetFilter) {
- ctrl.setFilterFunction(attr.stSetFilter);
- }
-
- if (attr.stSetSort) {
- ctrl.setSortFunction(attr.stSetSort);
- }
- }
- };
- });
+ //table state --> view
+ scope.$watch(function () {
+ return ctrl.tableState().sort;
+ }, function (newValue) {
+ if (newValue.predicate !== predicate) {
+ index = 0;
+ element
+ .removeClass(classAscent)
+ .removeClass(classDescent);
+ } else {
+ index = newValue.reverse === true ? 2 : 1;
+ element
+ .removeClass(stateClasses[index % 2])
+ .addClass(stateClasses[index - 1]);
+ }
+ }, true);
+ }
+ };
+ }]);
ng.module('smart-table')
- .directive('stSearch', ['$timeout', function ($timeout) {
- return {
- require: '^stTable',
- scope: {
- predicate: '=?stSearch'
- },
- link: function (scope, element, attr, ctrl) {
- var tableCtrl = ctrl;
- var promise = null;
- var throttle = attr.stDelay || 400;
-
- scope.$watch('predicate', function (newValue, oldValue) {
- if (newValue !== oldValue) {
- ctrl.tableState().search = {};
- tableCtrl.search(element[0].value || '', newValue);
- }
- });
-
- //table state -> view
- scope.$watch(function () {
- return ctrl.tableState().search;
- }, function (newValue, oldValue) {
- var predicateExpression = scope.predicate || '$';
- if (newValue.predicateObject && newValue.predicateObject[predicateExpression] !== element[0].value) {
- element[0].value = newValue.predicateObject[predicateExpression] || '';
- }
- }, true);
-
- // view -> table state
- element.bind('input', function (evt) {
- evt = evt.originalEvent || evt;
- if (promise !== null) {
- $timeout.cancel(promise);
- }
- promise = $timeout(function () {
- tableCtrl.search(evt.target.value, scope.predicate || '');
- promise = null;
- }, throttle);
- });
- }
- };
- }]);
+ .directive('stPagination', ['stConfig', function (stConfig) {
+ return {
+ restrict: 'EA',
+ require: '^stTable',
+ scope: {
+ stItemsByPage: '=?',
+ stDisplayedPages: '=?',
+ stPageChange: '&'
+ },
+ templateUrl: function (element, attrs) {
+ if (attrs.stTemplate) {
+ return attrs.stTemplate;
+ }
+ return stConfig.pagination.template;
+ },
+ link: function (scope, element, attrs, ctrl) {
+
+ scope.stItemsByPage = scope.stItemsByPage ? +(scope.stItemsByPage) : stConfig.pagination.itemsByPage;
+ scope.stDisplayedPages = scope.stDisplayedPages ? +(scope.stDisplayedPages) : stConfig.pagination.displayedPages;
+
+ scope.currentPage = 1;
+ scope.pages = [];
+
+ function redraw () {
+ var paginationState = ctrl.tableState().pagination;
+ var start = 1;
+ var end;
+ var i;
+ var prevPage = scope.currentPage;
+ scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1;
+
+ start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2)));
+ end = start + scope.stDisplayedPages;
+
+ if (end > paginationState.numberOfPages) {
+ end = paginationState.numberOfPages + 1;
+ start = Math.max(1, end - scope.stDisplayedPages);
+ }
+
+ scope.pages = [];
+ scope.numPages = paginationState.numberOfPages;
+
+ for (i = start; i < end; i++) {
+ scope.pages.push(i);
+ }
+
+ if (prevPage !== scope.currentPage) {
+ scope.stPageChange({newPage: scope.currentPage});
+ }
+ }
-ng.module('smart-table')
- .directive('stSelectRow', function () {
- return {
- restrict: 'A',
- require: '^stTable',
- scope: {
- row: '=stSelectRow'
- },
- link: function (scope, element, attr, ctrl) {
- var mode = attr.stSelectMode || 'single';
- element.bind('click', function () {
- scope.$apply(function () {
- ctrl.select(scope.row, mode);
- });
- });
-
- scope.$watch('row.isSelected', function (newValue, oldValue) {
- if (newValue === true) {
- element.addClass('st-selected');
- } else {
- element.removeClass('st-selected');
- }
- });
- }
+ //table state --> view
+ scope.$watch(function () {
+ return ctrl.tableState().pagination;
+ }, redraw, true);
+
+ //scope --> table state (--> view)
+ scope.$watch('stItemsByPage', function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ scope.selectPage(1);
+ }
+ });
+
+ scope.$watch('stDisplayedPages', redraw);
+
+ //view -> table state
+ scope.selectPage = function (page) {
+ if (page > 0 && page <= scope.numPages) {
+ ctrl.slice((page - 1) * scope.stItemsByPage, scope.stItemsByPage);
+ }
};
- });
-ng.module('smart-table')
- .directive('stSort', ['$parse', function ($parse) {
- return {
- restrict: 'A',
- require: '^stTable',
- link: function (scope, element, attr, ctrl) {
-
- var predicate = attr.stSort;
- var getter = $parse(predicate);
- var index = 0;
- var classAscent = attr.stClassAscent || 'st-sort-ascent';
- var classDescent = attr.stClassDescent || 'st-sort-descent';
- var stateClasses = [classAscent, classDescent];
-
- //view --> table state
- function sort() {
- index++;
- if (index % 3 === 0 && attr.stSkipNatural === undefined) {
- //manual reset
- index = 0;
- ctrl.tableState().sort = {};
- ctrl.tableState().pagination.start = 0;
- ctrl.pipe();
- } else {
- ctrl.sortBy(predicate, index % 2 === 0);
- }
- }
-
- if (ng.isFunction(getter(scope))) {
- predicate = getter(scope);
- }
-
- element.bind('click', function sortClick() {
- if (predicate) {
- scope.$apply(sort);
- }
- });
-
- if (attr.stSortDefault !== undefined) {
- index = attr.stSortDefault === 'reverse' ? 1 : 0;
- sort();
- }
-
- //table state --> view
- scope.$watch(function () {
- return ctrl.tableState().sort;
- }, function (newValue) {
- if (newValue.predicate !== predicate) {
- index = 0;
- element
- .removeClass(classAscent)
- .removeClass(classDescent);
- } else {
- index = newValue.reverse === true ? 2 : 1;
- element
- .removeClass(stateClasses[index % 2])
- .addClass(stateClasses[index - 1]);
- }
- }, true);
- }
- };
- }]);
+ if (!ctrl.tableState().pagination.number) {
+ ctrl.slice(0, scope.stItemsByPage);
+ }
+ }
+ };
+ }]);
ng.module('smart-table')
- .directive('stPagination', function () {
- return {
- restrict: 'EA',
- require: '^stTable',
- scope: {
- stItemsByPage: '=?',
- stDisplayedPages: '=?'
- },
- templateUrl: function(element, attrs) {
- if (attrs.stTemplate) {
- return attrs.stTemplate;
- }
- return 'template/smart-table/pagination.html';
- },
- link: function (scope, element, attrs, ctrl) {
-
- scope.stItemsByPage = scope.stItemsByPage ? +(scope.stItemsByPage) : 10;
- scope.stDisplayedPages = scope.stDisplayedPages ? +(scope.stDisplayedPages) : 5;
-
- scope.currentPage = 1;
- scope.pages = [];
-
- function redraw() {
- var paginationState = ctrl.tableState().pagination;
- var start = 1;
- var end;
- var i;
- scope.currentPage = Math.floor(paginationState.start / paginationState.number) + 1;
-
- start = Math.max(start, scope.currentPage - Math.abs(Math.floor(scope.stDisplayedPages / 2)));
- end = start + scope.stDisplayedPages;
-
- if (end > paginationState.numberOfPages) {
- end = paginationState.numberOfPages + 1;
- start = Math.max(1, end - scope.stDisplayedPages);
- }
-
- scope.pages = [];
- scope.numPages = paginationState.numberOfPages;
-
- for (i = start; i < end; i++) {
- scope.pages.push(i);
- }
- }
-
- //table state --> view
- scope.$watch(function () {
- return ctrl.tableState().pagination;
- }, redraw, true);
-
- //scope --> table state (--> view)
- scope.$watch('stItemsByPage', function () {
- scope.selectPage(1);
- });
-
- scope.$watch('stDisplayedPages', redraw);
-
- //view -> table state
- scope.selectPage = function (page) {
- if (page > 0 && page <= scope.numPages) {
- ctrl.slice((page - 1) * scope.stItemsByPage, scope.stItemsByPage);
- }
- };
-
- //select the first page
- ctrl.slice(0, scope.stItemsByPage);
+ .directive('stPipe', function () {
+ return {
+ require: 'stTable',
+ scope: {
+ stPipe: '='
+ },
+ link: {
+
+ pre: function (scope, element, attrs, ctrl) {
+ if (ng.isFunction(scope.stPipe)) {
+ ctrl.preventPipeOnWatch();
+ ctrl.pipe = function () {
+ return scope.stPipe(ctrl.tableState(), ctrl);
}
- };
- });
+ }
+ },
-ng.module('smart-table')
- .directive('stPipe', function () {
- return {
- require: 'stTable',
- scope: {
- stPipe: '='
- },
- link: {
- pre: function (scope, element, attrs, ctrl) {
-
- if (ng.isFunction(scope.stPipe)) {
- ctrl.preventPipeOnWatch();
- ctrl.pipe = function () {
- return scope.stPipe(ctrl.tableState(), ctrl);
- }
- }
- }
- }
- };
- });
+ post: function (scope, element, attrs, ctrl) {
+ ctrl.pipe();
+ }
+ }
+ };
+ });
-})(angular); \ No newline at end of file
+})(angular);
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy90b3AudHh0Iiwic3JjL3NtYXJ0LXRhYmxlLm1vZHVsZS5qcyIsInNyYy9zdENvbmZpZy5qcyIsInNyYy9zdFRhYmxlLmpzIiwic3JjL3N0U2VhcmNoLmpzIiwic3JjL3N0U2VsZWN0Um93LmpzIiwic3JjL3N0U29ydC5qcyIsInNyYy9zdFBhZ2luYXRpb24uanMiLCJzcmMvc3RQaXBlLmpzIiwic3JjL2JvdHRvbS50eHQiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FDRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2xNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQzFCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDaEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUN4QkEiLCJmaWxlIjoic21hcnQtdGFibGUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gKG5nLCB1bmRlZmluZWQpe1xuICAgICd1c2Ugc3RyaWN0JztcbiIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnLCBbXSkucnVuKFsnJHRlbXBsYXRlQ2FjaGUnLCBmdW5jdGlvbiAoJHRlbXBsYXRlQ2FjaGUpIHtcbiAgICAkdGVtcGxhdGVDYWNoZS5wdXQoJ3RlbXBsYXRlL3NtYXJ0LXRhYmxlL3BhZ2luYXRpb24uaHRtbCcsXG4gICAgICAgICc8bmF2IG5nLWlmPVwicGFnZXMubGVuZ3RoID49IDJcIj48dWwgY2xhc3M9XCJwYWdpbmF0aW9uXCI+JyArXG4gICAgICAgICc8bGkgbmctcmVwZWF0PVwicGFnZSBpbiBwYWdlc1wiIG5nLWNsYXNzPVwie2FjdGl2ZTogcGFnZT09Y3VycmVudFBhZ2V9XCI+PGEgbmctY2xpY2s9XCJzZWxlY3RQYWdlKHBhZ2UpXCI+e3twYWdlfX08L2E+PC9saT4nICtcbiAgICAgICAgJzwvdWw+PC9uYXY+Jyk7XG59XSk7XG5cbiIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnKVxuICAuY29uc3RhbnQoJ3N0Q29uZmlnJywge1xuICAgIHBhZ2luYXRpb246IHtcbiAgICAgIHRlbXBsYXRlOiAndGVtcGxhdGUvc21hcnQtdGFibGUvcGFnaW5hdGlvbi5odG1sJyxcbiAgICAgIGl0ZW1zQnlQYWdlOiAxMCxcbiAgICAgIGRpc3BsYXllZFBhZ2VzOiA1XG4gICAgfSxcbiAgICBzZWFyY2g6IHtcbiAgICAgIGRlbGF5OiA0MDAgLy8gbXNcbiAgICB9LFxuICAgIHNlbGVjdDoge1xuICAgICAgbW9kZTogJ3NpbmdsZScsXG4gICAgICBzZWxlY3RlZENsYXNzOiAnc3Qtc2VsZWN0ZWQnXG4gICAgfSxcbiAgICBzb3J0OiB7XG4gICAgICBhc2NlbnRDbGFzczogJ3N0LXNvcnQtYXNjZW50JyxcbiAgICAgIGRlc2NlbnRDbGFzczogJ3N0LXNvcnQtZGVzY2VudCdcbiAgICB9XG4gIH0pOyIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnKVxuICAuY29udHJvbGxlcignc3RUYWJsZUNvbnRyb2xsZXInLCBbJyRzY29wZScsICckcGFyc2UnLCAnJGZpbHRlcicsICckYXR0cnMnLCBmdW5jdGlvbiBTdFRhYmxlQ29udHJvbGxlciAoJHNjb3BlLCAkcGFyc2UsICRmaWx0ZXIsICRhdHRycykge1xuICAgIHZhciBwcm9wZXJ0eU5hbWUgPSAkYXR0cnMuc3RUYWJsZTtcbiAgICB2YXIgZGlzcGxheUdldHRlciA9ICRwYXJzZShwcm9wZXJ0eU5hbWUpO1xuICAgIHZhciBkaXNwbGF5U2V0dGVyID0gZGlzcGxheUdldHRlci5hc3NpZ247XG4gICAgdmFyIHNhZmVHZXR0ZXI7XG4gICAgdmFyIG9yZGVyQnkgPSAkZmlsdGVyKCdvcmRlckJ5Jyk7XG4gICAgdmFyIGZpbHRlciA9ICRmaWx0ZXIoJ2ZpbHRlcicpO1xuICAgIHZhciBzYWZlQ29weSA9IGNvcHlSZWZzKGRpc3BsYXlHZXR0ZXIoJHNjb3BlKSk7XG4gICAgdmFyIHRhYmxlU3RhdGUgPSB7XG4gICAgICBzb3J0OiB7fSxcbiAgICAgIHNlYXJjaDoge30sXG4gICAgICBwYWdpbmF0aW9uOiB7XG4gICAgICAgIHN0YXJ0OiAwXG4gICAgICB9XG4gICAgfTtcbiAgICB2YXIgZmlsdGVyZWQ7XG4gICAgdmFyIHBpcGVBZnRlclNhZmVDb3B5ID0gdHJ1ZTtcbiAgICB2YXIgY3RybCA9IHRoaXM7XG4gICAgdmFyIGxhc3RTZWxlY3RlZDtcblxuICAgIGZ1bmN0aW9uIGNvcHlSZWZzIChzcmMpIHtcbiAgICAgIHJldHVybiBzcmMgPyBbXS5jb25jYXQoc3JjKSA6IFtdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHVwZGF0ZVNhZmVDb3B5ICgpIHtcbiAgICAgIHNhZmVDb3B5ID0gY29weVJlZnMoc2FmZUdldHRlcigkc2NvcGUpKTtcbiAgICAgIGlmIChwaXBlQWZ0ZXJTYWZlQ29weSA9PT0gdHJ1ZSkge1xuICAgICAgICBjdHJsLnBpcGUoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoJGF0dHJzLnN0U2FmZVNyYykge1xuICAgICAgc2FmZUdldHRlciA9ICRwYXJzZSgkYXR0cnMuc3RTYWZlU3JjKTtcbiAgICAgICRzY29wZS4kd2F0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2FmZVNyYyA9IHNhZmVHZXR0ZXIoJHNjb3BlKTtcbiAgICAgICAgcmV0dXJuIHNhZmVTcmMgPyBzYWZlU3JjLmxlbmd0aCA6IDA7XG5cbiAgICAgIH0sIGZ1bmN0aW9uIChuZXdWYWx1ZSwgb2xkVmFsdWUpIHtcbiAgICAgICAgaWYgKG5ld1ZhbHVlICE9PSBzYWZlQ29weS5sZW5ndGgpIHtcbiAgICAgICAgICB1cGRhdGVTYWZlQ29weSgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgICRzY29wZS4kd2F0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gc2FmZUdldHRlcigkc2NvcGUpO1xuICAgICAgfSwgZnVuY3Rpb24gKG5ld1ZhbHVlLCBvbGRWYWx1ZSkge1xuICAgICAgICBpZiAobmV3VmFsdWUgIT09IG9sZFZhbHVlKSB7XG4gICAgICAgICAgdXBkYXRlU2FmZUNvcHkoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogc29ydCB0aGUgcm93c1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb24gfCBTdHJpbmd9IHByZWRpY2F0ZSAtIGZ1bmN0aW9uIG9yIHN0cmluZyB3aGljaCB3aWxsIGJlIHVzZWQgYXMgcHJlZGljYXRlIGZvciB0aGUgc29ydGluZ1xuICAgICAqIEBwYXJhbSBbcmV2ZXJzZV0gLSBpZiB5b3Ugd2FudCB0byByZXZlcnNlIHRoZSBvcmRlclxuICAgICAqL1xuICAgIHRoaXMuc29ydEJ5ID0gZnVuY3Rpb24gc29ydEJ5IChwcmVkaWNhdGUsIHJldmVyc2UpIHtcbiAgICAgIHRhYmxlU3RhdGUuc29ydC5wcmVkaWNhdGUgPSBwcmVkaWNhdGU7XG4gICAgICB0YWJsZVN0YXRlLnNvcnQucmV2ZXJzZSA9IHJldmVyc2UgPT09IHRydWU7XG5cbiAgICAgIGlmIChuZy5pc0Z1bmN0aW9uKHByZWRpY2F0ZSkpIHtcbiAgICAgICAgdGFibGVTdGF0ZS5zb3J0LmZ1bmN0aW9uTmFtZSA9IHByZWRpY2F0ZS5uYW1lO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGVsZXRlIHRhYmxlU3RhdGUuc29ydC5mdW5jdGlvbk5hbWU7XG4gICAgICB9XG5cbiAgICAgIHRhYmxlU3RhdGUucGFnaW5hdGlvbi5zdGFydCA9IDA7XG4gICAgICByZXR1cm4gdGhpcy5waXBlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHNlYXJjaCBtYXRjaGluZyByb3dzXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IC0gdGhlIGlucHV0IHN0cmluZ1xuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBbcHJlZGljYXRlXSAtIHRoZSBwcm9wZXJ0eSBuYW1lIGFnYWluc3QgeW91IHdhbnQgdG8gY2hlY2sgdGhlIG1hdGNoLCBvdGhlcndpc2UgaXQgd2lsbCBzZWFyY2ggb24gYWxsIHByb3BlcnRpZXNcbiAgICAgKi9cbiAgICB0aGlzLnNlYXJjaCA9IGZ1bmN0aW9uIHNlYXJjaCAoaW5wdXQsIHByZWRpY2F0ZSkge1xuICAgICAgdmFyIHByZWRpY2F0ZU9iamVjdCA9IHRhYmxlU3RhdGUuc2VhcmNoLnByZWRpY2F0ZU9iamVjdCB8fCB7fTtcbiAgICAgIHZhciBwcm9wID0gcHJlZGljYXRlID8gcHJlZGljYXRlIDogJyQnO1xuXG4gICAgICBpbnB1dCA9IG5nLmlzU3RyaW5nKGlucHV0KSA/IGlucHV0LnRyaW0oKSA6IGlucHV0O1xuICAgICAgcHJlZGljYXRlT2JqZWN0W3Byb3BdID0gaW5wdXQ7XG4gICAgICAvLyB0byBhdm9pZCB0byBmaWx0ZXIgb3V0IG51bGwgdmFsdWVcbiAgICAgIGlmICghaW5wdXQpIHtcbiAgICAgICAgZGVsZXRlIHByZWRpY2F0ZU9iamVjdFtwcm9wXTtcbiAgICAgIH1cbiAgICAgIHRhYmxlU3RhdGUuc2VhcmNoLnByZWRpY2F0ZU9iamVjdCA9IHByZWRpY2F0ZU9iamVjdDtcbiAgICAgIHRhYmxlU3RhdGUucGFnaW5hdGlvbi5zdGFydCA9IDA7XG4gICAgICByZXR1cm4gdGhpcy5waXBlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHRoaXMgd2lsbCBjaGFpbiB0aGUgb3BlcmF0aW9ucyBvZiBzb3J0aW5nIGFuZCBmaWx0ZXJpbmcgYmFzZWQgb24gdGhlIGN1cnJlbnQgdGFibGUgc3RhdGUgKHNvcnQgb3B0aW9ucywgZmlsdGVyaW5nLCBlY3QpXG4gICAgICovXG4gICAgdGhpcy5waXBlID0gZnVuY3Rpb24gcGlwZSAoKSB7XG4gICAgICB2YXIgcGFnaW5hdGlvbiA9IHRhYmxlU3RhdGUucGFnaW5hdGlvbjtcbiAgICAgIHZhciBvdXRwdXQ7XG4gICAgICBmaWx0ZXJlZCA9IHRhYmxlU3RhdGUuc2VhcmNoLnByZWRpY2F0ZU9iamVjdCA/IGZpbHRlcihzYWZlQ29weSwgdGFibGVTdGF0ZS5zZWFyY2gucHJlZGljYXRlT2JqZWN0KSA6IHNhZmVDb3B5O1xuICAgICAgaWYgKHRhYmxlU3RhdGUuc29ydC5wcmVkaWNhdGUpIHtcbiAgICAgICAgZmlsdGVyZWQgPSBvcmRlckJ5KGZpbHRlcmVkLCB0YWJsZVN0YXRlLnNvcnQucHJlZGljYXRlLCB0YWJsZVN0YXRlLnNvcnQucmV2ZXJzZSk7XG4gICAgICB9XG4gICAgICBpZiAocGFnaW5hdGlvbi5udW1iZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBwYWdpbmF0aW9uLm51bWJlck9mUGFnZXMgPSBmaWx0ZXJlZC5sZW5ndGggPiAwID8gTWF0aC5jZWlsKGZpbHRlcmVkLmxlbmd0aCAvIHBhZ2luYXRpb24ubnVtYmVyKSA6IDE7XG4gICAgICAgIHBhZ2luYXRpb24uc3RhcnQgPSBwYWdpbmF0aW9uLnN0YXJ0ID49IGZpbHRlcmVkLmxlbmd0aCA/IChwYWdpbmF0aW9uLm51bWJlck9mUGFnZXMgLSAxKSAqIHBhZ2luYXRpb24ubnVtYmVyIDogcGFnaW5hdGlvbi5zdGFydDtcbiAgICAgICAgb3V0cHV0ID0gZmlsdGVyZWQuc2xpY2UocGFnaW5hdGlvbi5zdGFydCwgcGFnaW5hdGlvbi5zdGFydCArIHBhcnNlSW50KHBhZ2luYXRpb24ubnVtYmVyKSk7XG4gICAgICB9XG4gICAgICBkaXNwbGF5U2V0dGVyKCRzY29wZSwgb3V0cHV0IHx8IGZpbHRlcmVkKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogc2VsZWN0IGEgZGF0YVJvdyAoaXQgd2lsbCBhZGQgdGhlIGF0dHJpYnV0ZSBpc1NlbGVjdGVkIHRvIHRoZSByb3cgb2JqZWN0KVxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSByb3cgLSB0aGUgcm93IHRvIHNlbGVjdFxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBbbW9kZV0gLSBcInNpbmdsZVwiIG9yIFwibXVsdGlwbGVcIiAobXVsdGlwbGUgYnkgZGVmYXVsdClcbiAgICAgKi9cbiAgICB0aGlzLnNlbGVjdCA9IGZ1bmN0aW9uIHNlbGVjdCAocm93LCBtb2RlKSB7XG4gICAgICB2YXIgcm93cyA9IHNhZmVDb3B5O1xuICAgICAgdmFyIGluZGV4ID0gcm93cy5pbmRleE9mKHJvdyk7XG4gICAgICBpZiAoaW5kZXggIT09IC0xKSB7XG4gICAgICAgIGlmIChtb2RlID09PSAnc2luZ2xlJykge1xuICAgICAgICAgIHJvdy5pc1NlbGVjdGVkID0gcm93LmlzU2VsZWN0ZWQgIT09IHRydWU7XG4gICAgICAgICAgaWYgKGxhc3RTZWxlY3RlZCkge1xuICAgICAgICAgICAgbGFzdFNlbGVjdGVkLmlzU2VsZWN0ZWQgPSBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbGFzdFNlbGVjdGVkID0gcm93LmlzU2VsZWN0ZWQgPT09IHRydWUgPyByb3cgOiB1bmRlZmluZWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcm93c1tpbmRleF0uaXNTZWxlY3RlZCA9ICFyb3dzW2luZGV4XS5pc1NlbGVjdGVkO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIHRha2UgYSBzbGljZSBvZiB0aGUgY3VycmVudCBzb3J0ZWQvZmlsdGVyZWQgY29sbGVjdGlvbiAocGFnaW5hdGlvbilcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBzdGFydCAtIHN0YXJ0IGluZGV4IG9mIHRoZSBzbGljZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBudW1iZXIgLSB0aGUgbnVtYmVyIG9mIGl0ZW0gaW4gdGhlIHNsaWNlXG4gICAgICovXG4gICAgdGhpcy5zbGljZSA9IGZ1bmN0aW9uIHNwbGljZSAoc3RhcnQsIG51bWJlcikge1xuICAgICAgdGFibGVTdGF0ZS5wYWdpbmF0aW9uLnN0YXJ0ID0gc3RhcnQ7XG4gICAgICB0YWJsZVN0YXRlLnBhZ2luYXRpb24ubnVtYmVyID0gbnVtYmVyO1xuICAgICAgcmV0dXJuIHRoaXMucGlwZSgpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiByZXR1cm4gdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHRhYmxlXG4gICAgICogQHJldHVybnMge3tzb3J0OiB7fSwgc2VhcmNoOiB7fSwgcGFnaW5hdGlvbjoge3N0YXJ0OiBudW1iZXJ9fX1cbiAgICAgKi9cbiAgICB0aGlzLnRhYmxlU3RhdGUgPSBmdW5jdGlvbiBnZXRUYWJsZVN0YXRlICgpIHtcbiAgICAgIHJldHVybiB0YWJsZVN0YXRlO1xuICAgIH07XG5cbiAgICB0aGlzLmdldEZpbHRlcmVkQ29sbGVjdGlvbiA9IGZ1bmN0aW9uIGdldEZpbHRlcmVkQ29sbGVjdGlvbiAoKSB7XG4gICAgICByZXR1cm4gZmlsdGVyZWQgfHwgc2FmZUNvcHk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVzZSBhIGRpZmZlcmVudCBmaWx0ZXIgZnVuY3Rpb24gdGhhbiB0aGUgYW5ndWxhciBGaWx0ZXJGaWx0ZXJcbiAgICAgKiBAcGFyYW0gZmlsdGVyTmFtZSB0aGUgbmFtZSB1bmRlciB3aGljaCB0aGUgY3VzdG9tIGZpbHRlciBpcyByZWdpc3RlcmVkXG4gICAgICovXG4gICAgdGhpcy5zZXRGaWx0ZXJGdW5jdGlvbiA9IGZ1bmN0aW9uIHNldEZpbHRlckZ1bmN0aW9uIChmaWx0ZXJOYW1lKSB7XG4gICAgICBmaWx0ZXIgPSAkZmlsdGVyKGZpbHRlck5hbWUpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVc2UgYSBkaWZmZXJlbnQgZnVuY3Rpb24gdGhhbiB0aGUgYW5ndWxhciBvcmRlckJ5XG4gICAgICogQHBhcmFtIHNvcnRGdW5jdGlvbk5hbWUgdGhlIG5hbWUgdW5kZXIgd2hpY2ggdGhlIGN1c3RvbSBvcmRlciBmdW5jdGlvbiBpcyByZWdpc3RlcmVkXG4gICAgICovXG4gICAgdGhpcy5zZXRTb3J0RnVuY3Rpb24gPSBmdW5jdGlvbiBzZXRTb3J0RnVuY3Rpb24gKHNvcnRGdW5jdGlvbk5hbWUpIHtcbiAgICAgIG9yZGVyQnkgPSAkZmlsdGVyKHNvcnRGdW5jdGlvbk5hbWUpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVc3VhbGx5IHdoZW4gdGhlIHNhZmUgY29weSBpcyB1cGRhdGVkIHRoZSBwaXBlIGZ1bmN0aW9uIGlzIGNhbGxlZC5cbiAgICAgKiBDYWxsaW5nIHRoaXMgbWV0aG9kIHdpbGwgcHJldmVudCBpdCwgd2hpY2ggaXMgc29tZXRoaW5nIHJlcXVpcmVkIHdoZW4gdXNpbmcgYSBjdXN0b20gcGlwZSBmdW5jdGlvblxuICAgICAqL1xuICAgIHRoaXMucHJldmVudFBpcGVPbldhdGNoID0gZnVuY3Rpb24gcHJldmVudFBpcGUgKCkge1xuICAgICAgcGlwZUFmdGVyU2FmZUNvcHkgPSBmYWxzZTtcbiAgICB9O1xuICB9XSlcbiAgLmRpcmVjdGl2ZSgnc3RUYWJsZScsIGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcmVzdHJpY3Q6ICdBJyxcbiAgICAgIGNvbnRyb2xsZXI6ICdzdFRhYmxlQ29udHJvbGxlcicsXG4gICAgICBsaW5rOiBmdW5jdGlvbiAoc2NvcGUsIGVsZW1lbnQsIGF0dHIsIGN0cmwpIHtcblxuICAgICAgICBpZiAoYXR0ci5zdFNldEZpbHRlcikge1xuICAgICAgICAgIGN0cmwuc2V0RmlsdGVyRnVuY3Rpb24oYXR0ci5zdFNldEZpbHRlcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYXR0ci5zdFNldFNvcnQpIHtcbiAgICAgICAgICBjdHJsLnNldFNvcnRGdW5jdGlvbihhdHRyLnN0U2V0U29ydCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuICB9KTtcbiIsIm5nLm1vZHVsZSgnc21hcnQtdGFibGUnKVxuICAuZGlyZWN0aXZlKCdzdFNlYXJjaCcsIFsnc3RDb25maWcnLCAnJHRpbWVvdXQnLCBmdW5jdGlvbiAoc3RDb25maWcsICR0aW1lb3V0KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlcXVpcmU6ICdec3RUYWJsZScsXG4gICAgICBzY29wZToge1xuICAgICAgICBwcmVkaWNhdGU6ICc9P3N0U2VhcmNoJ1xuICAgICAgfSxcbiAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0ciwgY3RybCkge1xuICAgICAgICB2YXIgdGFibGVDdHJsID0gY3RybDtcbiAgICAgICAgdmFyIHByb21pc2UgPSBudWxsO1xuICAgICAgICB2YXIgdGhyb3R0bGUgPSBhdHRyLnN0RGVsYXkgfHwgc3RDb25maWcuc2VhcmNoLmRlbGF5O1xuXG4gICAgICAgIHNjb3BlLiR3YXRjaCgncHJlZGljYXRlJywgZnVuY3Rpb24gKG5ld1ZhbHVlLCBvbGRWYWx1ZSkge1xuICAgICAgICAgIGlmIChuZXdWYWx1ZSAhPT0gb2xkVmFsdWUpIHtcbiAgICAgICAgICAgIGN0cmwudGFibGVTdGF0ZSgpLnNlYXJjaCA9IHt9O1xuICAgICAgICAgICAgdGFibGVDdHJsLnNlYXJjaChlbGVtZW50WzBdLnZhbHVlIHx8ICcnLCBuZXdWYWx1ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvL3RhYmxlIHN0YXRlIC0+IHZpZXdcbiAgICAgICAgc2NvcGUuJHdhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gY3RybC50YWJsZVN0YXRlKCkuc2VhcmNoO1xuICAgICAgICB9LCBmdW5jdGlvbiAobmV3VmFsdWUsIG9sZFZhbHVlKSB7XG4gICAgICAgICAgdmFyIHByZWRpY2F0ZUV4cHJlc3Npb24gPSBzY29wZS5wcmVkaWNhdGUgfHwgJyQnO1xuICAgICAgICAgIGlmIChuZXdWYWx1ZS5wcmVkaWNhdGVPYmplY3QgJiYgbmV3VmFsdWUucHJlZGljYXRlT2JqZWN0W3ByZWRpY2F0ZUV4cHJlc3Npb25dICE9PSBlbGVtZW50WzBdLnZhbHVlKSB7XG4gICAgICAgICAgICBlbGVtZW50WzBdLnZhbHVlID0gbmV3VmFsdWUucHJlZGljYXRlT2JqZWN0W3ByZWRpY2F0ZUV4cHJlc3Npb25dIHx8ICcnO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgdHJ1ZSk7XG5cbiAgICAgICAgLy8gdmlldyAtPiB0YWJsZSBzdGF0ZVxuICAgICAgICBlbGVtZW50LmJpbmQoJ2lucHV0JywgZnVuY3Rpb24gKGV2dCkge1xuICAgICAgICAgIGV2dCA9IGV2dC5vcmlnaW5hbEV2ZW50IHx8IGV2dDtcbiAgICAgICAgICBpZiAocHJvbWlzZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgJHRpbWVvdXQuY2FuY2VsKHByb21pc2UpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBwcm9taXNlID0gJHRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGFibGVDdHJsLnNlYXJjaChldnQudGFyZ2V0LnZhbHVlLCBzY29wZS5wcmVkaWNhdGUgfHwgJycpO1xuICAgICAgICAgICAgcHJvbWlzZSA9IG51bGw7XG4gICAgICAgICAgfSwgdGhyb3R0bGUpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICB9XSk7XG4iLCJuZy5tb2R1bGUoJ3NtYXJ0LXRhYmxlJylcbiAgLmRpcmVjdGl2ZSgnc3RTZWxlY3RSb3cnLCBbJ3N0Q29uZmlnJywgZnVuY3Rpb24gKHN0Q29uZmlnKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlc3RyaWN0OiAnQScsXG4gICAgICByZXF1aXJlOiAnXnN0VGFibGUnLFxuICAgICAgc2NvcGU6IHtcbiAgICAgICAgcm93OiAnPXN0U2VsZWN0Um93J1xuICAgICAgfSxcbiAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0ciwgY3RybCkge1xuICAgICAgICB2YXIgbW9kZSA9IGF0dHIuc3RTZWxlY3RNb2RlIHx8IHN0Q29uZmlnLnNlbGVjdC5tb2RlO1xuICAgICAgICBlbGVtZW50LmJpbmQoJ2NsaWNrJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHNjb3BlLiRhcHBseShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjdHJsLnNlbGVjdChzY29wZS5yb3csIG1vZGUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICBzY29wZS4kd2F0Y2goJ3Jvdy5pc1NlbGVjdGVkJywgZnVuY3Rpb24gKG5ld1ZhbHVlKSB7XG4gICAgICAgICAgaWYgKG5ld1ZhbHVlID09PSB0cnVlKSB7XG4gICAgICAgICAgICBlbGVtZW50LmFkZENsYXNzKHN0Q29uZmlnLnNlbGVjdC5zZWxlY3RlZENsYXNzKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZWxlbWVudC5yZW1vdmVDbGFzcyhzdENvbmZpZy5zZWxlY3Quc2VsZWN0ZWRDbGFzcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICB9XSk7XG4iLCJuZy5tb2R1bGUoJ3NtYXJ0LXRhYmxlJylcbiAgLmRpcmVjdGl2ZSgnc3RTb3J0JywgWydzdENvbmZpZycsICckcGFyc2UnLCBmdW5jdGlvbiAoc3RDb25maWcsICRwYXJzZSkge1xuICAgIHJldHVybiB7XG4gICAgICByZXN0cmljdDogJ0EnLFxuICAgICAgcmVxdWlyZTogJ15zdFRhYmxlJyxcbiAgICAgIGxpbms6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0ciwgY3RybCkge1xuXG4gICAgICAgIHZhciBwcmVkaWNhdGUgPSBhdHRyLnN0U29ydDtcbiAgICAgICAgdmFyIGdldHRlciA9ICRwYXJzZShwcmVkaWNhdGUpO1xuICAgICAgICB2YXIgaW5kZXggPSAwO1xuICAgICAgICB2YXIgY2xhc3NBc2NlbnQgPSBhdHRyLnN0Q2xhc3NBc2NlbnQgfHwgc3RDb25maWcuc29ydC5hc2NlbnRDbGFzcztcbiAgICAgICAgdmFyIGNsYXNzRGVzY2VudCA9IGF0dHIuc3RDbGFzc0Rlc2NlbnQgfHwgc3RDb25maWcuc29ydC5kZXNjZW50Q2xhc3M7XG4gICAgICAgIHZhciBzdGF0ZUNsYXNzZXMgPSBbY2xhc3NBc2NlbnQsIGNsYXNzRGVzY2VudF07XG4gICAgICAgIHZhciBzb3J0RGVmYXVsdDtcblxuICAgICAgICBpZiAoYXR0ci5zdFNvcnREZWZhdWx0KSB7XG4gICAgICAgICAgc29ydERlZmF1bHQgPSBzY29wZS4kZXZhbChhdHRyLnN0U29ydERlZmF1bHQpICE9PSB1bmRlZmluZWQgPyBzY29wZS4kZXZhbChhdHRyLnN0U29ydERlZmF1bHQpIDogYXR0ci5zdFNvcnREZWZhdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgLy92aWV3IC0tPiB0YWJsZSBzdGF0ZVxuICAgICAgICBmdW5jdGlvbiBzb3J0ICgpIHtcbiAgICAgICAgICBpbmRleCsrO1xuICAgICAgICAgIHByZWRpY2F0ZSA9IG5nLmlzRnVuY3Rpb24oZ2V0dGVyKHNjb3BlKSkgPyBnZXR0ZXIoc2NvcGUpIDogYXR0ci5zdFNvcnQ7XG4gICAgICAgICAgaWYgKGluZGV4ICUgMyA9PT0gMCAmJiBhdHRyLnN0U2tpcE5hdHVyYWwgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy9tYW51YWwgcmVzZXRcbiAgICAgICAgICAgIGluZGV4ID0gMDtcbiAgICAgICAgICAgIGN0cmwudGFibGVTdGF0ZSgpLnNvcnQgPSB7fTtcbiAgICAgICAgICAgIGN0cmwudGFibGVTdGF0ZSgpLnBhZ2luYXRpb24uc3RhcnQgPSAwO1xuICAgICAgICAgICAgY3RybC5waXBlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGN0cmwuc29ydEJ5KHByZWRpY2F0ZSwgaW5kZXggJSAyID09PSAwKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBlbGVtZW50LmJpbmQoJ2NsaWNrJywgZnVuY3Rpb24gc29ydENsaWNrICgpIHtcbiAgICAgICAgICBpZiAocHJlZGljYXRlKSB7XG4gICAgICAgICAgICBzY29wZS4kYXBwbHkoc29ydCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoc29ydERlZmF1bHQpIHtcbiAgICAgICAgICBpbmRleCA9IHNvcnREZWZhdWx0ID09PSAncmV2ZXJzZScgPyAxIDogMDtcbiAgICAgICAgICBzb3J0KCk7XG4gICAgICAgIH1cblxuICAgICAgICAvL3RhYmxlIHN0YXRlIC0tPiB2aWV3XG4gICAgICAgIHNjb3BlLiR3YXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgcmV0dXJuIGN0cmwudGFibGVTdGF0ZSgpLnNvcnQ7XG4gICAgICAgIH0sIGZ1bmN0aW9uIChuZXdWYWx1ZSkge1xuICAgICAgICAgIGlmIChuZXdWYWx1ZS5wcmVkaWNhdGUgIT09IHByZWRpY2F0ZSkge1xuICAgICAgICAgICAgaW5kZXggPSAwO1xuICAgICAgICAgICAgZWxlbWVudFxuICAgICAgICAgICAgICAucmVtb3ZlQ2xhc3MoY2xhc3NBc2NlbnQpXG4gICAgICAgICAgICAgIC5yZW1vdmVDbGFzcyhjbGFzc0Rlc2NlbnQpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpbmRleCA9IG5ld1ZhbHVlLnJldmVyc2UgPT09IHRydWUgPyAyIDogMTtcbiAgICAgICAgICAgIGVsZW1lbnRcbiAgICAgICAgICAgICAgLnJlbW92ZUNsYXNzKHN0YXRlQ2xhc3Nlc1tpbmRleCAlIDJdKVxuICAgICAgICAgICAgICAuYWRkQ2xhc3Moc3RhdGVDbGFzc2VzW2luZGV4IC0gMV0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgdHJ1ZSk7XG4gICAgICB9XG4gICAgfTtcbiAgfV0pO1xuIiwibmcubW9kdWxlKCdzbWFydC10YWJsZScpXG4gIC5kaXJlY3RpdmUoJ3N0UGFnaW5hdGlvbicsIFsnc3RDb25maWcnLCBmdW5jdGlvbiAoc3RDb25maWcpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcmVzdHJpY3Q6ICdFQScsXG4gICAgICByZXF1aXJlOiAnXnN0VGFibGUnLFxuICAgICAgc2NvcGU6IHtcbiAgICAgICAgc3RJdGVtc0J5UGFnZTogJz0/JyxcbiAgICAgICAgc3REaXNwbGF5ZWRQYWdlczogJz0/JyxcbiAgICAgICAgc3RQYWdlQ2hhbmdlOiAnJidcbiAgICAgIH0sXG4gICAgICB0ZW1wbGF0ZVVybDogZnVuY3Rpb24gKGVsZW1lbnQsIGF0dHJzKSB7XG4gICAgICAgIGlmIChhdHRycy5zdFRlbXBsYXRlKSB7XG4gICAgICAgICAgcmV0dXJuIGF0dHJzLnN0VGVtcGxhdGU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0Q29uZmlnLnBhZ2luYXRpb24udGVtcGxhdGU7XG4gICAgICB9LFxuICAgICAgbGluazogZnVuY3Rpb24gKHNjb3BlLCBlbGVtZW50LCBhdHRycywgY3RybCkge1xuXG4gICAgICAgIHNjb3BlLnN0SXRlbXNCeVBhZ2UgPSBzY29wZS5zdEl0ZW1zQnlQYWdlID8gKyhzY29wZS5zdEl0ZW1zQnlQYWdlKSA6IHN0Q29uZmlnLnBhZ2luYXRpb24uaXRlbXNCeVBhZ2U7XG4gICAgICAgIHNjb3BlLnN0RGlzcGxheWVkUGFnZXMgPSBzY29wZS5zdERpc3BsYXllZFBhZ2VzID8gKyhzY29wZS5zdERpc3BsYXllZFBhZ2VzKSA6IHN0Q29uZmlnLnBhZ2luYXRpb24uZGlzcGxheWVkUGFnZXM7XG5cbiAgICAgICAgc2NvcGUuY3VycmVudFBhZ2UgPSAxO1xuICAgICAgICBzY29wZS5wYWdlcyA9IFtdO1xuXG4gICAgICAgIGZ1bmN0aW9uIHJlZHJhdyAoKSB7XG4gICAgICAgICAgdmFyIHBhZ2luYXRpb25TdGF0ZSA9IGN0cmwudGFibGVTdGF0ZSgpLnBhZ2luYXRpb247XG4gICAgICAgICAgdmFyIHN0YXJ0ID0gMTtcbiAgICAgICAgICB2YXIgZW5kO1xuICAgICAgICAgIHZhciBpO1xuICAgICAgICAgIHZhciBwcmV2UGFnZSA9IHNjb3BlLmN1cnJlbnRQYWdlO1xuICAgICAgICAgIHNjb3BlLmN1cnJlbnRQYWdlID0gTWF0aC5mbG9vcihwYWdpbmF0aW9uU3RhdGUuc3RhcnQgLyBwYWdpbmF0aW9uU3RhdGUubnVtYmVyKSArIDE7XG5cbiAgICAgICAgICBzdGFydCA9IE1hdGgubWF4KHN0YXJ0LCBzY29wZS5jdXJyZW50UGFnZSAtIE1hdGguYWJzKE1hdGguZmxvb3Ioc2NvcGUuc3REaXNwbGF5ZWRQYWdlcyAvIDIpKSk7XG4gICAgICAgICAgZW5kID0gc3RhcnQgKyBzY29wZS5zdERpc3BsYXllZFBhZ2VzO1xuXG4gICAgICAgICAgaWYgKGVuZCA+IHBhZ2luYXRpb25TdGF0ZS5udW1iZXJPZlBhZ2VzKSB7XG4gICAgICAgICAgICBlbmQgPSBwYWdpbmF0aW9uU3RhdGUubnVtYmVyT2ZQYWdlcyArIDE7XG4gICAgICAgICAgICBzdGFydCA9IE1hdGgubWF4KDEsIGVuZCAtIHNjb3BlLnN0RGlzcGxheWVkUGFnZXMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHNjb3BlLnBhZ2VzID0gW107XG4gICAgICAgICAgc2NvcGUubnVtUGFnZXMgPSBwYWdpbmF0aW9uU3RhdGUubnVtYmVyT2ZQYWdlcztcblxuICAgICAgICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyBpKyspIHtcbiAgICAgICAgICAgIHNjb3BlLnBhZ2VzLnB1c2goaSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHByZXZQYWdlICE9PSBzY29wZS5jdXJyZW50UGFnZSkge1xuICAgICAgICAgICAgc2NvcGUuc3RQYWdlQ2hhbmdlKHtuZXdQYWdlOiBzY29wZS5jdXJyZW50UGFnZX0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vdGFibGUgc3RhdGUgLS0+IHZpZXdcbiAgICAgICAgc2NvcGUuJHdhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICByZXR1cm4gY3RybC50YWJsZVN0YXRlKCkucGFnaW5hdGlvbjtcbiAgICAgICAgfSwgcmVkcmF3LCB0cnVlKTtcblxuICAgICAgICAvL3Njb3BlIC0tPiB0YWJsZSBzdGF0ZSAgKC0tPiB2aWV3KVxuICAgICAgICBzY29wZS4kd2F0Y2goJ3N0SXRlbXNCeVBhZ2UnLCBmdW5jdGlvbiAobmV3VmFsdWUsIG9sZFZhbHVlKSB7XG4gICAgICAgICAgaWYgKG5ld1ZhbHVlICE9PSBvbGRWYWx1ZSkge1xuICAgICAgICAgICAgc2NvcGUuc2VsZWN0UGFnZSgxKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNjb3BlLiR3YXRjaCgnc3REaXNwbGF5ZWRQYWdlcycsIHJlZHJhdyk7XG5cbiAgICAgICAgLy92aWV3IC0+IHRhYmxlIHN0YXRlXG4gICAgICAgIHNjb3BlLnNlbGVjdFBhZ2UgPSBmdW5jdGlvbiAocGFnZSkge1xuICAgICAgICAgIGlmIChwYWdlID4gMCAmJiBwYWdlIDw9IHNjb3BlLm51bVBhZ2VzKSB7XG4gICAgICAgICAgICBjdHJsLnNsaWNlKChwYWdlIC0gMSkgKiBzY29wZS5zdEl0ZW1zQnlQYWdlLCBzY29wZS5zdEl0ZW1zQnlQYWdlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKCFjdHJsLnRhYmxlU3RhdGUoKS5wYWdpbmF0aW9uLm51bWJlcikge1xuICAgICAgICAgIGN0cmwuc2xpY2UoMCwgc2NvcGUuc3RJdGVtc0J5UGFnZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuICB9XSk7XG4iLCJuZy5tb2R1bGUoJ3NtYXJ0LXRhYmxlJylcbiAgLmRpcmVjdGl2ZSgnc3RQaXBlJywgZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICByZXF1aXJlOiAnc3RUYWJsZScsXG4gICAgICBzY29wZToge1xuICAgICAgICBzdFBpcGU6ICc9J1xuICAgICAgfSxcbiAgICAgIGxpbms6IHtcblxuICAgICAgICBwcmU6IGZ1bmN0aW9uIChzY29wZSwgZWxlbWVudCwgYXR0cnMsIGN0cmwpIHtcbiAgICAgICAgICBpZiAobmcuaXNGdW5jdGlvbihzY29wZS5zdFBpcGUpKSB7XG4gICAgICAgICAgICBjdHJsLnByZXZlbnRQaXBlT25XYXRjaCgpO1xuICAgICAgICAgICAgY3RybC5waXBlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICByZXR1cm4gc2NvcGUuc3RQaXBlKGN0cmwudGFibGVTdGF0ZSgpLCBjdHJsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgcG9zdDogZnVuY3Rpb24gKHNjb3BlLCBlbGVtZW50LCBhdHRycywgY3RybCkge1xuICAgICAgICAgIGN0cmwucGlwZSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcbiAgfSk7XG4iLCJ9KShhbmd1bGFyKTsiXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0= \ No newline at end of file