Remove AngularUtils

The AngularUtils library is no longer maintained. This brings
the pagination directive used on the log events page into the
project and removes it from package.json

Resolves openbmc/phosphor-webui#10

Change-Id: I8235ef6ff325c9b0d8440d203816a38ded5d3890
Signed-off-by: beccabroek <beccabroek@gmail.com>
diff --git a/app/common/directives/dirPagination.js b/app/common/directives/dirPagination.js
new file mode 100644
index 0000000..97f7a1f
--- /dev/null
+++ b/app/common/directives/dirPagination.js
@@ -0,0 +1,699 @@
+/**
+ * dirPagination - AngularJS module for paginating (almost) anything.
+ * https://github.com/michaelbromley/angularUtils
+ *
+ *
+ * Credits
+ * =======
+ *
+ * Daniel Tabuenca:
+ * https://groups.google.com/d/msg/angular/an9QpzqIYiM/r8v-3W1X5vcJ for the idea
+ * on how to dynamically invoke the ng-repeat directive.
+ *
+ * I borrowed a couple of lines and a few attribute names from the AngularUI
+ * Bootstrap project:
+ * https://github.com/angular-ui/bootstrap/blob/master/src/pagination/pagination.js
+ *
+ * Copyright 2014 Michael Bromley <michael@michaelbromley.co.uk>
+ */
+
+(function() {
+
+/**
+ * Config
+ */
+var moduleName = 'app.common.directives.dirPagination';
+var DEFAULT_ID = '__default';
+
+/**
+ * Module
+ */
+angular.module(moduleName, [])
+    .directive(
+        'dirPaginate',
+        ['$compile', '$parse', 'paginationService', dirPaginateDirective])
+    .directive('dirPaginateNoCompile', noCompileDirective)
+    .directive(
+        'dirPaginationControls',
+        [
+          'paginationService', 'paginationTemplate',
+          dirPaginationControlsDirective
+        ])
+    .filter('itemsPerPage', ['paginationService', itemsPerPageFilter])
+    .service('paginationService', paginationService)
+    .provider('paginationTemplate', paginationTemplateProvider)
+    .run(['$templateCache', dirPaginationControlsTemplateInstaller]);
+
+function dirPaginateDirective($compile, $parse, paginationService) {
+  return {
+    terminal: true,
+    multiElement: true,
+    priority: 100,
+    compile: dirPaginationCompileFn
+  };
+
+  function dirPaginationCompileFn(tElement, tAttrs) {
+    var expression = tAttrs.dirPaginate;
+    // regex taken directly from
+    // https://github.com/angular/angular.js/blob/v1.4.x/src/ng/directive/ngRepeat.js#L339
+    var match = expression.match(
+        /^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
+
+    var filterPattern =
+        /\|\s*itemsPerPage\s*:\s*(.*\(\s*\w*\)|([^\)]*?(?=\s+as\s+))|[^\)]*)/;
+    if (match[2].match(filterPattern) === null) {
+      throw 'pagination directive: the \'itemsPerPage\' filter must be set.';
+    }
+    var itemsPerPageFilterRemoved = match[2].replace(filterPattern, '');
+    var collectionGetter = $parse(itemsPerPageFilterRemoved);
+
+    addNoCompileAttributes(tElement);
+
+    // If any value is specified for paginationId, we register the un-evaluated
+    // expression at this stage for the benefit of any dir-pagination-controls
+    // directives that may be looking for this ID.
+    var rawId = tAttrs.paginationId || DEFAULT_ID;
+    paginationService.registerInstance(rawId);
+
+    return function dirPaginationLinkFn(scope, element, attrs) {
+      // Now that we have access to the `scope` we can interpolate any
+      // expression given in the paginationId attribute and potentially register
+      // a new ID if it evaluates to a different value than the rawId.
+      var paginationId =
+          $parse(attrs.paginationId)(scope) || attrs.paginationId || DEFAULT_ID;
+
+      // (TODO: this seems sound, but I'm reverting as many bug reports followed
+      // it's introduction in 0.11.0. Needs more investigation.) In case rawId
+      // != paginationId we deregister using rawId for the sake of general
+      // cleanliness before registering using paginationId
+      // paginationService.deregisterInstance(rawId);
+      paginationService.registerInstance(paginationId);
+
+      var repeatExpression = getRepeatExpression(expression, paginationId);
+      addNgRepeatToElement(element, attrs, repeatExpression);
+
+      removeTemporaryAttributes(element);
+      var compiled = $compile(element);
+
+      var currentPageGetter =
+          makeCurrentPageGetterFn(scope, attrs, paginationId);
+      paginationService.setCurrentPageParser(
+          paginationId, currentPageGetter, scope);
+
+      if (typeof attrs.totalItems !== 'undefined') {
+        paginationService.setAsyncModeTrue(paginationId);
+        scope.$watch(
+            function() {
+              return $parse(attrs.totalItems)(scope);
+            },
+            function(result) {
+              if (0 <= result) {
+                paginationService.setCollectionLength(paginationId, result);
+              }
+            });
+      } else {
+        paginationService.setAsyncModeFalse(paginationId);
+        scope.$watchCollection(
+            function() {
+              return collectionGetter(scope);
+            },
+            function(collection) {
+              if (collection) {
+                var collectionLength = (collection instanceof Array) ?
+                    collection.length :
+                    Object.keys(collection).length;
+                paginationService.setCollectionLength(
+                    paginationId, collectionLength);
+              }
+            });
+      }
+
+      // Delegate to the link function returned by the new compilation of the
+      // ng-repeat
+      compiled(scope);
+
+      // (TODO: Reverting this due to many bug reports in v 0.11.0. Needs
+      // investigation as the principle is sound) When the scope is destroyed,
+      // we make sure to remove the reference to it in paginationService so that
+      // it can be properly garbage collected scope.$on('$destroy', function
+      // destroyDirPagination() {
+      //     paginationService.deregisterInstance(paginationId);
+      // });
+    };
+  }
+
+  /**
+   * If a pagination id has been specified, we need to check that it is present
+   * as the second argument passed to the itemsPerPage filter. If it is not
+   * there, we add it and return the modified expression.
+   *
+   * @param expression
+   * @param paginationId
+   * @returns {*}
+   */
+  function getRepeatExpression(expression, paginationId) {
+    var repeatExpression,
+        idDefinedInFilter =
+            !!expression.match(/(\|\s*itemsPerPage\s*:[^|]*:[^|]*)/);
+
+    if (paginationId !== DEFAULT_ID && !idDefinedInFilter) {
+      repeatExpression = expression.replace(
+          /(\|\s*itemsPerPage\s*:\s*[^|\s]*)/, '$1 : \'' + paginationId + '\'');
+    } else {
+      repeatExpression = expression;
+    }
+
+    return repeatExpression;
+  }
+
+  /**
+   * Adds the ng-repeat directive to the element. In the case of multi-element
+   * (-start, -end) it adds the appropriate multi-element ng-repeat to the first
+   * and last element in the range.
+   * @param element
+   * @param attrs
+   * @param repeatExpression
+   */
+  function addNgRepeatToElement(element, attrs, repeatExpression) {
+    if (element[0].hasAttribute('dir-paginate-start') ||
+        element[0].hasAttribute('data-dir-paginate-start')) {
+      // using multiElement mode (dir-paginate-start, dir-paginate-end)
+      attrs.$set('ngRepeatStart', repeatExpression);
+      element.eq(element.length - 1).attr('ng-repeat-end', true);
+    } else {
+      attrs.$set('ngRepeat', repeatExpression);
+    }
+  }
+
+  /**
+   * Adds the dir-paginate-no-compile directive to each element in the tElement
+   * range.
+   * @param tElement
+   */
+  function addNoCompileAttributes(tElement) {
+    angular.forEach(tElement, function(el) {
+      if (el.nodeType === 1) {
+        angular.element(el).attr('dir-paginate-no-compile', true);
+      }
+    });
+  }
+
+  /**
+   * Removes the variations on dir-paginate (data-, -start, -end) and the
+   * dir-paginate-no-compile directives.
+   * @param element
+   */
+  function removeTemporaryAttributes(element) {
+    angular.forEach(element, function(el) {
+      if (el.nodeType === 1) {
+        angular.element(el).removeAttr('dir-paginate-no-compile');
+      }
+    });
+    element.eq(0)
+        .removeAttr('dir-paginate-start')
+        .removeAttr('dir-paginate')
+        .removeAttr('data-dir-paginate-start')
+        .removeAttr('data-dir-paginate');
+    element.eq(element.length - 1)
+        .removeAttr('dir-paginate-end')
+        .removeAttr('data-dir-paginate-end');
+  }
+
+  /**
+   * Creates a getter function for the current-page attribute, using the
+   * expression provided or a default value if no current-page expression was
+   * specified.
+   *
+   * @param scope
+   * @param attrs
+   * @param paginationId
+   * @returns {*}
+   */
+  function makeCurrentPageGetterFn(scope, attrs, paginationId) {
+    var currentPageGetter;
+    if (attrs.currentPage) {
+      currentPageGetter = $parse(attrs.currentPage);
+    } else {
+      // If the current-page attribute was not set, we'll make our own.
+      // Replace any non-alphanumeric characters which might confuse
+      // the $parse service and give unexpected results.
+      // See https://github.com/michaelbromley/angularUtils/issues/233
+      var defaultCurrentPage =
+          (paginationId + '__currentPage').replace(/\W/g, '_');
+      scope[defaultCurrentPage] = 1;
+      currentPageGetter = $parse(defaultCurrentPage);
+    }
+    return currentPageGetter;
+  }
+}
+
+/**
+ * This is a helper directive that allows correct compilation when in
+ * multi-element mode (ie dir-paginate-start, dir-paginate-end). It is
+ * dynamically added to all elements in the dir-paginate compile function, and
+ * it prevents further compilation of any inner directives. It is then removed
+ * in the link function, and all inner directives are then manually compiled.
+ */
+function noCompileDirective() {
+  return {priority: 5000, terminal: true};
+}
+
+function dirPaginationControlsTemplateInstaller($templateCache) {
+  $templateCache.put(
+      'app.common.directives.dirPagination.template',
+      '<ul class="pagination" ng-if="1 < pages.length || !autoHide"><li ng-if="boundaryLinks" ng-class="{ disabled : pagination.current == 1 }"><a href="" ng-click="setCurrent(1)">&laquo;</a></li><li ng-if="directionLinks" ng-class="{ disabled : pagination.current == 1 }"><a href="" ng-click="setCurrent(pagination.current - 1)">&lsaquo;</a></li><li ng-repeat="pageNumber in pages track by tracker(pageNumber, $index)" ng-class="{ active : pagination.current == pageNumber, disabled : pageNumber == \'...\' || ( ! autoHide && pages.length === 1 ) }"><a href="" ng-click="setCurrent(pageNumber)">{{ pageNumber }}</a></li><li ng-if="directionLinks" ng-class="{ disabled : pagination.current == pagination.last }"><a href="" ng-click="setCurrent(pagination.current + 1)">&rsaquo;</a></li><li ng-if="boundaryLinks"  ng-class="{ disabled : pagination.current == pagination.last }"><a href="" ng-click="setCurrent(pagination.last)">&raquo;</a></li></ul>');
+}
+
+function dirPaginationControlsDirective(paginationService, paginationTemplate) {
+  var numberRegex = /^\d+$/;
+
+  var DDO = {
+    restrict: 'AE',
+    scope:
+        {maxSize: '=?', onPageChange: '&?', paginationId: '=?', autoHide: '=?'},
+    link: dirPaginationControlsLinkFn
+  };
+
+  // We need to check the paginationTemplate service to see whether a template
+  // path or string has been specified, and add the `template` or `templateUrl`
+  // property to the DDO as appropriate. The order of priority to decide which
+  // template to use is (highest priority first):
+  // 1. paginationTemplate.getString()
+  // 2. attrs.templateUrl
+  // 3. paginationTemplate.getPath()
+  var templateString = paginationTemplate.getString();
+  if (templateString !== undefined) {
+    DDO.template = templateString;
+  } else {
+    DDO.templateUrl = function(elem, attrs) {
+      return attrs.templateUrl || paginationTemplate.getPath();
+    };
+  }
+  return DDO;
+
+  function dirPaginationControlsLinkFn(scope, element, attrs) {
+    // rawId is the un-interpolated value of the pagination-id attribute. This
+    // is only important when the corresponding dir-paginate directive has not
+    // yet been linked (e.g. if it is inside an ng-if block), and in that case
+    // it prevents this controls directive from assuming that there is no
+    // corresponding dir-paginate directive and wrongly throwing an exception.
+    var rawId = attrs.paginationId || DEFAULT_ID;
+    var paginationId = scope.paginationId || attrs.paginationId || DEFAULT_ID;
+
+    if (!paginationService.isRegistered(paginationId) &&
+        !paginationService.isRegistered(rawId)) {
+      var idMessage =
+          (paginationId !== DEFAULT_ID) ? ' (id: ' + paginationId + ') ' : ' ';
+      if (window.console) {
+        console.warn(
+            'Pagination directive: the pagination controls' + idMessage +
+            'cannot be used without the corresponding pagination directive, which was not found at link time.');
+      }
+    }
+
+    if (!scope.maxSize) {
+      scope.maxSize = 9;
+    }
+    scope.autoHide = scope.autoHide === undefined ? true : scope.autoHide;
+    scope.directionLinks = angular.isDefined(attrs.directionLinks) ?
+        scope.$parent.$eval(attrs.directionLinks) :
+        true;
+    scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ?
+        scope.$parent.$eval(attrs.boundaryLinks) :
+        false;
+
+    var paginationRange = Math.max(scope.maxSize, 5);
+    scope.pages = [];
+    scope.pagination = {last: 1, current: 1};
+    scope.range = {lower: 1, upper: 1, total: 1};
+
+    scope.$watch('maxSize', function(val) {
+      if (val) {
+        paginationRange = Math.max(scope.maxSize, 5);
+        generatePagination();
+      }
+    });
+
+    scope.$watch(
+        function() {
+          if (paginationService.isRegistered(paginationId)) {
+            return (paginationService.getCollectionLength(paginationId) + 1) *
+                paginationService.getItemsPerPage(paginationId);
+          }
+        },
+        function(length) {
+          if (0 < length) {
+            generatePagination();
+          }
+        });
+
+    scope.$watch(
+        function() {
+          if (paginationService.isRegistered(paginationId)) {
+            return (paginationService.getItemsPerPage(paginationId));
+          }
+        },
+        function(current, previous) {
+          if (current != previous && typeof previous !== 'undefined') {
+            goToPage(scope.pagination.current);
+          }
+        });
+
+    scope.$watch(
+        function() {
+          if (paginationService.isRegistered(paginationId)) {
+            return paginationService.getCurrentPage(paginationId);
+          }
+        },
+        function(currentPage, previousPage) {
+          if (currentPage != previousPage) {
+            goToPage(currentPage);
+          }
+        });
+
+    scope.setCurrent = function(num) {
+      if (paginationService.isRegistered(paginationId) &&
+          isValidPageNumber(num)) {
+        num = parseInt(num, 10);
+        paginationService.setCurrentPage(paginationId, num);
+      }
+    };
+
+    /**
+     * Custom "track by" function which allows for duplicate "..." entries on
+     * long lists, yet fixes the problem of wrongly-highlighted links which
+     * happens when using "track by $index" - see
+     * https://github.com/michaelbromley/angularUtils/issues/153
+     * @param id
+     * @param index
+     * @returns {string}
+     */
+    scope.tracker = function(id, index) {
+      return id + '_' + index;
+    };
+
+    function goToPage(num) {
+      if (paginationService.isRegistered(paginationId) &&
+          isValidPageNumber(num)) {
+        var oldPageNumber = scope.pagination.current;
+
+        scope.pages = generatePagesArray(
+            num, paginationService.getCollectionLength(paginationId),
+            paginationService.getItemsPerPage(paginationId), paginationRange);
+        scope.pagination.current = num;
+        updateRangeValues();
+
+        // if a callback has been set, then call it with the page number as the
+        // first argument and the previous page number as a second argument
+        if (scope.onPageChange) {
+          scope.onPageChange(
+              {newPageNumber: num, oldPageNumber: oldPageNumber});
+        }
+      }
+    }
+
+    function generatePagination() {
+      if (paginationService.isRegistered(paginationId)) {
+        var page =
+            parseInt(paginationService.getCurrentPage(paginationId)) || 1;
+        scope.pages = generatePagesArray(
+            page, paginationService.getCollectionLength(paginationId),
+            paginationService.getItemsPerPage(paginationId), paginationRange);
+        scope.pagination.current = page;
+        scope.pagination.last = scope.pages[scope.pages.length - 1];
+        if (scope.pagination.last < scope.pagination.current) {
+          scope.setCurrent(scope.pagination.last);
+        } else {
+          updateRangeValues();
+        }
+      }
+    }
+
+    /**
+     * This function updates the values (lower, upper, total) of the
+     * `scope.range` object, which can be used in the pagination template to
+     * display the current page range, e.g. "showing 21 - 40 of 144 results";
+     */
+    function updateRangeValues() {
+      if (paginationService.isRegistered(paginationId)) {
+        var currentPage = paginationService.getCurrentPage(paginationId),
+            itemsPerPage = paginationService.getItemsPerPage(paginationId),
+            totalItems = paginationService.getCollectionLength(paginationId);
+
+        scope.range.lower = (currentPage - 1) * itemsPerPage + 1;
+        scope.range.upper = Math.min(currentPage * itemsPerPage, totalItems);
+        scope.range.total = totalItems;
+      }
+    }
+    function isValidPageNumber(num) {
+      return (
+          numberRegex.test(num) && (0 < num && num <= scope.pagination.last));
+    }
+  }
+
+  /**
+   * Generate an array of page numbers (or the '...' string) which is used in an
+   * ng-repeat to generate the links used in pagination
+   *
+   * @param currentPage
+   * @param rowsPerPage
+   * @param paginationRange
+   * @param collectionLength
+   * @returns {Array}
+   */
+  function generatePagesArray(
+      currentPage, collectionLength, rowsPerPage, paginationRange) {
+    var pages = [];
+    var totalPages = Math.ceil(collectionLength / rowsPerPage);
+    var halfWay = Math.ceil(paginationRange / 2);
+    var position;
+
+    if (currentPage <= halfWay) {
+      position = 'start';
+    } else if (totalPages - halfWay < currentPage) {
+      position = 'end';
+    } else {
+      position = 'middle';
+    }
+
+    var ellipsesNeeded = paginationRange < totalPages;
+    var i = 1;
+    while (i <= totalPages && i <= paginationRange) {
+      var pageNumber =
+          calculatePageNumber(i, currentPage, paginationRange, totalPages);
+
+      var openingEllipsesNeeded =
+          (i === 2 && (position === 'middle' || position === 'end'));
+      var closingEllipsesNeeded =
+          (i === paginationRange - 1 &&
+           (position === 'middle' || position === 'start'));
+      if (ellipsesNeeded && (openingEllipsesNeeded || closingEllipsesNeeded)) {
+        pages.push('...');
+      } else {
+        pages.push(pageNumber);
+      }
+      i++;
+    }
+    return pages;
+  }
+
+  /**
+   * Given the position in the sequence of pagination links [i], figure out what
+   * page number corresponds to that position.
+   *
+   * @param i
+   * @param currentPage
+   * @param paginationRange
+   * @param totalPages
+   * @returns {*}
+   */
+  function calculatePageNumber(i, currentPage, paginationRange, totalPages) {
+    var halfWay = Math.ceil(paginationRange / 2);
+    if (i === paginationRange) {
+      return totalPages;
+    } else if (i === 1) {
+      return i;
+    } else if (paginationRange < totalPages) {
+      if (totalPages - halfWay < currentPage) {
+        return totalPages - paginationRange + i;
+      } else if (halfWay < currentPage) {
+        return currentPage - halfWay + i;
+      } else {
+        return i;
+      }
+    } else {
+      return i;
+    }
+  }
+}
+
+/**
+ * This filter slices the collection into pages based on the current page number
+ * and number of items per page.
+ * @param paginationService
+ * @returns {Function}
+ */
+function itemsPerPageFilter(paginationService) {
+  return function(collection, itemsPerPage, paginationId) {
+    if (typeof (paginationId) === 'undefined') {
+      paginationId = DEFAULT_ID;
+    }
+    if (!paginationService.isRegistered(paginationId)) {
+      throw 'pagination directive: the itemsPerPage id argument (id: ' +
+          paginationId + ') does not match a registered pagination-id.';
+    }
+    var end;
+    var start;
+    if (angular.isObject(collection)) {
+      itemsPerPage = parseInt(itemsPerPage) || 9999999999;
+      if (paginationService.isAsyncMode(paginationId)) {
+        start = 0;
+      } else {
+        start =
+            (paginationService.getCurrentPage(paginationId) - 1) * itemsPerPage;
+      }
+      end = start + itemsPerPage;
+      paginationService.setItemsPerPage(paginationId, itemsPerPage);
+
+      if (collection instanceof Array) {
+        // the array just needs to be sliced
+        return collection.slice(start, end);
+      } else {
+        // in the case of an object, we need to get an array of keys, slice
+        // that, then map back to the original object.
+        var slicedObject = {};
+        angular.forEach(keys(collection).slice(start, end), function(key) {
+          slicedObject[key] = collection[key];
+        });
+        return slicedObject;
+      }
+    } else {
+      return collection;
+    }
+  };
+}
+
+/**
+ * Shim for the Object.keys() method which does not exist in IE < 9
+ * @param obj
+ * @returns {Array}
+ */
+function keys(obj) {
+  if (!Object.keys) {
+    var objKeys = [];
+    for (var i in obj) {
+      if (obj.hasOwnProperty(i)) {
+        objKeys.push(i);
+      }
+    }
+    return objKeys;
+  } else {
+    return Object.keys(obj);
+  }
+}
+
+/**
+ * This service allows the various parts of the module to communicate and stay
+ * in sync.
+ */
+function paginationService() {
+  var instances = {};
+  var lastRegisteredInstance;
+
+  this.registerInstance = function(instanceId) {
+    if (typeof instances[instanceId] === 'undefined') {
+      instances[instanceId] = {asyncMode: false};
+      lastRegisteredInstance = instanceId;
+    }
+  };
+
+  this.deregisterInstance = function(instanceId) {
+    delete instances[instanceId];
+  };
+
+  this.isRegistered = function(instanceId) {
+    return (typeof instances[instanceId] !== 'undefined');
+  };
+
+  this.getLastInstanceId = function() {
+    return lastRegisteredInstance;
+  };
+
+  this.setCurrentPageParser = function(instanceId, val, scope) {
+    instances[instanceId].currentPageParser = val;
+    instances[instanceId].context = scope;
+  };
+  this.setCurrentPage = function(instanceId, val) {
+    instances[instanceId].currentPageParser.assign(
+        instances[instanceId].context, val);
+  };
+  this.getCurrentPage = function(instanceId) {
+    var parser = instances[instanceId].currentPageParser;
+    return parser ? parser(instances[instanceId].context) : 1;
+  };
+
+  this.setItemsPerPage = function(instanceId, val) {
+    instances[instanceId].itemsPerPage = val;
+  };
+  this.getItemsPerPage = function(instanceId) {
+    return instances[instanceId].itemsPerPage;
+  };
+
+  this.setCollectionLength = function(instanceId, val) {
+    instances[instanceId].collectionLength = val;
+  };
+  this.getCollectionLength = function(instanceId) {
+    return instances[instanceId].collectionLength;
+  };
+
+  this.setAsyncModeTrue = function(instanceId) {
+    instances[instanceId].asyncMode = true;
+  };
+
+  this.setAsyncModeFalse = function(instanceId) {
+    instances[instanceId].asyncMode = false;
+  };
+
+  this.isAsyncMode = function(instanceId) {
+    return instances[instanceId].asyncMode;
+  };
+}
+
+/**
+ * This provider allows global configuration of the template path used by the
+ * dir-pagination-controls directive.
+ */
+function paginationTemplateProvider() {
+  var templatePath = 'app.common.directives.dirPagination.template';
+  var templateString;
+
+  /**
+   * Set a templateUrl to be used by all instances of <dir-pagination-controls>
+   * @param {String} path
+   */
+  this.setPath = function(path) {
+    templatePath = path;
+  };
+
+  /**
+   * Set a string of HTML to be used as a template by all instances
+   * of <dir-pagination-controls>. If both a path *and* a string have been set,
+   * the string takes precedence.
+   * @param {String} str
+   */
+  this.setString = function(str) {
+    templateString = str;
+  };
+
+  this.$get = function() {
+    return {
+      getPath: function() {
+        return templatePath;
+      },
+      getString: function() {
+        return templateString;
+      }
+    };
+  };
+}
+})();
diff --git a/app/index.js b/app/index.js
index 9a108a0..68ef68d 100644
--- a/app/index.js
+++ b/app/index.js
@@ -17,8 +17,6 @@
 import angular_sanitize from 'angular-sanitize';
 import angular_ui_bootstrap from 'angular-ui-bootstrap';
 import angular_ui_router from 'angular-ui-router';
-import angular_utils from 'angularUtils/src/angularUtils.js';
-import angular_utils_pagination from 'angularUtils/src/directives/pagination/dirPagination.js';
 
 require('./styles/index.scss');
 var config = require('../config.json');
@@ -49,6 +47,7 @@
 import loader from './common/directives/loader.js';
 import paginate from './common/directives/paginate.js';
 import serial_console from './common/directives/serial-console.js';
+import dir_paginate from './common/directives/dirPagination.js';
 
 import login_index from './login/index.js';
 import login_controller from './login/controllers/login-controller.js';
@@ -88,7 +87,7 @@
           [
             // Dependencies
             'ngRoute', 'angular-clipboard',
-            'angularUtils.directives.dirPagination',
+            'app.common.directives.dirPagination',
             // Basic resources
             'app.common.services', 'app.common.directives',
             'app.common.filters',