text: ;(function (angular) {
      'use strict';
  
      /**
       * tiny AngularJS Virtual Keyboard
       * An AngularJs Virtual Keyboard Interface based on GreyWyvern VKI & https://github.com/the-darc/angular-virtual-keyboard
       * @version The very first Alpha
       * @link
          * @license MIT
       */
  
  
      /* ********************************************************************
       **********************************************************************
       * Add a script-driven keyboard interface to text fields and password  fields.
       *
       * NOTE: The code below has been modified to conform to modern standards of HTML markup, and to ensure a more comfortable setting, as well as reduced in terms of supporting legacy browsers and
       */
  
      var VKI;
      VKI = function VKI(customConfig, layout, keyNames, keyInputCallback) {
          var self = this;
          self.keyInputCallback = keyInputCallback || function () {
              };
  
          this.vki_target = false;
          this.vki_kt = 'US International';  // Default keyboard layout
          this.uppercase = false;
  
          this.vki_caps = keyNames.capsKey[0];
          this.vki_space = keyNames.spaceKey[0];
          this.vki_backspace = keyNames.backspaceKey[0];
          this.vki_symbols = keyNames.characterKeyboard[0];
          this.vki_alphabetic = keyNames.alphabeticKeyboard[0];
          this.vki_num = keyNames.numericKeyboard[0];
  
          /* ***** Create keyboards ************************************** */
          // - Lay out each keyboard in rows of sub-arrays.  Each sub-array
          //   represents one key.
          //
          // - Each sub-array consists of two slots described as follows:
          //     example: ["a", "A"]
          //
          //          a) Normal character
          //          A) Character + Caps
  
  
          // - Note that any characters beyond the normal ASCII set should be
          //   entered in escaped Unicode format.  (eg \u00a3 = Pound symbol)
          //   You can find Unicode values for characters here:
          //     http://unicode.org/charts/
  
  
          this.vki_layout = layout;
  
          function hasSelectionStartEnd(elem) {
              var hasSelection = false;
              try {
                  hasSelection = !isNaN(elem.selectionStart) && !isNaN(elem.selectionEnd);
              } catch (e) {
              }
              return hasSelection;
          }
  
          /* ****************************************************************
           * Attach the keyboard to an element
           *
           */
          self.attachVki = function (elem) {
              if (elem.getAttribute("vki_attached")) return false;
  
              elem.onfocus = function () {
                  if (self.vki_target != this) {
                      if (self.vki_target) self.vki_close(false);
                      self.vki_show(this);
                  }
              };
  
              elem.onclick = function () {
                  if (!self.vki_target) self.vki_show(this);
              };
  
              elem.setAttribute("vki_attached", 'true');
  
              vki_addListener(elem, 'click', function (e) {
                  if (self.vki_target == this) {
                      e = e || event;
                      if (e.stopPropagation) {
                          e.stopPropagation();
                      } else e.cancelBubble = true;
                  }
                  return false;
              }, false);
  
              vki_addListener(document.documentElement, 'click', function () {
                  self.vki_close(false);
              }, false);
  
              // Attach close event handler.
              angular.element(elem).bind('vki_close', function () {
                  self.vki_close(false);
              });
          };
  
          /* ***** Build the keyboard interface ************************** */
          this.vki_keyboard = document.createElement('div');
          this.vki_keyboard.className = "vk";
  
          vki_addListener(this.vki_keyboard, 'click', function (e) {
              e = e || event;
              if (e.stopPropagation) {
                  e.stopPropagation();
              } else e.cancelBubble = true;
              return false;
          }, false);
  
          if (!this.vki_layout[this.vki_kt])
              return alert('No keyboard named "' + this.vki_kt + '"');
  
          function KeyHint(key, first) {
              var hintClass = 'hint',
                  done = false;
  
              var findHint = function () {
                  var hintedElem,
                      container = key.parentNode;
  
                  while (!container.classList.contains('vk')) {
                      container = container.parentNode;
                  }
  
                  var keys = container.getElementsByClassName('vk-key');
  
                  for (var i = keys.length - 1; i >= 0; i--) {
                      if (keys[i].classList.contains(hintClass) && keys[i] !== key) {
                          hintedElem = keys[i];
                      }
                  }
                  return hintedElem;
              };
  
              var removeSelfHint = function () {
                  key.classList.remove(hintClass);
                  done = false;
              };
  
              var removeOtherHint = function () {
                  var hintedElem = findHint();
                  if (!hintedElem) {
                      return false;
                  }
                  hintedElem.classList.remove(hintClass);
              };
  
              var showHint = function () {
                  if (!done) {
  
                      if (first !== true) {
                          removeOtherHint();
                          first = true;
                      }
  
                      key.classList.add(hintClass);
                      done = true;
                  }
              };
  
              this.show = function () {
                  showHint();
              };
  
              this.hide = function () {
                  removeSelfHint();
              };
  
          }
  
          /* ****************************************************************
           * Private table cell attachment function for generic characters
           *
           */
          function vki_keyClick() {
              var done = false,
                  /*jshint validthis:true */
                  character = this.dataset.attr,
                  timer,
                  /*jshint validthis:true */
                  hint = new KeyHint(this, false);
  
              if (!!timer) {
                  window.clearTimeout(timer);
              }
  
              if (character !== ' ') {
                  hint.show();
              }
  
              timer = window.setTimeout(function () {
                  hint.hide();
              }, 300);
  
              if (!done) {
                  self.vki_insert(character);
              }
              self.vki_modify('');
          }
  
          this.vki_setAttr = function (n) {
              if (
                  n === this.vki_caps ||
                  n === this.vki_symbols ||
                  n === this.vki_backspace ||
                  n === this.vki_alphabetic ||
                  n === this.vki_num
              ) {
                  return '';
              } else if (n === this.vki_space) {
                  return ' ';
              } else {
                  return n;
              }
          };
  
          /* ****************************************************************
           * Build or rebuild the keyboard keys
           *
           */
          this.vki_buildKeys = function () {
              var container = this.vki_keyboard,
                  kbrds = container.getElementsByClassName('vk-row');
  
              for (var n = kbrds.length - 1; n >= 0; n--) container.removeChild(kbrds[n]);
  
              for (var x = 0, lyt; lyt = this.vki_layout[this.vki_kt].keys[x]; x++) {
                  var vkRow = document.createElement('div');
                  vkRow.className = 'vk-row';
                  for (var y = 0, lkey; lkey = lyt[y]; y++) {
                      var nkeys = document.createElement('span');
  
                      nkeys.appendChild(document.createTextNode(lkey[0]));
  
                      nkeys.classList.add('vk-key');
                      nkeys.setAttribute('data-attr', this.vki_setAttr(lkey[0]));
  
                      switch (lkey[1]) {
                          case this.vki_caps:
                              vki_addListener(nkeys, 'click', (function (type) {
                                  return function () {
                                      self.vki_modify(type);
                                      return false;
                                  };
                              })(lkey[1]), false);
                              break;
                          case this.vki_backspace:
                              vki_addListener(nkeys, 'click', function () {
                                  self.vki_target.focus();
                                  if (self.vki_target.setSelectionRange && hasSelectionStartEnd(self.vki_target) && !self.vki_target.readOnly) {
                                      var rng = [self.vki_target.selectionStart, self.vki_target.selectionEnd];
                                      if (rng[0] < rng[1]) rng[0]++;
                                      self.vki_target.value = self.vki_target.value.substr(0, rng[0] - 1) + self.vki_target.value.substr(rng[1]);
                                      self.vki_target.setSelectionRange(rng[0] - 1, rng[0] - 1);
                                  } else if (self.vki_target.createTextRange && !self.vki_target.readOnly) {
                                      try {
                                          self.vki_target.range.select();
                                      } catch (e) {
                                          self.vki_target.range = document.selection.createRange();
                                      }
                                      if (!self.vki_target.range.text.length) self.vki_target.range.moveStart('character', -1);
                                      self.vki_target.range.text = "";
                                  } else self.vki_target.value = self.vki_target.value.substr(0, self.vki_target.value.length - 1);
                                  self.vki_target.focus();
                                  self.keyInputCallback();
                                  return true;
                              }, false);
                              break;
                          case this.vki_num:
                              vki_addListener(nkeys, 'click', function (e) {
                                  e = e || event;
                                  if (e.stopPropagation) {
                                      e.stopPropagation();
                                  } else e.cancelBubble = true;
                                  self.vki_kts = self.vki_kt = 'Numeric';
                                  self.vki_buildKeys();
                              }, false);
                              break;
                          case this.vki_symbols:
                              vki_addListener(nkeys, 'click', function (e) {
                                  e = e || event;
                                  if (e.stopPropagation) {
                                      e.stopPropagation();
                                  } else e.cancelBubble = true;
                                  self.vki_kts = self.vki_kt = 'Character';
                                  self.vki_buildKeys();
                              }, false);
                              break;
                          case this.vki_alphabetic:
                              vki_addListener(nkeys, 'click', function (e) {
                                  e = e || event;
                                  if (e.stopPropagation) {
                                      e.stopPropagation();
                                  } else e.cancelBubble = true;
                                  self.vki_kts = self.vki_kt = 'US International';
                                  self.vki_buildKeys();
                              }, false);
                              break;
                          default:
                              vki_addListener(nkeys, 'click', vki_keyClick, false);
  
                      }
                      vkRow.appendChild(nkeys);
  
                  }
                  container.appendChild(vkRow);
              }
          };
  
          this.vki_buildKeys();
  
          vki_addListener(this.vki_keyboard, 'selectstart', function () {
              return false;
          }, false);
          this.vki_keyboard.unselectable = 'on';
  
          /* ****************************************************************
           * Controls modifier keys
           *
           */
          this.vki_modify = function (type) {
              switch (type) {
                  case this.vki_caps:
                      this.uppercase = !this.uppercase;
                      break;
              }
              var vchar = 0;
              if (this.uppercase) vchar = 1;
  
              var kbrds = this.vki_keyboard.getElementsByClassName('vk-row');
              for (var x = 0; x < kbrds.length; x++) {
                  var nkeys = kbrds[x].getElementsByClassName('vk-key');
                  for (var y = 0; y < nkeys.length; y++) {
                      var lkey = this.vki_layout[this.vki_kt].keys[x][y];
  
                      switch (lkey[1]) {
                          case this.vki_backspace:
                              self.vki_target.focus();
                              break;
                          default:
                              if (type) {
                                  nkeys[y].removeChild(nkeys[y].firstChild);
                                  nkeys[y].appendChild(document.createTextNode(lkey[vchar]));
                                  nkeys[y].setAttribute('data-attr', this.vki_setAttr(lkey[vchar]));
                              }
                      }
                  }
              }
          };
  
          /* ****************************************************************
           * Insert text at the cursor
           *
           */
          this.vki_insert = function (text) {
              this.vki_target.focus();
              if (this.vki_target.maxLength) this.vki_target.maxlength = this.vki_target.maxLength;
              if (typeof this.vki_target.maxlength == 'undefined' ||
                  this.vki_target.maxlength < 0 ||
                  this.vki_target.value.length < this.vki_target.maxlength) {
                  if (this.vki_target.setSelectionRange && hasSelectionStartEnd(this.vki_target) && !this.vki_target.readOnly) {
                      var rng = [this.vki_target.selectionStart, this.vki_target.selectionEnd];
                      this.vki_target.value = this.vki_target.value.substr(0, rng[0]) + text + this.vki_target.value.substr(rng[1]);
                      this.vki_target.setSelectionRange(rng[0] + text.length, rng[0] + text.length);
                  } else if (this.vki_target.createTextRange && !this.vki_target.readOnly) {
                      try {
                          this.vki_target.range.select();
                      } catch (e) {
                          this.vki_target.range = document.selection.createRange();
                      }
                      this.vki_target.range.text = text;
                      this.vki_target.range.collapse(true);
                      this.vki_target.range.select();
                  } else this.vki_target.value += text;
  
                  if (this.uppercase) this.vki_modify(this.vki_caps);
  
                  this.vki_target.focus();
                  this.keyInputCallback();
              } else if (this.vki_target.createTextRange && this.vki_target.range)
                  this.vki_target.range.select();
          };
  
          /* ****************************************************************
           * Show the keyboard interface
           *
           */
          this.vki_show = function (elem) {
              if (!this.vki_target) {
                  this.vki_target = elem;
                  try {
                      this.vki_keyboard.parentNode.removeChild(this.vki_keyboard);
                  } catch (e) {
                  }
  
                  document.body.appendChild(this.vki_keyboard);
  
                  this.vki_target.blur();
                  this.vki_target.focus();
  
                  this.vki_closeOthers();
  
              } else this.vki_close(false);
          };
  
          /* ****************************************************************
           * For triggering close to non-focused virtual keyboard elements
           *
           */
          this.vki_closeOthers = function () {
              function fireCloseEvent(angularElement) {
                  if (angularElement.getAttribute('vki_attached') === 'true' && !angular.equals(self.vki_target, angularElement)) {
                      var inputChild = angular.element(angularElement);
                      inputChild.triggerHandler('vki_close');
                  }
              }
  
              angular.forEach(angular.element(document).find('input'), fireCloseEvent);
              angular.forEach(angular.element(document).find('textarea'), fireCloseEvent);
          };
  
          /* ****************************************************************
           * Close the keyboard interface
           *
           */
          self.vki_close = function (keepFocus) {
              if (self.vki_target) {
                  try {
                      self.vki_keyboard.parentNode.removeChild(self.vki_keyboard);
                  } catch (e) {
                  }
  
                  if (keepFocus) {
                      self.vki_target.focus();
                  }
                  self.vki_target = false;
              }
          };
  
  
          /* ***** Private functions *************************************** */
          function vki_addListener(elem, type, func, cap) {
              if (elem.addEventListener) {
                  elem.addEventListener(type, function (e) {
                      func.call(elem, e);
                  }, cap);
              } else if (elem.attachEvent)
                  elem.attachEvent('on' + type, function () {
                      func.call(elem);
                  });
          }
  
          return self;
      };
  
      angular.module('tinyVirtualKeyboard', [])
          .constant('VKI_CONFIG', (function () {
              /*jshint maxlen:500 */
              var keyNames = {
                      'spaceKey': ['Space', 'Space'],
                      'capsKey': ['Caps', 'Caps'],
                      'backspaceKey': ['Backspace', 'Backspace'],
                      'alphabeticKeyboard': ['ABC', 'ABC'],
                      'numericKeyboard': ['123', '123'],
                      'characterKeyboard': ['#+=', '#+=']
                  },
                  layout = {
                      'US International': {
                          'name': 'US International', 'keys': [
                              [['q', 'Q'], ['w', 'W'], ['e', 'E'], ['r', 'R'], ['t', 'T'], ['y', 'Y'], ['u', 'U'], ['i', 'I'], ['o', 'O'], ['p', 'P']],
                              [['a', 'A'], ['s', 'S'], ['d', 'D'], ['f', 'F'], ['g', 'G'], ['h', 'H'], ['j', 'J'], ['k', 'K'], ['l', 'L']],
                              [keyNames.capsKey, ['z', 'Z'], ['x', 'X'], ['c', 'C'], ['v', 'V'], ['b', 'B'], ['n', 'N'], ['m', 'M'], keyNames.backspaceKey],
                              [keyNames.numericKeyboard, keyNames.spaceKey, keyNames.numericKeyboard]
                          ],
                          'lang': ['en']
                      },
                      'Numeric': {
                          'name': 'Numeric', 'keys': [
                              [['1'], ['2'], ['3'], ['4'], ['5'], ['6'], ['7'], ['8'], ['9'], ['0']],
                              [['-'], ['/'], [':'], [';'], ['('], [')'], ['&'], ['@'], ['\u0022']],
                              [keyNames.characterKeyboard, ['.'], [','], ['?'], ['!'], ['\u0027'], keyNames.backspaceKey],
                              [keyNames.alphabeticKeyboard, keyNames.spaceKey, keyNames.alphabeticKeyboard]
                          ]
                      },
                      'Character': {
                          'name': 'Character', 'keys': [
                              [['\['], ['\]'], ['{'], ['}'], ['#'], ['%'], ['^'], ['*'], ['+'], ['=']],
                              [['_'], ['\\'], ['|'], ['\u007E'], ['<'], ['>'], ['$'], ['\u20AC'], ['\u00B7']],
                              [keyNames.numericKeyboard, ['.'], [','], ['?'], ['!'], ['\u0060'], keyNames.backspaceKey],
                              [keyNames.alphabeticKeyboard, keyNames.spaceKey, keyNames.alphabeticKeyboard]
                          ]
                      }
                  };
              return {
                  keyNames: keyNames,
                  layout: layout
              };
          })())
          .service('ngVirtualKeyboardService', ['VKI_CONFIG', function (VKI_CONFIG) {
              /*globals VKI */
              return {
                  attach: function (element, config, inputCallback) {
                      config = config || {};
                      config.kn = VKI_CONFIG.keyNames;
                      config.kt = VKI_CONFIG.kt;
                      var vki = new VKI(config, VKI_CONFIG.layout, VKI_CONFIG.keyNames, inputCallback);
                      vki.attachVki(element);
                  }
              };
          }])
          .directive('ngVirtualKeyboard', ['ngVirtualKeyboardService', '$timeout',
              function (ngVirtualKeyboardService, $timeout) {
                  return {
                      restrict: 'A',
                      require: '?ngModel',
                      scope: {
                          config: '=ngVirtualKeyboard'
                      },
                      link: function (scope, elements, attrs, ngModelCtrl) {
                          if (!ngModelCtrl) {
                              return;
                          }
  
                          ngVirtualKeyboardService.attach(elements[0], scope.config, function () {
                              $timeout(function () {
                                  ngModelCtrl.$setViewValue(elements[0].value);
                              });
                          });
  
                      }
                  };
              }]);
  
  })(angular);
  
  