text: (function ($) {
      'use strict';
      $.jqPaginator = function (el, options) {
          if (!(this instanceof $.jqPaginator)) {
              return new $.jqPaginator(el, options);
          }
          var self = this;
          self.$container = $(el);
          self.$container.data('jqPaginator', self);
          self.init = function () {
              if (options.first || options.prev || options.next || options.last || options.page) {
                  options = $.extend({}, {
                      first: '',
                      prev: '',
                      next: '',
                      last: '',
                      page: ''
                  }, options);
              }
              self.options = $.extend({}, $.jqPaginator.defaultOptions, options);
              self.verify();
              self.extendJquery();
              self.render();
              self.fireEvent(this.options.currentPage, 'init');
          };
          self.verify = function () {
              var opts = self.options;
              if (!self.isNumber(opts.totalPages)) {
                  throw new Error('[jqPaginator] type error: totalPages');
              }
              if (!self.isNumber(opts.totalCounts)) {
                  throw new Error('[jqPaginator] type error: totalCounts');
              }
              if (!self.isNumber(opts.pageSize)) {
                  throw new Error('[jqPaginator] type error: pageSize');
              }
              if (!self.isNumber(opts.currentPage)) {
                  throw new Error('[jqPaginator] type error: currentPage');
              }
              if (!self.isNumber(opts.visiblePages)) {
                  throw new Error('[jqPaginator] type error: visiblePages');
              }
              if (!opts.totalPages && !opts.totalCounts) {
                  throw new Error('[jqPaginator] totalCounts or totalPages is required');
              }
              if (!opts.totalPages && !opts.totalCounts) {
                  throw new Error('[jqPaginator] totalCounts or totalPages is required');
              }
              if (!opts.totalPages && opts.totalCounts && !opts.pageSize) {
                  throw new Error('[jqPaginator] pageSize is required');
              }
              if (opts.totalCounts && opts.pageSize) {
                  opts.totalPages = Math.ceil(opts.totalCounts / opts.pageSize);
              }
              if (opts.currentPage < 1 || opts.currentPage > opts.totalPages) {
                  throw new Error('[jqPaginator] currentPage is incorrect');
              }
              if (opts.totalPages < 1) {
                  throw new Error('[jqPaginator] totalPages cannot be less currentPage');
              }
          };
          self.extendJquery = function () {
              $.fn.jqPaginatorHTML = function (s) {
                  return s ? this.before(s).remove() : $('<p>').append(this.eq(0).clone()).html();
              };
          };
          self.render = function () {
              self.renderHtml();
              self.setStatus();
              self.bindEvents();
          };
          self.renderHtml = function () {
              var html = [];
              var pages = self.getPages();
              for (var i = 0, j = pages.length; i < j; i++) {
                  html.push(self.buildItem('page', pages[i]));
              }
              self.isEnable('prev') && html.unshift(self.buildItem('prev', self.options.currentPage - 1));
              self.isEnable('first') && html.unshift(self.buildItem('first', 1));
              self.isEnable('statistics') && html.unshift(self.buildItem('statistics'));
              self.isEnable('next') && html.push(self.buildItem('next', self.options.currentPage + 1));
              self.isEnable('last') && html.push(self.buildItem('last', self.options.totalPages));
              if (self.options.wrapper) {
                  self.$container.html($(self.options.wrapper).html(html.join('')).jqPaginatorHTML());
              } else {
                  self.$container.html(html.join(''));
              }
          };
          self.buildItem = function (type, pageData) {
              var html = self.options[type]
                  .replace(/{{page}}/g, pageData)
                  .replace(/{{totalPages}}/g, self.options.totalPages)
                  .replace(/{{totalCounts}}/g, self.options.totalCounts);
              return $(html).attr({
                  'jp-role': type,
                  'jp-data': pageData
              }).jqPaginatorHTML();
          };
          self.setStatus = function () {
              var options = self.options;
              if (!self.isEnable('first') || options.currentPage === 1) {
                  $('[jp-role=first]', self.$container).addClass(options.disableClass);
              }
              if (!self.isEnable('prev') || options.currentPage === 1) {
                  $('[jp-role=prev]', self.$container).addClass(options.disableClass);
              }
              if (!self.isEnable('next') || options.currentPage >= options.totalPages) {
                  $('[jp-role=next]', self.$container).addClass(options.disableClass);
              }
              if (!self.isEnable('last') || options.currentPage >= options.totalPages) {
                  $('[jp-role=last]', self.$container).addClass(options.disableClass);
              }
              $('[jp-role=page]', self.$container).removeClass(options.activeClass);
              $('[jp-role=page][jp-data=' + options.currentPage + ']', self.$container).addClass(options.activeClass);
          };
          self.getPages = function () {
              var pages = [],
                  visiblePages = self.options.visiblePages,
                  currentPage = self.options.currentPage,
                  totalPages = self.options.totalPages;
              if (visiblePages > totalPages) {
                  visiblePages = totalPages;
              }
              var half = Math.floor(visiblePages / 2);
              var start = currentPage - half + 1 - visiblePages % 2;
              var end = currentPage + half;
              if (start < 1) {
                  start = 1;
                  end = visiblePages;
              }
              if (end > totalPages) {
                  end = totalPages;
                  start = 1 + totalPages - visiblePages;
              }
              var itPage = start;
              while (itPage <= end) {
                  pages.push(itPage);
                  itPage++;
              }
              return pages;
          };
          self.isNumber = function (value) {
              var type = typeof value;
              return type === 'number' || type === 'undefined';
          };
          self.isEnable = function (type) {
              return self.options[type] && typeof self.options[type] === 'string';
          };
          self.switchPage = function (pageIndex) {
              self.options.currentPage = pageIndex;
              self.render();
          };
          self.fireEvent = function (pageIndex, type) {
              return (typeof self.options.onPageChange !== 'function') || (self.options.onPageChange(pageIndex, type) !== false);
          };
          self.callMethod = function (method, options) {
              switch (method) {
                  case 'option':
                      self.options = $.extend({}, self.options, options);
                      self.verify();
                      self.render();
                      break;
                  case 'destroy':
                      self.$container.empty();
                      self.$container.removeData('jqPaginator');
                      break;
                  default :
                      throw new Error('[jqPaginator] method "' + method + '" does not exist');
              }
              return self.$container;
          };
          self.bindEvents = function () {
              var opts = self.options;
              self.$container.off();
              self.$container.on('click', '[jp-role]', function () {
                  var $el = $(this);
                  if ($el.hasClass(opts.disableClass) || $el.hasClass(opts.activeClass)) {
                      return;
                  }
                  var pageIndex = +$el.attr('jp-data');
                  if (self.fireEvent(pageIndex, 'change')) {
                      self.switchPage(pageIndex);
                  }
              });
          };
          self.init();
          return self.$container;
      };
      $.jqPaginator.defaultOptions = {
          wrapper: '',
          first: '<li class="first"><a href="javascript:;">First</a></li>',
          prev: '<li class="prev"><a href="javascript:;">Previous</a></li>',
          next: '<li class="next"><a href="javascript:;">Next</a></li>',
          last: '<li class="last"><a href="javascript:;">Last</a></li>',
          page: '<li class="page"><a href="javascript:;">{{page}}</a></li>',
          totalPages: 0,
          totalCounts: 0,
          pageSize: 0,
          currentPage: 1,
          visiblePages: 7,
          disableClass: 'disabled',
          activeClass: 'active',
          onPageChange: null
      };
      $.fn.jqPaginator = function () {
          var self = this,
              args = Array.prototype.slice.call(arguments);
          if (typeof args[0] === 'string') {
              var $instance = $(self).data('jqPaginator');
              if (!$instance) {
                  throw new Error('[jqPaginator] the element is not instantiated');
              } else {
                  return $instance.callMethod(args[0], args[1]);
              }
          } else {
              return new $.jqPaginator(this, args[0]);
          }
      };
  })(jQuery);