diff options
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | .gitreview | 4 | ||||
-rw-r--r-- | LICENSE | 21 | ||||
-rw-r--r-- | MANIFEST.in | 3 | ||||
-rw-r--r-- | PKG-INFO | 25 | ||||
-rw-r--r-- | setup.cfg | 20 | ||||
-rw-r--r-- | setup.py | 28 | ||||
-rw-r--r-- | xstatic/pkg/angular_smart_table/__init__.py | 4 | ||||
-rw-r--r-- | xstatic/pkg/angular_smart_table/data/smart-table.js | 826 |
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 @@ -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 @@ -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 |