text: /**
   * alertifyjs 1.12.0 http://alertifyjs.com
   * AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications.
   * Copyright 2019 Mohammad Younes <Mohammad@alertifyjs.com> (http://alertifyjs.com) 
   * Licensed under GPL 3 <https://opensource.org/licenses/gpl-3.0>*/
  ( function ( window ) {
      'use strict';
      var NOT_DISABLED_NOT_RESET = ':not(:disabled):not(.ajs-reset)';
      /**
       * Keys enum
       * @type {Object}
       */
      var keys = {
          ENTER: 13,
          ESC: 27,
          F1: 112,
          F12: 123,
          LEFT: 37,
          RIGHT: 39,
          TAB: 9
      };
      /**
       * Default options 
       * @type {Object}
       */
      var defaults = {
          autoReset:true,
          basic:false,
          closable:true,
          closableByDimmer:true,
          invokeOnCloseOff:false,
          frameless:false,
          defaultFocusOff:false,
          maintainFocus:true, //global default not per instance, applies to all dialogs
          maximizable:true,
          modal:true,
          movable:true,
          moveBounded:false,
          overflow:true,
          padding: true,
          pinnable:true,
          pinned:true,
          preventBodyShift:false, //global default not per instance, applies to all dialogs
          resizable:true,
          startMaximized:false,
          transition:'pulse',
          tabbable:['button', '[href]', 'input', 'select', 'textarea', '[tabindex]:not([tabindex^="-"])'+NOT_DISABLED_NOT_RESET].join(NOT_DISABLED_NOT_RESET+','),//global
          notifier:{
              delay:5,
              position:'bottom-right',
              closeButton:false,
              classes: {
                  base: 'alertify-notifier',
                  prefix:'ajs-',
                  message: 'ajs-message',
                  top: 'ajs-top',
                  right: 'ajs-right',
                  bottom: 'ajs-bottom',
                  left: 'ajs-left',
                  center: 'ajs-center',
                  visible: 'ajs-visible',
                  hidden: 'ajs-hidden',
                  close: 'ajs-close'
              }
          },
          glossary:{
              title:'AlertifyJS',
              ok: 'Ok',
              cancel: 'Cancelar',
              acccpt: 'Acceptar',
              deny: 'Deny',
              confirm: 'Confirmar',
              decline: 'Decline',
              close: 'Cerrar',
              maximize: 'Maximize',
              restore: 'Restore',
          },
          theme:{
              input:'ajs-input',
              ok:'ajs-ok',
              cancel:'ajs-cancel',
          },
          hooks:{
              preinit:function(){},
              postinit:function(){}
          }
      };
      
      //holds open dialogs instances
      var openDialogs = [];
  
      /**
       * [Helper]  Adds the specified class(es) to the element.
       *
       * @element {node}      The element
       * @className {string}  One or more space-separated classes to be added to the class attribute of the element.
       * 
       * @return {undefined}
       */
      function addClass(element,classNames){
          element.className += ' ' + classNames;
      }
      
      /**
       * [Helper]  Removes the specified class(es) from the element.
       *
       * @element {node}      The element
       * @className {string}  One or more space-separated classes to be removed from the class attribute of the element.
       * 
       * @return {undefined}
       */
      function removeClass(element, classNames) {
          var original = element.className.split(' ');
          var toBeRemoved = classNames.split(' ');
          for (var x = 0; x < toBeRemoved.length; x += 1) {
              var index = original.indexOf(toBeRemoved[x]);
              if (index > -1){
                  original.splice(index,1);
              }
          }
          element.className = original.join(' ');
      }
  
      /**
       * [Helper]  Checks if the document is RTL
       *
       * @return {Boolean} True if the document is RTL, false otherwise.
       */
      function isRightToLeft(){
          return window.getComputedStyle(document.body).direction === 'rtl';
      }
      /**
       * [Helper]  Get the document current scrollTop
       *
       * @return {Number} current document scrollTop value
       */
      function getScrollTop(){
          return ((document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop);
      }
  
      /**
       * [Helper]  Get the document current scrollLeft
       *
       * @return {Number} current document scrollLeft value
       */
      function getScrollLeft(){
          return ((document.documentElement && document.documentElement.scrollLeft) || document.body.scrollLeft);
      }
  
      /**
      * Helper: clear contents
      *
      */
      function clearContents(element){
          while (element.lastChild) {
              element.removeChild(element.lastChild);
          }
      }
      /**
       * Extends a given prototype by merging properties from base into sub.
       *
       * @sub {Object} sub The prototype being overwritten.
       * @base {Object} base The prototype being written.
       *
       * @return {Object} The extended prototype.
       */
      function copy(src) {
          if(null === src){
              return src;
          }
          var cpy;
          if(Array.isArray(src)){
              cpy = [];
              for(var x=0;x<src.length;x+=1){
                  cpy.push(copy(src[x]));
              }
              return cpy;
          }
        
          if(src instanceof Date){
              return new Date(src.getTime());
          }
        
          if(src instanceof RegExp){
              cpy = new RegExp(src.source);
              cpy.global = src.global;
              cpy.ignoreCase = src.ignoreCase;
              cpy.multiline = src.multiline;
              cpy.lastIndex = src.lastIndex;
              return cpy;
          }
          
          if(typeof src === 'object'){
              cpy = {};
              // copy dialog pototype over definition.
              for (var prop in src) {
                  if (src.hasOwnProperty(prop)) {
                      cpy[prop] = copy(src[prop]);
                  }
              }
              return cpy;
          }
          return src;
      }
      /**
        * Helper: destruct the dialog
        *
        */
      function destruct(instance, initialize){
          if(instance.elements){
              //delete the dom and it's references.
              var root = instance.elements.root;
              root.parentNode.removeChild(root);
              delete instance.elements;
              //copy back initial settings.
              instance.settings = copy(instance.__settings);
              //re-reference init function.
              instance.__init = initialize;
              //delete __internal variable to allow re-initialization.
              delete instance.__internal;
          }
      }
  
      /**
       * Use a closure to return proper event listener method. Try to use
       * `addEventListener` by default but fallback to `attachEvent` for
       * unsupported browser. The closure simply ensures that the test doesn't
       * happen every time the method is called.
       *
       * @param    {Node}     el    Node element
       * @param    {String}   event Event type
       * @param    {Function} fn    Callback of event
       * @return   {Function}
       */
      var on = (function () {
          if (document.addEventListener) {
              return function (el, event, fn, useCapture) {
                  el.addEventListener(event, fn, useCapture === true);
              };
          } else if (document.attachEvent) {
              return function (el, event, fn) {
                  el.attachEvent('on' + event, fn);
              };
          }
      }());
  
      /**
       * Use a closure to return proper event listener method. Try to use
       * `removeEventListener` by default but fallback to `detachEvent` for
       * unsupported browser. The closure simply ensures that the test doesn't
       * happen every time the method is called.
       *
       * @param    {Node}     el    Node element
       * @param    {String}   event Event type
       * @param    {Function} fn    Callback of event
       * @return   {Function}
       */
      var off = (function () {
          if (document.removeEventListener) {
              return function (el, event, fn, useCapture) {
                  el.removeEventListener(event, fn, useCapture === true);
              };
          } else if (document.detachEvent) {
              return function (el, event, fn) {
                  el.detachEvent('on' + event, fn);
              };
          }
      }());
  
      /**
       * Prevent default event from firing
       *
       * @param  {Event} event Event object
       * @return {undefined}
  
      function prevent ( event ) {
          if ( event ) {
              if ( event.preventDefault ) {
                  event.preventDefault();
              } else {
                  event.returnValue = false;
              }
          }
      }
      */
      var transition = (function () {
          var t, type;
          var supported = false;
          var transitions = {
              'animation'        : 'animationend',
              'OAnimation'       : 'oAnimationEnd oanimationend',
              'msAnimation'      : 'MSAnimationEnd',
              'MozAnimation'     : 'animationend',
              'WebkitAnimation'  : 'webkitAnimationEnd'
          };
  
          for (t in transitions) {
              if (document.documentElement.style[t] !== undefined) {
                  type = transitions[t];
                  supported = true;
                  break;
              }
          }
  
          return {
              type: type,
              supported: supported
          };
      }());
  
      /**
      * Creates event handler delegate that sends the instance as last argument.
      * 
      * @return {Function}    a function wrapper which sends the instance as last argument.
      */
      function delegate(context, method) {
          return function () {
              if (arguments.length > 0) {
                  var args = [];
                  for (var x = 0; x < arguments.length; x += 1) {
                      args.push(arguments[x]);
                  }
                  args.push(context);
                  return method.apply(context, args);
              }
              return method.apply(context, [null, context]);
          };
      }
      /**
      * Helper for creating a dialog close event.
      * 
      * @return {object}
      */
      function createCloseEvent(index, button) {
          return {
              index: index,
              button: button,
              cancel: false
          };
      }
      /**
      * Helper for dispatching events.
      *
      * @param  {string} evenType The type of the event to disptach.
      * @param  {object} instance The dialog instance disptaching the event.
      *
      * @return   {any}   The result of the invoked function.
      */
      function dispatchEvent(eventType, instance) {
          if ( typeof instance.get(eventType) === 'function' ) {
              return instance.get(eventType).call(instance);
          }
      }
  
  
      /**
       * Super class for all dialogs
       *
       * @return {Object}		base dialog prototype
       */
      var dialog = (function () {
          var //holds the list of used keys.
              usedKeys = [],
              //dummy variable, used to trigger dom reflow.
              reflow = null,
              //holds body tab index in case it has any.
              tabindex = false,
              //condition for detecting safari
              isSafari = window.navigator.userAgent.indexOf('Safari') > -1 && window.navigator.userAgent.indexOf('Chrome') < 0,
              //dialog building blocks
              templates = {
                  dimmer:'<div class="ajs-dimmer"></div>',
                  /*tab index required to fire click event before body focus*/
                  modal: '<div class="ajs-modal" tabindex="0"></div>',
                  dialog: '<div class="ajs-dialog" tabindex="0"></div>',
                  reset: '<button class="ajs-reset"></button>',
                  commands: '<div class="ajs-commands"><button class="ajs-pin"></button><button class="ajs-maximize"></button><button class="ajs-close"></button></div>',
                  header: '<div class="ajs-header"></div>',
                  body: '<div class="ajs-body"></div>',
                  content: '<div class="ajs-content"></div>',
                  footer: '<div class="ajs-footer"></div>',
                  buttons: { primary: '<div class="ajs-primary ajs-buttons"></div>', auxiliary: '<div class="ajs-auxiliary ajs-buttons"></div>' },
                  button: '<button class="ajs-button btn btn-outline-primary"></button>',
                  resizeHandle: '<div class="ajs-handle"></div>',
              },
              //common class names
              classes = {
                  animationIn: 'ajs-in',
                  animationOut: 'ajs-out',
                  base: 'alertify',
                  basic:'ajs-basic',
                  capture: 'ajs-capture',
                  closable:'ajs-closable',
                  fixed: 'ajs-fixed',
                  frameless:'ajs-frameless',
                  hidden: 'ajs-hidden',
                  maximize: 'ajs-maximize',
                  maximized: 'ajs-maximized',
                  maximizable:'ajs-maximizable',
                  modeless: 'ajs-modeless',
                  movable: 'ajs-movable',
                  noSelection: 'ajs-no-selection',
                  noOverflow: 'ajs-no-overflow',
                  noPadding:'ajs-no-padding',
                  pin:'ajs-pin',
                  pinnable:'ajs-pinnable',
                  prefix: 'ajs-',
                  resizable: 'ajs-resizable',
                  restore: 'ajs-restore',
                  shake:'ajs-shake',
                  unpinned:'ajs-unpinned',
              };
  
          /**
           * Helper: initializes the dialog instance
           * 
           * @return	{Number}	The total count of currently open modals.
           */
          function initialize(instance){
              
              if(!instance.__internal){
                  //invoke preinit global hook
                  alertify.defaults.hooks.preinit(instance);
                  //no need to expose init after this.
                  delete instance.__init;
                
                  //keep a copy of initial dialog settings
                  if(!instance.__settings){
                      instance.__settings = copy(instance.settings);
                  }
                  
                  //get dialog buttons/focus setup
                  var setup;
                  if(typeof instance.setup === 'function'){
                      setup = instance.setup();
                      setup.options = setup.options  || {};
                      setup.focus = setup.focus  || {};
                  }else{
                      setup = {
                          buttons:[],
                          focus:{
                              element:null,
                              select:false
                          },
                          options:{
                          }
                      };
                  }
                  
                  //initialize hooks object.
                  if(typeof instance.hooks !== 'object'){
                      instance.hooks = {};
                  }
  
                  //copy buttons defintion
                  var buttonsDefinition = [];
                  if(Array.isArray(setup.buttons)){
                      for(var b=0;b<setup.buttons.length;b+=1){
                          var ref  = setup.buttons[b],
                              cpy = {};
                          for (var i in ref) {
                              if (ref.hasOwnProperty(i)) {
                                  cpy[i] = ref[i];
                              }
                          }
                          buttonsDefinition.push(cpy);
                      }
                  }
  
                  var internal = instance.__internal = {
                      /**
                       * Flag holding the open state of the dialog
                       * 
                       * @type {Boolean}
                       */
                      isOpen:false,
                      /**
                       * Active element is the element that will receive focus after
                       * closing the dialog. It defaults as the body tag, but gets updated
                       * to the last focused element before the dialog was opened.
                       *
                       * @type {Node}
                       */
                      activeElement:document.body,
                      timerIn:undefined,
                      timerOut:undefined,
                      buttons: buttonsDefinition,
                      focus: setup.focus,
                      options: {
                          title: undefined,
                          modal: undefined,
                          basic:undefined,
                          frameless:undefined,
                          defaultFocusOff:undefined,
                          pinned: undefined,
                          movable: undefined,
                          moveBounded:undefined,
                          resizable: undefined,
                          autoReset: undefined,
                          closable: undefined,
                          closableByDimmer: undefined,
                          invokeOnCloseOff:undefined,
                          maximizable: undefined,
                          startMaximized: undefined,
                          pinnable: undefined,
                          transition: undefined,
                          padding:undefined,
                          overflow:undefined,
                          onshow:undefined,
                          onclosing:undefined,
                          onclose:undefined,
                          onfocus:undefined,
                          onmove:undefined,
                          onmoved:undefined,
                          onresize:undefined,
                          onresized:undefined,
                          onmaximize:undefined,
                          onmaximized:undefined,
                          onrestore:undefined,
                          onrestored:undefined
                      },
                      resetHandler:undefined,
                      beginMoveHandler:undefined,
                      beginResizeHandler:undefined,
                      bringToFrontHandler:undefined,
                      modalClickHandler:undefined,
                      buttonsClickHandler:undefined,
                      commandsClickHandler:undefined,
                      transitionInHandler:undefined,
                      transitionOutHandler:undefined,
                      destroy:undefined
                  };
  
                  var elements = {};
                  //root node
                  elements.root = document.createElement('div');
                  //prevent FOUC in case of async styles loading.
                  elements.root.style.display = 'none';
                  elements.root.className = classes.base + ' ' + classes.hidden + ' ';
  
                  elements.root.innerHTML = templates.dimmer + templates.modal;
                  
                  //dimmer
                  elements.dimmer = elements.root.firstChild;
  
                  //dialog
                  elements.modal = elements.root.lastChild;
                  elements.modal.innerHTML = templates.dialog;
                  elements.dialog = elements.modal.firstChild;
                  elements.dialog.innerHTML = templates.reset + templates.commands + templates.header + templates.body + templates.footer + templates.resizeHandle + templates.reset;
  
                  //reset links
                  elements.reset = [];
                  elements.reset.push(elements.dialog.firstChild);
                  elements.reset.push(elements.dialog.lastChild);
                  
                  //commands
                  elements.commands = {};
                  elements.commands.container = elements.reset[0].nextSibling;
                  elements.commands.pin = elements.commands.container.firstChild;
                  elements.commands.maximize = elements.commands.pin.nextSibling;
                  elements.commands.close = elements.commands.maximize.nextSibling;
                  
                  //header
                  elements.header = elements.commands.container.nextSibling;
  
                  //body
                  elements.body = elements.header.nextSibling;
                  elements.body.innerHTML = templates.content;
                  elements.content = elements.body.firstChild;
  
                  //footer
                  elements.footer = elements.body.nextSibling;
                  elements.footer.innerHTML = templates.buttons.auxiliary + templates.buttons.primary;
                  
                  //resize handle
                  elements.resizeHandle = elements.footer.nextSibling;
  
                  //buttons
                  elements.buttons = {};
                  elements.buttons.auxiliary = elements.footer.firstChild;
                  elements.buttons.primary = elements.buttons.auxiliary.nextSibling;
                  elements.buttons.primary.innerHTML = templates.button;
                  elements.buttonTemplate = elements.buttons.primary.firstChild;
                  //remove button template
                  elements.buttons.primary.removeChild(elements.buttonTemplate);
                                 
                  for(var x=0; x < instance.__internal.buttons.length; x+=1) {
                      var button = instance.__internal.buttons[x];
                      
                      // add to the list of used keys.
                      if(usedKeys.indexOf(button.key) < 0){
                          usedKeys.push(button.key);
                      }
  
                      button.element = elements.buttonTemplate.cloneNode();
                      button.element.innerHTML = button.text;
                      if(typeof button.className === 'string' &&  button.className !== ''){
                          addClass(button.element, button.className);
                      }
                      for(var key in button.attrs){
                          if(key !== 'className' && button.attrs.hasOwnProperty(key)){
                              button.element.setAttribute(key, button.attrs[key]);
                          }
                      }
                      if(button.scope === 'auxiliary'){
                          elements.buttons.auxiliary.appendChild(button.element);
                      }else{
                          elements.buttons.primary.appendChild(button.element);
                      }
                  }
                  //make elements pubic
                  instance.elements = elements;
                  
                  //save event handlers delegates
                  internal.resetHandler = delegate(instance, onReset);
                  internal.beginMoveHandler = delegate(instance, beginMove);
                  internal.beginResizeHandler = delegate(instance, beginResize);
                  internal.bringToFrontHandler = delegate(instance, bringToFront);
                  internal.modalClickHandler = delegate(instance, modalClickHandler);
                  internal.buttonsClickHandler = delegate(instance, buttonsClickHandler);
                  internal.commandsClickHandler = delegate(instance, commandsClickHandler);
                  internal.transitionInHandler = delegate(instance, handleTransitionInEvent);
                  internal.transitionOutHandler = delegate(instance, handleTransitionOutEvent);
  
                  //settings
                  for(var opKey in internal.options){
                      if(setup.options[opKey] !== undefined){
                          // if found in user options
                          instance.set(opKey, setup.options[opKey]);
                      }else if(alertify.defaults.hasOwnProperty(opKey)) {
                          // else if found in defaults options
                          instance.set(opKey, alertify.defaults[opKey]);
                      }else if(opKey === 'title' ) {
                          // else if title key, use alertify.defaults.glossary
                          instance.set(opKey, alertify.defaults.glossary[opKey]);
                      }
                  }
  
                  // allow dom customization
                  if(typeof instance.build === 'function'){
                      instance.build();
                  }
  
                  //invoke postinit global hook
                  alertify.defaults.hooks.postinit(instance);
              }
  
              //add to the end of the DOM tree.
              document.body.appendChild(instance.elements.root);
          }
  
          /**
           * Helper: maintains scroll position
           *
           */
          var scrollX, scrollY;
          function saveScrollPosition(){
              scrollX = getScrollLeft();
              scrollY = getScrollTop();
          }
          function restoreScrollPosition(){
              window.scrollTo(scrollX, scrollY);
          }
  
          /**
           * Helper: adds/removes no-overflow class from body
           *
           */
          function ensureNoOverflow(){
              var requiresNoOverflow = 0;
              for(var x=0;x<openDialogs.length;x+=1){
                  var instance = openDialogs[x];
                  if(instance.isModal() || instance.isMaximized()){
                      requiresNoOverflow+=1;
                  }
              }
              if(requiresNoOverflow === 0 && document.body.className.indexOf(classes.noOverflow) >= 0){
                  //last open modal or last maximized one
                  removeClass(document.body, classes.noOverflow);
                  preventBodyShift(false);
              }else if(requiresNoOverflow > 0 && document.body.className.indexOf(classes.noOverflow) < 0){
                  //first open modal or first maximized one
                  preventBodyShift(true);
                  addClass(document.body, classes.noOverflow);
              }
          }
          var top = '', topScroll = 0;
          /**
           * Helper: prevents body shift.
           *
           */
          function preventBodyShift(add){
              if(alertify.defaults.preventBodyShift){
                  if(add && document.documentElement.scrollHeight > document.documentElement.clientHeight ){//&& openDialogs[openDialogs.length-1].elements.dialog.clientHeight <= document.documentElement.clientHeight){
                      topScroll = scrollY;
                      top = window.getComputedStyle(document.body).top;
                      addClass(document.body, classes.fixed);
                      document.body.style.top = -scrollY + 'px';
                  } else if(!add) {
                      scrollY = topScroll;
                      document.body.style.top = top;
                      removeClass(document.body, classes.fixed);
                      restoreScrollPosition();
                  }
              }
          }
  		
          /**
           * Sets the name of the transition used to show/hide the dialog
           * 
           * @param {Object} instance The dilog instance.
           *
           */
          function updateTransition(instance, value, oldValue){
              if(typeof oldValue === 'string'){
                  removeClass(instance.elements.root,classes.prefix +  oldValue);
              }
              addClass(instance.elements.root, classes.prefix + value);
              reflow = instance.elements.root.offsetWidth;
          }
  		
          /**
           * Toggles the dialog display mode
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function updateDisplayMode(instance){
              if(instance.get('modal')){
  
                  //make modal
                  removeClass(instance.elements.root, classes.modeless);
  
                  //only if open
                  if(instance.isOpen()){
                      unbindModelessEvents(instance);
  
                      //in case a pinned modless dialog was made modal while open.
                      updateAbsPositionFix(instance);
  
                      ensureNoOverflow();
                  }
              }else{
                  //make modelss
                  addClass(instance.elements.root, classes.modeless);
  
                  //only if open
                  if(instance.isOpen()){
                      bindModelessEvents(instance);
  
                      //in case pin/unpin was called while a modal is open
                      updateAbsPositionFix(instance);
  
                      ensureNoOverflow();
                  }
              }
          }
  
          /**
           * Toggles the dialog basic view mode 
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function updateBasicMode(instance){
              if (instance.get('basic')) {
                  // add class
                  addClass(instance.elements.root, classes.basic);
              } else {
                  // remove class
                  removeClass(instance.elements.root, classes.basic);
              }
          }
  
          /**
           * Toggles the dialog frameless view mode 
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function updateFramelessMode(instance){
              if (instance.get('frameless')) {
                  // add class
                  addClass(instance.elements.root, classes.frameless);
              } else {
                  // remove class
                  removeClass(instance.elements.root, classes.frameless);
              }
          }
  		
          /**
           * Helper: Brings the modeless dialog to front, attached to modeless dialogs.
           *
           * @param {Event} event Focus event
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function bringToFront(event, instance){
              
              // Do not bring to front if preceeded by an open modal
              var index = openDialogs.indexOf(instance);
              for(var x=index+1;x<openDialogs.length;x+=1){
                  if(openDialogs[x].isModal()){
                      return;
                  }
              }
  			
              // Bring to front by making it the last child.
              if(document.body.lastChild !== instance.elements.root){
                  document.body.appendChild(instance.elements.root);
                  //also make sure its at the end of the list
                  openDialogs.splice(openDialogs.indexOf(instance),1);
                  openDialogs.push(instance);
                  setFocus(instance);
              }
  			
              return false;
          }
  		
          /**
           * Helper: reflects dialogs options updates
           *
           * @param {Object} instance The dilog instance.
           * @param {String} option The updated option name.
           *
           * @return	{undefined}	
           */
          function optionUpdated(instance, option, oldValue, newValue){
              switch(option){
              case 'title':
                  instance.setHeader(newValue);
                  break;
              case 'modal':
                  updateDisplayMode(instance);
                  break;
              case 'basic':
                  updateBasicMode(instance);
                  break;
              case 'frameless':
                  updateFramelessMode(instance);
                  break;
              case 'pinned':
                  updatePinned(instance);
                  break;
              case 'closable':
                  updateClosable(instance);
                  break;
              case 'maximizable':
                  updateMaximizable(instance);
                  break;
              case 'pinnable':
                  updatePinnable(instance);
                  break;
              case 'movable':
                  updateMovable(instance);
                  break;
              case 'resizable':
                  updateResizable(instance);
                  break;
              case 'padding':
                  if(newValue){
                      removeClass(instance.elements.root, classes.noPadding);
                  }else if(instance.elements.root.className.indexOf(classes.noPadding) < 0){
                      addClass(instance.elements.root, classes.noPadding);
                  }
                  break;
              case 'overflow':
                  if(newValue){
                      removeClass(instance.elements.root, classes.noOverflow);
                  }else if(instance.elements.root.className.indexOf(classes.noOverflow) < 0){
                      addClass(instance.elements.root, classes.noOverflow);
                  }
                  break;
              case 'transition':
                  updateTransition(instance,newValue, oldValue);
                  break;
              }
  
              // internal on option updated event
              if(typeof instance.hooks.onupdate === 'function'){
                  instance.hooks.onupdate.call(instance, option, oldValue, newValue);
              }
          }
  		
          /**
           * Helper: reflects dialogs options updates
           *
           * @param {Object} instance The dilog instance.
           * @param {Object} obj The object to set/get a value on/from.
           * @param {Function} callback The callback function to call if the key was found.
           * @param {String|Object} key A string specifying a propery name or a collection of key value pairs.
           * @param {Object} value Optional, the value associated with the key (in case it was a string).
           * @param {String} option The updated option name.
           *
           * @return	{Object} result object 
           *	The result objects has an 'op' property, indicating of this is a SET or GET operation.
           *		GET: 
           *		- found: a flag indicating if the key was found or not.
           *		- value: the property value.
           *		SET:
           *		- items: a list of key value pairs of the properties being set.
           *				each contains:
           *					- found: a flag indicating if the key was found or not.
           *					- key: the property key.
           *					- value: the property value.
           */
          function update(instance, obj, callback, key, value){
              var result = {op:undefined, items: [] };
              if(typeof value === 'undefined' && typeof key === 'string') {
                  //get
                  result.op = 'get';
                  if(obj.hasOwnProperty(key)){
                      result.found = true;
                      result.value = obj[key];
                  }else{
                      result.found = false;
                      result.value = undefined;
                  }
              }
              else
              {
                  var old;
                  //set
                  result.op = 'set';
                  if(typeof key === 'object'){
                      //set multiple
                      var args = key;
                      for (var prop in args) {
                          if (obj.hasOwnProperty(prop)) {
                              if(obj[prop] !== args[prop]){
                                  old = obj[prop];
                                  obj[prop] = args[prop];
                                  callback.call(instance,prop, old, args[prop]);
                              }
                              result.items.push({ 'key': prop, 'value': args[prop], 'found':true});
                          }else{
                              result.items.push({ 'key': prop, 'value': args[prop], 'found':false});
                          }
                      }
                  } else if (typeof key === 'string'){
                      //set single
                      if (obj.hasOwnProperty(key)) {
                          if(obj[key] !== value){
                              old  = obj[key];
                              obj[key] = value;
                              callback.call(instance,key, old, value);
                          }
                          result.items.push({'key': key, 'value': value , 'found':true});
  
                      }else{
                          result.items.push({'key': key, 'value': value , 'found':false});
                      }
                  } else {
                      //invalid params
                      throw new Error('args must be a string or object');
                  }
              }
              return result;
          }
  
  
          /**
           * Triggers a close event.
           *
           * @param {Object} instance	The dilog instance.
           * 
           * @return {undefined}
           */
          function triggerClose(instance) {
              var found;
              triggerCallback(instance, function (button) {
                  return found = instance.get('invokeOnCloseOff') !== true && (button.invokeOnClose === true);
              });
              //none of the buttons registered as onclose callback
              //close the dialog
              if (!found && instance.isOpen()) {
                  instance.close();
              }
          }
  
          /**
           * Dialogs commands event handler, attached to the dialog commands element.
           *
           * @param {Event} event	DOM event object.
           * @param {Object} instance	The dilog instance.
           * 
           * @return {undefined}
           */
          function commandsClickHandler(event, instance) {
              var target = event.srcElement || event.target;
              switch (target) {
              case instance.elements.commands.pin:
                  if (!instance.isPinned()) {
                      pin(instance);
                  } else {
                      unpin(instance);
                  }
                  break;
              case instance.elements.commands.maximize:
                  if (!instance.isMaximized()) {
                      maximize(instance);
                  } else {
                      restore(instance);
                  }
                  break;
              case instance.elements.commands.close:
                  triggerClose(instance);
                  break;
              }
              return false;
          }
  
          /**
           * Helper: pins the modeless dialog.
           *
           * @param {Object} instance	The dialog instance.
           * 
           * @return {undefined}
           */
          function pin(instance) {
              //pin the dialog
              instance.set('pinned', true);
          }
  
          /**
           * Helper: unpins the modeless dialog.
           *
           * @param {Object} instance	The dilog instance.
           * 
           * @return {undefined}
           */
          function unpin(instance) {
              //unpin the dialog 
              instance.set('pinned', false);
          }
  
  
          /**
           * Helper: enlarges the dialog to fill the entire screen.
           *
           * @param {Object} instance	The dilog instance.
           * 
           * @return {undefined}
           */
          function maximize(instance) {
              // allow custom `onmaximize` method
              dispatchEvent('onmaximize', instance);
              //maximize the dialog 
              addClass(instance.elements.root, classes.maximized);
              if (instance.isOpen()) {
                  ensureNoOverflow();
              }
              // allow custom `onmaximized` method
              dispatchEvent('onmaximized', instance);
          }
  
          /**
           * Helper: returns the dialog to its former size.
           *
           * @param {Object} instance	The dilog instance.
           * 
           * @return {undefined}
           */
          function restore(instance) {
              // allow custom `onrestore` method
              dispatchEvent('onrestore', instance);
              //maximize the dialog 
              removeClass(instance.elements.root, classes.maximized);
              if (instance.isOpen()) {
                  ensureNoOverflow();
              }
              // allow custom `onrestored` method
              dispatchEvent('onrestored', instance);
          }
  
          /**
           * Show or hide the maximize box.
           *
           * @param {Object} instance The dilog instance.
           * @param {Boolean} on True to add the behavior, removes it otherwise.
           *
           * @return {undefined}
           */
          function updatePinnable(instance) {
              if (instance.get('pinnable')) {
                  // add class
                  addClass(instance.elements.root, classes.pinnable);
              } else {
                  // remove class
                  removeClass(instance.elements.root, classes.pinnable);
              }
          }
  
          /**
           * Helper: Fixes the absolutly positioned modal div position.
           *
           * @param {Object} instance The dialog instance.
           *
           * @return {undefined}
           */
          function addAbsPositionFix(instance) {
              var scrollLeft = getScrollLeft();
              instance.elements.modal.style.marginTop = getScrollTop() + 'px';
              instance.elements.modal.style.marginLeft = scrollLeft + 'px';
              instance.elements.modal.style.marginRight = (-scrollLeft) + 'px';
          }
  
          /**
           * Helper: Removes the absolutly positioned modal div position fix.
           *
           * @param {Object} instance The dialog instance.
           *
           * @return {undefined}
           */
          function removeAbsPositionFix(instance) {
              var marginTop = parseInt(instance.elements.modal.style.marginTop, 10);
              var marginLeft = parseInt(instance.elements.modal.style.marginLeft, 10);
              instance.elements.modal.style.marginTop = '';
              instance.elements.modal.style.marginLeft = '';
              instance.elements.modal.style.marginRight = '';
  
              if (instance.isOpen()) {
                  var top = 0,
                      left = 0
                  ;
                  if (instance.elements.dialog.style.top !== '') {
                      top = parseInt(instance.elements.dialog.style.top, 10);
                  }
                  instance.elements.dialog.style.top = (top + (marginTop - getScrollTop())) + 'px';
  
                  if (instance.elements.dialog.style.left !== '') {
                      left = parseInt(instance.elements.dialog.style.left, 10);
                  }
                  instance.elements.dialog.style.left = (left + (marginLeft - getScrollLeft())) + 'px';
              }
          }
          /**
           * Helper: Adds/Removes the absolutly positioned modal div position fix based on its pinned setting.
           *
           * @param {Object} instance The dialog instance.
           *
           * @return {undefined}
           */
          function updateAbsPositionFix(instance) {
              // if modeless and unpinned add fix
              if (!instance.get('modal') && !instance.get('pinned')) {
                  addAbsPositionFix(instance);
              } else {
                  removeAbsPositionFix(instance);
              }
          }
          /**
           * Toggles the dialog position lock | modeless only.
           *
           * @param {Object} instance The dilog instance.
           * @param {Boolean} on True to make it modal, false otherwise.
           *
           * @return {undefined}
           */
          function updatePinned(instance) {
              if (instance.get('pinned')) {
                  removeClass(instance.elements.root, classes.unpinned);
                  if (instance.isOpen()) {
                      removeAbsPositionFix(instance);
                  }
              } else {
                  addClass(instance.elements.root, classes.unpinned);
                  if (instance.isOpen() && !instance.isModal()) {
                      addAbsPositionFix(instance);
                  }
              }
          }
  
          /**
           * Show or hide the maximize box.
           *
           * @param {Object} instance The dilog instance.
           * @param {Boolean} on True to add the behavior, removes it otherwise.
           *
           * @return {undefined}
           */
          function updateMaximizable(instance) {
              if (instance.get('maximizable')) {
                  // add class
                  addClass(instance.elements.root, classes.maximizable);
              } else {
                  // remove class
                  removeClass(instance.elements.root, classes.maximizable);
              }
          }
  
          /**
           * Show or hide the close box.
           *
           * @param {Object} instance The dilog instance.
           * @param {Boolean} on True to add the behavior, removes it otherwise.
           *
           * @return {undefined}
           */
          function updateClosable(instance) {
              if (instance.get('closable')) {
                  // add class
                  addClass(instance.elements.root, classes.closable);
                  bindClosableEvents(instance);
              } else {
                  // remove class
                  removeClass(instance.elements.root, classes.closable);
                  unbindClosableEvents(instance);
              }
          }
  
          
          var cancelClick = false,// flag to cancel click event if already handled by end resize event (the mousedown, mousemove, mouseup sequence fires a click event.).
              modalClickHandlerTS=0 // stores last click timestamp to prevent executing the handler twice on double click.
              ;
  
          /**
           * Helper: closes the modal dialog when clicking the modal
           *
           * @param {Event} event	DOM event object.
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function modalClickHandler(event, instance) {
              if(event.timeStamp - modalClickHandlerTS > 200 && (modalClickHandlerTS = event.timeStamp) && !cancelClick){
                  var target = event.srcElement || event.target;
                  if (instance.get('closableByDimmer') === true && target === instance.elements.modal) {
                      triggerClose(instance);
                  }
                  cancelClick = false;
                  return false;
              }
          }
  
          // stores last call timestamp to prevent triggering the callback twice.
          var callbackTS = 0;
          // flag to cancel keyup event if already handled by click event (pressing Enter on a focusted button).
          var cancelKeyup = false;
          /** 
           * Helper: triggers a button callback
           *
           * @param {Object}		The dilog instance.
           * @param {Function}	Callback to check which button triggered the event.
           *
           * @return {undefined}
           */
          function triggerCallback(instance, check) {
              if(Date.now() - callbackTS > 200 && (callbackTS = Date.now())){
                  for (var idx = 0; idx < instance.__internal.buttons.length; idx += 1) {
                      var button = instance.__internal.buttons[idx];
                      if (!button.element.disabled && check(button)) {
                          var closeEvent = createCloseEvent(idx, button);
                          if (typeof instance.callback === 'function') {
                              instance.callback.apply(instance, [closeEvent]);
                          }
                          //close the dialog only if not canceled.
                          if (closeEvent.cancel === false) {
                              instance.close();
                          }
                          break;
                      }
                  }
              }
          }
  
          /**
           * Clicks event handler, attached to the dialog footer.
           *
           * @param {Event}		DOM event object.
           * @param {Object}		The dilog instance.
           * 
           * @return {undefined}
           */
          function buttonsClickHandler(event, instance) {
              var target = event.srcElement || event.target;
              triggerCallback(instance, function (button) {
                  // if this button caused the click, cancel keyup event
                  return button.element === target && (cancelKeyup = true);
              });
          }
  
          /**
           * Keyup event handler, attached to the document.body
           *
           * @param {Event}		DOM event object.
           * @param {Object}		The dilog instance.
           * 
           * @return {undefined}
           */
          function keyupHandler(event) {
              //hitting enter while button has focus will trigger keyup too.
              //ignore if handled by clickHandler
              if (cancelKeyup) {
                  cancelKeyup = false;
                  return;
              }
              var instance = openDialogs[openDialogs.length - 1];
              var keyCode = event.keyCode;
              if (instance.__internal.buttons.length === 0 && keyCode === keys.ESC && instance.get('closable') === true) {
                  triggerClose(instance);
                  return false;
              }else if (usedKeys.indexOf(keyCode) > -1) {
                  triggerCallback(instance, function (button) {
                      return button.key === keyCode;
                  });
                  return false;
              }
          }
          /**
          * Keydown event handler, attached to the document.body
          *
          * @param {Event}		DOM event object.
          * @param {Object}		The dilog instance.
          * 
          * @return {undefined}
          */
          function keydownHandler(event) {
              var instance = openDialogs[openDialogs.length - 1];
              var keyCode = event.keyCode;
              if (keyCode === keys.LEFT || keyCode === keys.RIGHT) {
                  var buttons = instance.__internal.buttons;
                  for (var x = 0; x < buttons.length; x += 1) {
                      if (document.activeElement === buttons[x].element) {
                          switch (keyCode) {
                          case keys.LEFT:
                              buttons[(x || buttons.length) - 1].element.focus();
                              return;
                          case keys.RIGHT:
                              buttons[(x + 1) % buttons.length].element.focus();
                              return;
                          }
                      }
                  }
              }else if (keyCode < keys.F12 + 1 && keyCode > keys.F1 - 1 && usedKeys.indexOf(keyCode) > -1) {
                  event.preventDefault();
                  event.stopPropagation();
                  triggerCallback(instance, function (button) {
                      return button.key === keyCode;
                  });
                  return false;
              }
          }
  
  
          /**
           * Sets focus to proper dialog element
           *
           * @param {Object} instance The dilog instance.
           * @param {Node} [resetTarget=undefined] DOM element to reset focus to.
           *
           * @return {undefined}
           */
          function setFocus(instance, resetTarget) {
              // reset target has already been determined.
              if (resetTarget) {
                  resetTarget.focus();
              } else {
                  // current instance focus settings
                  var focus = instance.__internal.focus;
                  // the focus element.
                  var element = focus.element;
  
                  switch (typeof focus.element) {
                  // a number means a button index
                  case 'number':
                      if (instance.__internal.buttons.length > focus.element) {
                          //in basic view, skip focusing the buttons.
                          if (instance.get('basic') === true) {
                              element = instance.elements.reset[0];
                          } else {
                              element = instance.__internal.buttons[focus.element].element;
                          }
                      }
                      break;
                  // a string means querySelector to select from dialog body contents.
                  case 'string':
                      element = instance.elements.body.querySelector(focus.element);
                      break;
                  // a function should return the focus element.
                  case 'function':
                      element = focus.element.call(instance);
                      break;
                  }
  
                  // if no focus element, default to first reset element.
                  if (instance.get('defaultFocusOff') === true || ((typeof element === 'undefined' || element === null) && instance.__internal.buttons.length === 0)) {
                      element = instance.elements.reset[0];
                  }
                  // focus
                  if (element && element.focus) {
                      element.focus();
                      // if selectable
                      if (focus.select && element.select) {
                          element.select();
                      }
                  }
              }
          }
  
          /**
           * Focus event handler, attached to document.body and dialogs own reset links.
           * handles the focus for modal dialogs only.
           *
           * @param {Event} event DOM focus event object.
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function onReset(event, instance) {
  
              // should work on last modal if triggered from document.body 
              if (!instance) {
                  for (var x = openDialogs.length - 1; x > -1; x -= 1) {
                      if (openDialogs[x].isModal()) {
                          instance = openDialogs[x];
                          break;
                      }
                  }
              }
  
              if(instance) {
                  // if modal
                  if (instance.isModal()) {
                      // determine reset target to enable forward/backward tab cycle.
                      var firstReset = instance.elements.reset[0],
                          lastReset = instance.elements.reset[1],
                          lastFocusedElement = event.relatedTarget,
                          within = instance.elements.root.contains(lastFocusedElement),
                          target = event.srcElement || event.target,
                          resetTarget;
  
                      //if the previous focused element element was outside the modal do nthing
                      if(  /*first show */
                          (target === firstReset && !within) ||
                           /*focus cycle */
                          (target === lastReset && lastFocusedElement == firstReset))
                          return
                      else if(target === lastReset || target === document.body)
                          resetTarget = firstReset
                      else if(target === firstReset && lastFocusedElement == lastReset){
                          resetTarget = findTabbable(instance)
                      }else if(target == firstReset && within){
                          resetTarget = findTabbable(instance, true)
                      }
                      // focus
                      setFocus(instance, resetTarget);
                  }
              }
          }
          function findTabbable(instance, last){
              var tabbables = [].slice.call(instance.elements.dialog.querySelectorAll(defaults.tabbable));
              last && tabbables.reverse()
              for(var x=0;x<tabbables.length;x++){
                  var tabbable = tabbables[x]
                  //check if visible
                  if(!!(tabbable.offsetParent || tabbable.offsetWidth || tabbable.offsetHeight || tabbable.getClientRects().length)){
                      return tabbable
                  }
              }
          }
          function recycleTab(event) {
              var instance = openDialogs[openDialogs.length - 1];
              if (instance && event.shiftKey && event.keyCode === keys.TAB) {
                  instance.elements.reset[1].focus()
              }
          }
          /**
           * Transition in transitionend event handler. 
           *
           * @param {Event}		TransitionEnd event object.
           * @param {Object}		The dilog instance.
           *
           * @return {undefined}
           */
          function handleTransitionInEvent(event, instance) {
              // clear the timer
              clearTimeout(instance.__internal.timerIn);
  
              // once transition is complete, set focus
              setFocus(instance);
  
              //restore scroll to prevent document jump
              restoreScrollPosition();
  
              // allow handling key up after transition ended.
              cancelKeyup = false;
  
              // allow custom `onfocus` method
              dispatchEvent('onfocus', instance);
  
              // unbind the event
              off(instance.elements.dialog, transition.type, instance.__internal.transitionInHandler);
  
              removeClass(instance.elements.root, classes.animationIn);
          }
  
          /**
           * Transition out transitionend event handler. 
           *
           * @param {Event}		TransitionEnd event object.
           * @param {Object}		The dilog instance.
           *
           * @return {undefined}
           */
          function handleTransitionOutEvent(event, instance) {
              // clear the timer
              clearTimeout(instance.__internal.timerOut);
              // unbind the event
              off(instance.elements.dialog, transition.type, instance.__internal.transitionOutHandler);
  
              // reset move updates
              resetMove(instance);
              // reset resize updates
              resetResize(instance);
  
              // restore if maximized
              if (instance.isMaximized() && !instance.get('startMaximized')) {
                  restore(instance);
              }
  
              // return focus to the last active element
              if (alertify.defaults.maintainFocus && instance.__internal.activeElement) {
                  instance.__internal.activeElement.focus();
                  instance.__internal.activeElement = null;
              }
              
              //destory the instance
              if (typeof instance.__internal.destroy === 'function') {
                  instance.__internal.destroy.apply(instance);
              }
          }
          /* Controls moving a dialog around */
          //holde the current moving instance
          var movable = null,
              //holds the current X offset when move starts
              offsetX = 0,
              //holds the current Y offset when move starts
              offsetY = 0,
              xProp = 'pageX',
              yProp = 'pageY',
              bounds = null,
              refreshTop = false,
              moveDelegate = null
          ;
  
          /**
           * Helper: sets the element top/left coordinates
           *
           * @param {Event} event	DOM event object.
           * @param {Node} element The element being moved.
           * 
           * @return {undefined}
           */
          function moveElement(event, element) {
              var left = (event[xProp] - offsetX),
                  top  = (event[yProp] - offsetY);
  
              if(refreshTop){
                  top -= document.body.scrollTop;
              }
             
              element.style.left = left + 'px';
              element.style.top = top + 'px';
             
          }
          /**
           * Helper: sets the element top/left coordinates within screen bounds
           *
           * @param {Event} event	DOM event object.
           * @param {Node} element The element being moved.
           * 
           * @return {undefined}
           */
          function moveElementBounded(event, element) {
              var left = (event[xProp] - offsetX),
                  top  = (event[yProp] - offsetY);
  
              if(refreshTop){
                  top -= document.body.scrollTop;
              }
              
              element.style.left = Math.min(bounds.maxLeft, Math.max(bounds.minLeft, left)) + 'px';
              if(refreshTop){
                  element.style.top = Math.min(bounds.maxTop, Math.max(bounds.minTop, top)) + 'px';
              }else{
                  element.style.top = Math.max(bounds.minTop, top) + 'px';
              }
          }
              
  
          /**
           * Triggers the start of a move event, attached to the header element mouse down event.
           * Adds no-selection class to the body, disabling selection while moving.
           *
           * @param {Event} event	DOM event object.
           * @param {Object} instance The dilog instance.
           * 
           * @return {Boolean} false
           */
          function beginMove(event, instance) {
              if (resizable === null && !instance.isMaximized() && instance.get('movable')) {
                  var eventSrc, left=0, top=0;
                  if (event.type === 'touchstart') {
                      event.preventDefault();
                      eventSrc = event.targetTouches[0];
                      xProp = 'clientX';
                      yProp = 'clientY';
                  } else if (event.button === 0) {
                      eventSrc = event;
                  }
  
                  if (eventSrc) {
  
                      var element = instance.elements.dialog;
                      addClass(element, classes.capture);
  
                      if (element.style.left) {
                          left = parseInt(element.style.left, 10);
                      }
  
                      if (element.style.top) {
                          top = parseInt(element.style.top, 10);
                      }
                      
                      offsetX = eventSrc[xProp] - left;
                      offsetY = eventSrc[yProp] - top;
  
                      if(instance.isModal()){
                          offsetY += instance.elements.modal.scrollTop;
                      }else if(instance.isPinned()){
                          offsetY -= document.body.scrollTop;
                      }
                      
                      if(instance.get('moveBounded')){
                          var current = element,
                              offsetLeft = -left,
                              offsetTop = -top;
                          
                          //calc offset
                          do {
                              offsetLeft += current.offsetLeft;
                              offsetTop += current.offsetTop;
                          } while (current = current.offsetParent);
                          
                          bounds = {
                              maxLeft : offsetLeft,
                              minLeft : -offsetLeft,
                              maxTop  : document.documentElement.clientHeight - element.clientHeight - offsetTop,
                              minTop  : -offsetTop
                          };
                          moveDelegate = moveElementBounded;
                      }else{
                          bounds = null;
                          moveDelegate = moveElement;
                      }
                      
                      // allow custom `onmove` method
                      dispatchEvent('onmove', instance);
  
                      refreshTop = !instance.isModal() && instance.isPinned();
                      movable = instance;
                      moveDelegate(eventSrc, element);
                      addClass(document.body, classes.noSelection);
                      return false;
                  }
              }
          }
  
          /**
           * The actual move handler,  attached to document.body mousemove event.
           *
           * @param {Event} event	DOM event object.
           * 
           * @return {undefined}
           */
          function move(event) {
              if (movable) {
                  var eventSrc;
                  if (event.type === 'touchmove') {
                      event.preventDefault();
                      eventSrc = event.targetTouches[0];
                  } else if (event.button === 0) {
                      eventSrc = event;
                  }
                  if (eventSrc) {
                      moveDelegate(eventSrc, movable.elements.dialog);
                  }
              }
          }
  
          /**
           * Triggers the end of a move event,  attached to document.body mouseup event.
           * Removes no-selection class from document.body, allowing selection.
           *
           * @return {undefined}
           */
          function endMove() {
              if (movable) {
                  var instance = movable;
                  movable = bounds = null;
                  removeClass(document.body, classes.noSelection);
                  removeClass(instance.elements.dialog, classes.capture);
                  // allow custom `onmoved` method
                  dispatchEvent('onmoved', instance);
              }
          }
  
          /**
           * Resets any changes made by moving the element to its original state,
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function resetMove(instance) {
              movable = null;
              var element = instance.elements.dialog;
              element.style.left = element.style.top = '';
          }
  
          /**
           * Updates the dialog move behavior.
           *
           * @param {Object} instance The dilog instance.
           * @param {Boolean} on True to add the behavior, removes it otherwise.
           *
           * @return {undefined}
           */
          function updateMovable(instance) {
              if (instance.get('movable')) {
                  // add class
                  addClass(instance.elements.root, classes.movable);
                  if (instance.isOpen()) {
                      bindMovableEvents(instance);
                  }
              } else {
  
                  //reset
                  resetMove(instance);
                  // remove class
                  removeClass(instance.elements.root, classes.movable);
                  if (instance.isOpen()) {
                      unbindMovableEvents(instance);
                  }
              }
          }
  
          /* Controls moving a dialog around */
          //holde the current instance being resized		
          var resizable = null,
              //holds the staring left offset when resize starts.
              startingLeft = Number.Nan,
              //holds the staring width when resize starts.
              startingWidth = 0,
              //holds the initial width when resized for the first time.
              minWidth = 0,
              //holds the offset of the resize handle.
              handleOffset = 0
          ;
  
          /**
           * Helper: sets the element width/height and updates left coordinate if neccessary.
           *
           * @param {Event} event	DOM mousemove event object.
           * @param {Node} element The element being moved.
           * @param {Boolean} pinned A flag indicating if the element being resized is pinned to the screen.
           * 
           * @return {undefined}
           */
          function resizeElement(event, element, pageRelative) {
  
              //calculate offsets from 0,0
              var current = element;
              var offsetLeft = 0;
              var offsetTop = 0;
              do {
                  offsetLeft += current.offsetLeft;
                  offsetTop += current.offsetTop;
              } while (current = current.offsetParent);
  
              // determine X,Y coordinates.
              var X, Y;
              if (pageRelative === true) {
                  X = event.pageX;
                  Y = event.pageY;
              } else {
                  X = event.clientX;
                  Y = event.clientY;
              }
              // rtl handling
              var isRTL = isRightToLeft();
              if (isRTL) {
                  // reverse X 
                  X = document.body.offsetWidth - X;
                  // if has a starting left, calculate offsetRight
                  if (!isNaN(startingLeft)) {
                      offsetLeft = document.body.offsetWidth - offsetLeft - element.offsetWidth;
                  }
              }
  
              // set width/height
              element.style.height = (Y - offsetTop + handleOffset) + 'px';
              element.style.width = (X - offsetLeft + handleOffset) + 'px';
  
              // if the element being resized has a starting left, maintain it.
              // the dialog is centered, divide by half the offset to maintain the margins.
              if (!isNaN(startingLeft)) {
                  var diff = Math.abs(element.offsetWidth - startingWidth) * 0.5;
                  if (isRTL) {
                      //negate the diff, why?
                      //when growing it should decrease left
                      //when shrinking it should increase left
                      diff *= -1;
                  }
                  if (element.offsetWidth > startingWidth) {
                      //growing
                      element.style.left = (startingLeft + diff) + 'px';
                  } else if (element.offsetWidth >= minWidth) {
                      //shrinking
                      element.style.left = (startingLeft - diff) + 'px';
                  }
              }
          }
  
          /**
           * Triggers the start of a resize event, attached to the resize handle element mouse down event.
           * Adds no-selection class to the body, disabling selection while moving.
           *
           * @param {Event} event	DOM event object.
           * @param {Object} instance The dilog instance.
           * 
           * @return {Boolean} false
           */
          function beginResize(event, instance) {
              if (!instance.isMaximized()) {
                  var eventSrc;
                  if (event.type === 'touchstart') {
                      event.preventDefault();
                      eventSrc = event.targetTouches[0];
                  } else if (event.button === 0) {
                      eventSrc = event;
                  }
                  if (eventSrc) {
                      // allow custom `onresize` method
                      dispatchEvent('onresize', instance);
                      
                      resizable = instance;
                      handleOffset = instance.elements.resizeHandle.offsetHeight / 2;
                      var element = instance.elements.dialog;
                      addClass(element, classes.capture);
                      startingLeft = parseInt(element.style.left, 10);
                      element.style.height = element.offsetHeight + 'px';
                      element.style.minHeight = instance.elements.header.offsetHeight + instance.elements.footer.offsetHeight + 'px';
                      element.style.width = (startingWidth = element.offsetWidth) + 'px';
  
                      if (element.style.maxWidth !== 'none') {
                          element.style.minWidth = (minWidth = element.offsetWidth) + 'px';
                      }
                      element.style.maxWidth = 'none';
                      addClass(document.body, classes.noSelection);
                      return false;
                  }
              }
          }
  
          /**
           * The actual resize handler,  attached to document.body mousemove event.
           *
           * @param {Event} event	DOM event object.
           * 
           * @return {undefined}
           */
          function resize(event) {
              if (resizable) {
                  var eventSrc;
                  if (event.type === 'touchmove') {
                      event.preventDefault();
                      eventSrc = event.targetTouches[0];
                  } else if (event.button === 0) {
                      eventSrc = event;
                  }
                  if (eventSrc) {
                      resizeElement(eventSrc, resizable.elements.dialog, !resizable.get('modal') && !resizable.get('pinned'));
                  }
              }
          }
  
          /**
           * Triggers the end of a resize event,  attached to document.body mouseup event.
           * Removes no-selection class from document.body, allowing selection.
           *
           * @return {undefined}
           */
          function endResize() {
              if (resizable) {
                  var instance = resizable;
                  resizable = null;
                  removeClass(document.body, classes.noSelection);
                  removeClass(instance.elements.dialog, classes.capture);
                  cancelClick = true;
                  // allow custom `onresized` method
                  dispatchEvent('onresized', instance);
              }
          }
  
          /**
           * Resets any changes made by resizing the element to its original state.
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function resetResize(instance) {
              resizable = null;
              var element = instance.elements.dialog;
              if (element.style.maxWidth === 'none') {
                  //clear inline styles.
                  element.style.maxWidth = element.style.minWidth = element.style.width = element.style.height = element.style.minHeight = element.style.left = '';
                  //reset variables.
                  startingLeft = Number.Nan;
                  startingWidth = minWidth = handleOffset = 0;
              }
          }
  
  
          /**
           * Updates the dialog move behavior.
           *
           * @param {Object} instance The dilog instance.
           * @param {Boolean} on True to add the behavior, removes it otherwise.
           *
           * @return {undefined}
           */
          function updateResizable(instance) {
              if (instance.get('resizable')) {
                  // add class
                  addClass(instance.elements.root, classes.resizable);
                  if (instance.isOpen()) {
                      bindResizableEvents(instance);
                  }
              } else {
                  //reset
                  resetResize(instance);
                  // remove class
                  removeClass(instance.elements.root, classes.resizable);
                  if (instance.isOpen()) {
                      unbindResizableEvents(instance);
                  }
              }
          }
  
          /**
           * Reset move/resize on window resize.
           *
           * @param {Event} event	window resize event object.
           *
           * @return {undefined}
           */
          function windowResize(/*event*/) {
              for (var x = 0; x < openDialogs.length; x += 1) {
                  var instance = openDialogs[x];
                  if (instance.get('autoReset')) {
                      resetMove(instance);
                      resetResize(instance);
                  }
              }
          }
          /**
           * Bind dialogs events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function bindEvents(instance) {
              // if first dialog, hook global handlers
              if (openDialogs.length === 1) {
                  //global
                  on(window, 'resize', windowResize);
                  on(document.body, 'keyup', keyupHandler);
                  on(document.body, 'keydown', keydownHandler);
                  on(document.body, 'focus', onReset);
  
                  //move
                  on(document.documentElement, 'mousemove', move);
                  on(document.documentElement, 'touchmove', move);
                  on(document.documentElement, 'mouseup', endMove);
                  on(document.documentElement, 'touchend', endMove);
                  //resize
                  on(document.documentElement, 'mousemove', resize);
                  on(document.documentElement, 'touchmove', resize);
                  on(document.documentElement, 'mouseup', endResize);
                  on(document.documentElement, 'touchend', endResize);
              }
  
              // common events
              on(instance.elements.commands.container, 'click', instance.__internal.commandsClickHandler);
              on(instance.elements.footer, 'click', instance.__internal.buttonsClickHandler);
              on(instance.elements.reset[0], 'focusin', instance.__internal.resetHandler);
              on(instance.elements.reset[0], 'keydown', recycleTab);
              on(instance.elements.reset[1], 'focusin', instance.__internal.resetHandler);
  
              //prevent handling key up when dialog is being opened by a key stroke.
              cancelKeyup = true;
              // hook in transition handler
              on(instance.elements.dialog, transition.type, instance.__internal.transitionInHandler);
  
              // modelss only events
              if (!instance.get('modal')) {
                  bindModelessEvents(instance);
              }
  
              // resizable
              if (instance.get('resizable')) {
                  bindResizableEvents(instance);
              }
  
              // movable
              if (instance.get('movable')) {
                  bindMovableEvents(instance);
              }
          }
  
          /**
           * Unbind dialogs events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function unbindEvents(instance) {
              // if last dialog, remove global handlers
              if (openDialogs.length === 1) {
                  //global
                  off(window, 'resize', windowResize);
                  off(document.body, 'keyup', keyupHandler);
                  off(document.body, 'keydown', keydownHandler);
                  off(document.body, 'focus', onReset);
                  //move
                  off(document.documentElement, 'mousemove', move);
                  off(document.documentElement, 'mouseup', endMove);
                  //resize
                  off(document.documentElement, 'mousemove', resize);
                  off(document.documentElement, 'mouseup', endResize);
              }
  
              // common events
              off(instance.elements.commands.container, 'click', instance.__internal.commandsClickHandler);
              off(instance.elements.footer, 'click', instance.__internal.buttonsClickHandler);
              off(instance.elements.reset[0], 'focusin', instance.__internal.resetHandler);
              off(instance.elements.reset[0], 'keydown', recycleTab);
              off(instance.elements.reset[1], 'focusin', instance.__internal.resetHandler);
  
              // hook out transition handler
              on(instance.elements.dialog, transition.type, instance.__internal.transitionOutHandler);
  
              // modelss only events
              if (!instance.get('modal')) {
                  unbindModelessEvents(instance);
              }
  
              // movable
              if (instance.get('movable')) {
                  unbindMovableEvents(instance);
              }
  
              // resizable
              if (instance.get('resizable')) {
                  unbindResizableEvents(instance);
              }
  
          }
  
          /**
           * Bind modeless specific events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function bindModelessEvents(instance) {
              on(instance.elements.dialog, 'focus', instance.__internal.bringToFrontHandler, true);
          }
  
          /**
           * Unbind modeless specific events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function unbindModelessEvents(instance) {
              off(instance.elements.dialog, 'focus', instance.__internal.bringToFrontHandler, true);
          }
  
  
  
          /**
           * Bind movable specific events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function bindMovableEvents(instance) {
              on(instance.elements.header, 'mousedown', instance.__internal.beginMoveHandler);
              on(instance.elements.header, 'touchstart', instance.__internal.beginMoveHandler);
          }
  
          /**
           * Unbind movable specific events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function unbindMovableEvents(instance) {
              off(instance.elements.header, 'mousedown', instance.__internal.beginMoveHandler);
              off(instance.elements.header, 'touchstart', instance.__internal.beginMoveHandler);
          }
  
  
  
          /**
           * Bind resizable specific events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function bindResizableEvents(instance) {
              on(instance.elements.resizeHandle, 'mousedown', instance.__internal.beginResizeHandler);
              on(instance.elements.resizeHandle, 'touchstart', instance.__internal.beginResizeHandler);
          }
  
          /**
           * Unbind resizable specific events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function unbindResizableEvents(instance) {
              off(instance.elements.resizeHandle, 'mousedown', instance.__internal.beginResizeHandler);
              off(instance.elements.resizeHandle, 'touchstart', instance.__internal.beginResizeHandler);
          }
  
          /**
           * Bind closable events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function bindClosableEvents(instance) {
              on(instance.elements.modal, 'click', instance.__internal.modalClickHandler);
          }
  
          /**
           * Unbind closable specific events
           *
           * @param {Object} instance The dilog instance.
           *
           * @return {undefined}
           */
          function unbindClosableEvents(instance) {
              off(instance.elements.modal, 'click', instance.__internal.modalClickHandler);
          }
          // dialog API
          return {
              __init:initialize,
              /**
               * Check if dialog is currently open
               *
               * @return {Boolean}
               */
              isOpen: function () {
                  return this.__internal.isOpen;
              },
              isModal: function (){
                  return this.elements.root.className.indexOf(classes.modeless) < 0;
              },
              isMaximized:function(){
                  return this.elements.root.className.indexOf(classes.maximized) > -1;
              },
              isPinned:function(){
                  return this.elements.root.className.indexOf(classes.unpinned) < 0;
              },
              maximize:function(){
                  if(!this.isMaximized()){
                      maximize(this);
                  }
                  return this;
              },
              restore:function(){
                  if(this.isMaximized()){
                      restore(this);
                  }
                  return this;
              },
              pin:function(){
                  if(!this.isPinned()){
                      pin(this);
                  }
                  return this;
              },
              unpin:function(){
                  if(this.isPinned()){
                      unpin(this);
                  }
                  return this;
              },
              bringToFront:function(){
                  bringToFront(null, this);
                  return this;
              },
              /**
               * Move the dialog to a specific x/y coordinates
               *
               * @param {Number} x    The new dialog x coordinate in pixels.
               * @param {Number} y    The new dialog y coordinate in pixels.
               *
               * @return {Object} The dialog instance.
               */
              moveTo:function(x,y){
                  if(!isNaN(x) && !isNaN(y)){
                      // allow custom `onmove` method
                      dispatchEvent('onmove', this);
                      
                      var element = this.elements.dialog,
                          current = element,
                          offsetLeft = 0,
                          offsetTop = 0;
                      
                      //subtract existing left,top
                      if (element.style.left) {
                          offsetLeft -= parseInt(element.style.left, 10);
                      }
                      if (element.style.top) {
                          offsetTop -= parseInt(element.style.top, 10);
                      }
                      //calc offset
                      do {
                          offsetLeft += current.offsetLeft;
                          offsetTop += current.offsetTop;
                      } while (current = current.offsetParent);
  
                      //calc left, top
                      var left = (x - offsetLeft);
                      var top  = (y - offsetTop);
  
                      //// rtl handling
                      if (isRightToLeft()) {
                          left *= -1;
                      }
  
                      element.style.left = left + 'px';
                      element.style.top = top + 'px';
                      
                      // allow custom `onmoved` method
                      dispatchEvent('onmoved', this);
                  }
                  return this;
              },
              /**
               * Resize the dialog to a specific width/height (the dialog must be 'resizable').
               * The dialog can be resized to:
               *  A minimum width equal to the initial display width
               *  A minimum height equal to the sum of header/footer heights.
               *
               *
               * @param {Number or String} width    The new dialog width in pixels or in percent.
               * @param {Number or String} height   The new dialog height in pixels or in percent.
               *
               * @return {Object} The dialog instance.
               */
              resizeTo:function(width,height){
                  var w = parseFloat(width),
                      h = parseFloat(height),
                      regex = /(\d*\.\d+|\d+)%/
                  ;
  
                  if(!isNaN(w) && !isNaN(h) && this.get('resizable') === true){
                      
                      // allow custom `onresize` method
                      dispatchEvent('onresize', this);
                      
                      if(('' + width).match(regex)){
                          w = w / 100 * document.documentElement.clientWidth ;
                      }
  
                      if(('' + height).match(regex)){
                          h = h / 100 * document.documentElement.clientHeight;
                      }
  
                      var element = this.elements.dialog;
                      if (element.style.maxWidth !== 'none') {
                          element.style.minWidth = (minWidth = element.offsetWidth) + 'px';
                      }
                      element.style.maxWidth = 'none';
                      element.style.minHeight = this.elements.header.offsetHeight + this.elements.footer.offsetHeight + 'px';
                      element.style.width = w + 'px';
                      element.style.height = h + 'px';
                      
                      // allow custom `onresized` method
                      dispatchEvent('onresized', this);
                  }
                  return this;
              },
              /**
               * Gets or Sets dialog settings/options 
               *
               * @param {String|Object} key A string specifying a propery name or a collection of key/value pairs.
               * @param {Object} value Optional, the value associated with the key (in case it was a string).
               *
               * @return {undefined}
               */
              setting : function (key, value) {
                  var self = this;
                  var result = update(this, this.__internal.options, function(k,o,n){ optionUpdated(self,k,o,n); }, key, value);
                  if(result.op === 'get'){
                      if(result.found){
                          return result.value;
                      }else if(typeof this.settings !== 'undefined'){
                          return update(this, this.settings, this.settingUpdated || function(){}, key, value).value;
                      }else{
                          return undefined;
                      }
                  }else if(result.op === 'set'){
                      if(result.items.length > 0){
                          var callback = this.settingUpdated || function(){};
                          for(var x=0;x<result.items.length;x+=1){
                              var item = result.items[x];
                              if(!item.found && typeof this.settings !== 'undefined'){
                                  update(this, this.settings, callback, item.key, item.value);
                              }
                          }
                      }
                      return this;
                  }
              },
              /**
               * [Alias] Sets dialog settings/options 
               */
              set:function(key, value){
                  this.setting(key,value);
                  return this;
              },
              /**
               * [Alias] Gets dialog settings/options 
               */
              get:function(key){
                  return this.setting(key);
              },
              /**
              * Sets dialog header
              * @content {string or element}
              *
              * @return {undefined}
              */
              setHeader:function(content){
                  if(typeof content === 'string'){
                      clearContents(this.elements.header);
                      this.elements.header.innerHTML = content;
                  }else if (content instanceof window.HTMLElement && this.elements.header.firstChild !== content){
                      clearContents(this.elements.header);
                      this.elements.header.appendChild(content);
                  }
                  return this;
              },
              /**
              * Sets dialog contents
              * @content {string or element}
              *
              * @return {undefined}
              */
              setContent:function(content){
                  if(typeof content === 'string'){
                      clearContents(this.elements.content);
                      this.elements.content.innerHTML = content;
                  }else if (content instanceof window.HTMLElement && this.elements.content.firstChild !== content){
                      clearContents(this.elements.content);
                      this.elements.content.appendChild(content);
                  }
                  return this;
              },
              /**
               * Show the dialog as modal
               *
               * @return {Object} the dialog instance.
               */
              showModal: function(className){
                  return this.show(true, className);
              },
              /**
               * Show the dialog
               *
               * @return {Object} the dialog instance.
               */
              show: function (modal, className) {
                  
                  // ensure initialization
                  initialize(this);
  
                  if ( !this.__internal.isOpen ) {
  
                      // add to open dialogs
                      this.__internal.isOpen = true;
                      openDialogs.push(this);
  
                      // save last focused element
                      if(alertify.defaults.maintainFocus){
                          this.__internal.activeElement = document.activeElement;
                      }
  
                      // set tabindex attribute on body element this allows script to give it focusable
                      if(!document.body.hasAttribute('tabindex')) {
                          document.body.setAttribute( 'tabindex', tabindex = '0');
                      }
  
                      //allow custom dom manipulation updates before showing the dialog.
                      if(typeof this.prepare === 'function'){
                          this.prepare();
                      }
  
                      bindEvents(this);
  
                      if(modal !== undefined){
                          this.set('modal', modal);
                      }
  
                      //save scroll to prevent document jump
                      saveScrollPosition();
  
                      ensureNoOverflow();
  
                      // allow custom dialog class on show
                      if(typeof className === 'string' && className !== ''){
                          this.__internal.className = className;
                          addClass(this.elements.root, className);
                      }
  
                      // maximize if start maximized
                      if ( this.get('startMaximized')) {
                          this.maximize();
                      }else if(this.isMaximized()){
                          restore(this);
                      }
  
                      updateAbsPositionFix(this);
                      this.elements.root.removeAttribute('style');
                      removeClass(this.elements.root, classes.animationOut);
                      addClass(this.elements.root, classes.animationIn);
  
                      // set 1s fallback in case transition event doesn't fire
                      clearTimeout( this.__internal.timerIn);
                      this.__internal.timerIn = setTimeout( this.__internal.transitionInHandler, transition.supported ? 1000 : 100 );
  
                      if(isSafari){
                          // force desktop safari reflow
                          var root = this.elements.root;
                          root.style.display  = 'none';
                          setTimeout(function(){root.style.display  = 'block';}, 0);
                      }
  
                      //reflow
                      reflow = this.elements.root.offsetWidth;
                    
                      // show dialog
                      removeClass(this.elements.root, classes.hidden);
  
                      // internal on show event
                      if(typeof this.hooks.onshow === 'function'){
                          this.hooks.onshow.call(this);
                      }
  
                      // allow custom `onshow` method
                      dispatchEvent('onshow', this);
  
                  }else{
                      // reset move updates
                      resetMove(this);
                      // reset resize updates
                      resetResize(this);
                      // shake the dialog to indicate its already open
                      addClass(this.elements.dialog, classes.shake);
                      var self = this;
                      setTimeout(function(){
                          removeClass(self.elements.dialog, classes.shake);
                      },200);
                  }
                  return this;
              },
              /**
               * Close the dialog
               *
               * @return {Object} The dialog instance
               */
              close: function () {
                  if (this.__internal.isOpen ) {
                      // custom `onclosing` event
                      if(dispatchEvent('onclosing', this) !== false){
  
                          unbindEvents(this);
  
                          removeClass(this.elements.root, classes.animationIn);
                          addClass(this.elements.root, classes.animationOut);
  
                          // set 1s fallback in case transition event doesn't fire
                          clearTimeout( this.__internal.timerOut );
                          this.__internal.timerOut = setTimeout( this.__internal.transitionOutHandler, transition.supported ? 1000 : 100 );
                          // hide dialog
                          addClass(this.elements.root, classes.hidden);
                          //reflow
                          reflow = this.elements.modal.offsetWidth;
  
                          // remove custom dialog class on hide
                          if (typeof this.__internal.className !== 'undefined' && this.__internal.className !== '') {
                              removeClass(this.elements.root, this.__internal.className);
                          }
  
                          // internal on close event
                          if(typeof this.hooks.onclose === 'function'){
                              this.hooks.onclose.call(this);
                          }
  
                          // allow custom `onclose` method
                          dispatchEvent('onclose', this);
  
                          //remove from open dialogs
                          openDialogs.splice(openDialogs.indexOf(this),1);
                          this.__internal.isOpen = false;
  
                          ensureNoOverflow();
                      }
  
                  }
                  // last dialog and tab index was set by us, remove it.
                  if(!openDialogs.length && tabindex === '0'){
                      document.body.removeAttribute('tabindex');
                  }
                  return this;
              },
              /**
               * Close all open dialogs except this.
               *
               * @return {undefined}
               */
              closeOthers:function(){
                  alertify.closeAll(this);
                  return this;
              },
              /**
               * Destroys this dialog instance
               *
               * @return {undefined}
               */
              destroy:function(){
                  if(this.__internal) {
                      if (this.__internal.isOpen ) {
                          //mark dialog for destruction, this will be called on tranistionOut event.
                          this.__internal.destroy = function(){
                              destruct(this, initialize);
                          };
                          //close the dialog to unbind all events.
                          this.close();
                      }else if(!this.__internal.destroy){
                          destruct(this, initialize);
                      }
                  }
                  return this;
              },
          };
  	} () );
      var notifier = (function () {
          var reflow,
              element,
              openInstances = [],
              classes = defaults.notifier.classes;
          /**
           * Helper: initializes the notifier instance
           *
           */
          function initialize(instance) {
  
              if (!instance.__internal) {
                  instance.__internal = {
                      position: alertify.defaults.notifier.position,
                      delay: alertify.defaults.notifier.delay,
                  };
  
                  element = document.createElement('DIV');
  
                  updatePosition(instance);
              }
  
              //add to DOM tree.
              if (element.parentNode !== document.body) {
                  document.body.appendChild(element);
              }
          }
  
          function pushInstance(instance) {
              instance.__internal.pushed = true;
              openInstances.push(instance);
          }
          function popInstance(instance) {
              openInstances.splice(openInstances.indexOf(instance), 1);
              instance.__internal.pushed = false;
          }
          /**
           * Helper: update the notifier instance position
           *
           */
          function updatePosition(instance) {
              element.className = classes.base;
              switch (instance.__internal.position) {
              case 'top-right':
                  addClass(element, classes.top + ' ' + classes.right);
                  break;
              case 'top-left':
                  addClass(element, classes.top + ' ' + classes.left);
                  break;
              case 'top-center':
                  addClass(element, classes.top + ' ' + classes.center);
                  break;
              case 'bottom-left':
                  addClass(element, classes.bottom + ' ' + classes.left);
                  break;
              case 'bottom-center':
                  addClass(element, classes.bottom + ' ' + classes.center);
                  break;
  
              default:
              case 'bottom-right':
                  addClass(element, classes.bottom + ' ' + classes.right);
                  break;
              }
          }
  
          /**
          * creates a new notification message
          *
          * @param  {DOMElement} message	The notifier message element
          * @param  {Number} wait   Time (in ms) to wait before the message is dismissed, a value of 0 means keep open till clicked.
          * @param  {Function} callback A callback function to be invoked when the message is dismissed.
          *
          * @return {undefined}
          */
          function create(div, callback) {
  
              function clickDelegate(event, instance) {
                  if(!instance.__internal.closeButton || event.target.getAttribute('data-close') === 'true'){
                      instance.dismiss(true);
                  }
              }
  
              function transitionDone(event, instance) {
                  // unbind event
                  off(instance.element, transition.type, transitionDone);
                  // remove the message
                  element.removeChild(instance.element);
              }
  
              function initialize(instance) {
                  if (!instance.__internal) {
                      instance.__internal = {
                          pushed: false,
                          delay : undefined,
                          timer: undefined,
                          clickHandler: undefined,
                          transitionEndHandler: undefined,
                          transitionTimeout: undefined
                      };
                      instance.__internal.clickHandler = delegate(instance, clickDelegate);
                      instance.__internal.transitionEndHandler = delegate(instance, transitionDone);
                  }
                  return instance;
              }
              function clearTimers(instance) {
                  clearTimeout(instance.__internal.timer);
                  clearTimeout(instance.__internal.transitionTimeout);
              }
              return initialize({
                  /* notification DOM element*/
                  element: div,
                  /*
                   * Pushes a notification message
                   * @param {string or DOMElement} content The notification message content
                   * @param {Number} wait The time (in seconds) to wait before the message is dismissed, a value of 0 means keep open till clicked.
                   *
                   */
                  push: function (_content, _wait) {
                      if (!this.__internal.pushed) {
  
                          pushInstance(this);
                          clearTimers(this);
  
                          var content, wait;
                          switch (arguments.length) {
                          case 0:
                              wait = this.__internal.delay;
                              break;
                          case 1:
                              if (typeof (_content) === 'number') {
                                  wait = _content;
                              } else {
                                  content = _content;
                                  wait = this.__internal.delay;
                              }
                              break;
                          case 2:
                              content = _content;
                              wait = _wait;
                              break;
                          }
                          this.__internal.closeButton = alertify.defaults.notifier.closeButton;
                          // set contents
                          if (typeof content !== 'undefined') {
                              this.setContent(content);
                          }
                          // append or insert
                          if (notifier.__internal.position.indexOf('top') < 0) {
                              element.appendChild(this.element);
                          } else {
                              element.insertBefore(this.element, element.firstChild);
                          }
                          reflow = this.element.offsetWidth;
                          addClass(this.element, classes.visible);
                          // attach click event
                          on(this.element, 'click', this.__internal.clickHandler);
                          return this.delay(wait);
                      }
                      return this;
                  },
                  /*
                   * {Function} callback function to be invoked before dismissing the notification message.
                   * Remarks: A return value === 'false' will cancel the dismissal
                   *
                   */
                  ondismiss: function () { },
                  /*
                   * {Function} callback function to be invoked when the message is dismissed.
                   *
                   */
                  callback: callback,
                  /*
                   * Dismisses the notification message
                   * @param {Boolean} clicked A flag indicating if the dismissal was caused by a click.
                   *
                   */
                  dismiss: function (clicked) {
                      if (this.__internal.pushed) {
                          clearTimers(this);
                          if (!(typeof this.ondismiss === 'function' && this.ondismiss.call(this) === false)) {
                              //detach click event
                              off(this.element, 'click', this.__internal.clickHandler);
                              // ensure element exists
                              if (typeof this.element !== 'undefined' && this.element.parentNode === element) {
                                  //transition end or fallback
                                  this.__internal.transitionTimeout = setTimeout(this.__internal.transitionEndHandler, transition.supported ? 1000 : 100);
                                  removeClass(this.element, classes.visible);
  
                                  // custom callback on dismiss
                                  if (typeof this.callback === 'function') {
                                      this.callback.call(this, clicked);
                                  }
                              }
                              popInstance(this);
                          }
                      }
                      return this;
                  },
                  /*
                   * Delays the notification message dismissal
                   * @param {Number} wait The time (in seconds) to wait before the message is dismissed, a value of 0 means keep open till clicked.
                   *
                   */
                  delay: function (wait) {
                      clearTimers(this);
                      this.__internal.delay = typeof wait !== 'undefined' && !isNaN(+wait) ? +wait : notifier.__internal.delay;
                      if (this.__internal.delay > 0) {
                          var  self = this;
                          this.__internal.timer = setTimeout(function () { self.dismiss(); }, this.__internal.delay * 1000);
                      }
                      return this;
                  },
                  /*
                   * Sets the notification message contents
                   * @param {string or DOMElement} content The notification message content
                   *
                   */
                  setContent: function (content) {
                      if (typeof content === 'string') {
                          clearContents(this.element);
                          this.element.innerHTML = content;
                      } else if (content instanceof window.HTMLElement && this.element.firstChild !== content) {
                          clearContents(this.element);
                          this.element.appendChild(content);
                      }
                      if(this.__internal.closeButton){
                          var close = document.createElement('span');
                          addClass(close, classes.close);
                          close.setAttribute('data-close', true);
                          this.element.appendChild(close);
                      }
                      return this;
                  },
                  /*
                   * Dismisses all open notifications except this.
                   *
                   */
                  dismissOthers: function () {
                      notifier.dismissAll(this);
                      return this;
                  }
              });
          }
  
          //notifier api
          return {
              /**
               * Gets or Sets notifier settings.
               *
               * @param {string} key The setting name
               * @param {Variant} value The setting value.
               *
               * @return {Object}	if the called as a setter, return the notifier instance.
               */
              setting: function (key, value) {
                  //ensure init
                  initialize(this);
  
                  if (typeof value === 'undefined') {
                      //get
                      return this.__internal[key];
                  } else {
                      //set
                      switch (key) {
                      case 'position':
                          this.__internal.position = value;
                          updatePosition(this);
                          break;
                      case 'delay':
                          this.__internal.delay = value;
                          break;
                      }
                  }
                  return this;
              },
              /**
               * [Alias] Sets dialog settings/options
               */
              set:function(key,value){
                  this.setting(key,value);
                  return this;
              },
              /**
               * [Alias] Gets dialog settings/options
               */
              get:function(key){
                  return this.setting(key);
              },
              /**
               * Creates a new notification message
               *
               * @param {string} type The type of notification message (simply a CSS class name 'ajs-{type}' to be added).
               * @param {Function} callback  A callback function to be invoked when the message is dismissed.
               *
               * @return {undefined}
               */
              create: function (type, callback) {
                  //ensure notifier init
                  initialize(this);
                  //create new notification message
                  var div = document.createElement('div');
                  div.className = classes.message + ((typeof type === 'string' && type !== '') ? ' ' + classes.prefix + type : '');
                  return create(div, callback);
              },
              /**
               * Dismisses all open notifications.
               *
               * @param {Object} excpet [optional] The notification object to exclude from dismissal.
               *
               */
              dismissAll: function (except) {
                  var clone = openInstances.slice(0);
                  for (var x = 0; x < clone.length; x += 1) {
                      var  instance = clone[x];
                      if (except === undefined || except !== instance) {
                          instance.dismiss();
                      }
                  }
              }
          };
      })();
  
      /**
       * Alertify public API
       * This contains everything that is exposed through the alertify object.
       *
       * @return {Object}
       */
      function Alertify() {
  
          // holds a references of created dialogs
          var dialogs = {};
  
          /**
           * Extends a given prototype by merging properties from base into sub.
           *
           * @sub {Object} sub The prototype being overwritten.
           * @base {Object} base The prototype being written.
           *
           * @return {Object} The extended prototype.
           */
          function extend(sub, base) {
              // copy dialog pototype over definition.
              for (var prop in base) {
                  if (base.hasOwnProperty(prop)) {
                      sub[prop] = base[prop];
                  }
              }
              return sub;
          }
  
  
          /**
          * Helper: returns a dialog instance from saved dialogs.
          * and initializes the dialog if its not already initialized.
          *
          * @name {String} name The dialog name.
          *
          * @return {Object} The dialog instance.
          */
          function get_dialog(name) {
              var dialog = dialogs[name].dialog;
              //initialize the dialog if its not already initialized.
              if (dialog && typeof dialog.__init === 'function') {
                  dialog.__init(dialog);
              }
              return dialog;
          }
  
          /**
           * Helper:  registers a new dialog definition.
           *
           * @name {String} name The dialog name.
           * @Factory {Function} Factory a function resposible for creating dialog prototype.
           * @transient {Boolean} transient True to create a new dialog instance each time the dialog is invoked, false otherwise.
           * @base {String} base the name of another dialog to inherit from.
           *
           * @return {Object} The dialog definition.
           */
          function register(name, Factory, transient, base) {
              var definition = {
                  dialog: null,
                  factory: Factory
              };
  
              //if this is based on an existing dialog, create a new definition
              //by applying the new protoype over the existing one.
              if (base !== undefined) {
                  definition.factory = function () {
                      return extend(new dialogs[base].factory(), new Factory());
                  };
              }
  
              if (!transient) {
                  //create a new definition based on dialog
                  definition.dialog = extend(new definition.factory(), dialog);
              }
              return dialogs[name] = definition;
          }
  
          return {
              /**
               * Alertify defaults
               * 
               * @type {Object}
               */
              defaults: defaults,
              /**
               * Dialogs factory 
               *
               * @param {string}      Dialog name.
               * @param {Function}    A Dialog factory function.
               * @param {Boolean}     Indicates whether to create a singleton or transient dialog.
               * @param {String}      The name of the base type to inherit from.
               */
              dialog: function (name, Factory, transient, base) {
  
                  // get request, create a new instance and return it.
                  if (typeof Factory !== 'function') {
                      return get_dialog(name);
                  }
  
                  if (this.hasOwnProperty(name)) {
                      throw new Error('alertify.dialog: name already exists');
                  }
  
                  // register the dialog
                  var definition = register(name, Factory, transient, base);
  
                  if (transient) {
  
                      // make it public
                      this[name] = function () {
                          //if passed with no params, consider it a get request
                          if (arguments.length === 0) {
                              return definition.dialog;
                          } else {
                              var instance = extend(new definition.factory(), dialog);
                              //ensure init
                              if (instance && typeof instance.__init === 'function') {
                                  instance.__init(instance);
                              }
                              instance['main'].apply(instance, arguments);
                              return instance['show'].apply(instance);
                          }
                      };
                  } else {
                      // make it public
                      this[name] = function () {
                          //ensure init
                          if (definition.dialog && typeof definition.dialog.__init === 'function') {
                              definition.dialog.__init(definition.dialog);
                          }
                          //if passed with no params, consider it a get request
                          if (arguments.length === 0) {
                              return definition.dialog;
                          } else {
                              var dialog = definition.dialog;
                              dialog['main'].apply(definition.dialog, arguments);
                              return dialog['show'].apply(definition.dialog);
                          }
                      };
                  }
              },
              /**
               * Close all open dialogs.
               *
               * @param {Object} excpet [optional] The dialog object to exclude from closing.
               *
               * @return {undefined}
               */
              closeAll: function (except) {
                  var clone = openDialogs.slice(0);
                  for (var x = 0; x < clone.length; x += 1) {
                      var instance = clone[x];
                      if (except === undefined || except !== instance) {
                          instance.close();
                      }
                  }
              },
              /**
               * Gets or Sets dialog settings/options. if the dialog is transient, this call does nothing.
               *
               * @param {string} name The dialog name.
               * @param {String|Object} key A string specifying a propery name or a collection of key/value pairs.
               * @param {Variant} value Optional, the value associated with the key (in case it was a string).
               *
               * @return {undefined}
               */
              setting: function (name, key, value) {
  
                  if (name === 'notifier') {
                      return notifier.setting(key, value);
                  }
  
                  var dialog = get_dialog(name);
                  if (dialog) {
                      return dialog.setting(key, value);
                  }
              },
              /**
               * [Alias] Sets dialog settings/options 
               */
              set: function(name,key,value){
                  return this.setting(name, key,value);
              },
              /**
               * [Alias] Gets dialog settings/options 
               */
              get: function(name, key){
                  return this.setting(name, key);
              },
              /**
               * Creates a new notification message.
               * If a type is passed, a class name "ajs-{type}" will be added.
               * This allows for custom look and feel for various types of notifications.
               *
               * @param  {String | DOMElement}    [message=undefined]		Message text
               * @param  {String}                 [type='']				Type of log message
               * @param  {String}                 [wait='']				Time (in seconds) to wait before auto-close
               * @param  {Function}               [callback=undefined]	A callback function to be invoked when the log is closed.
               *
               * @return {Object} Notification object.
               */
              notify: function (message, type, wait, callback) {
                  return notifier.create(type, callback).push(message, wait);
              },
              /**
               * Creates a new notification message.
               *
               * @param  {String}		[message=undefined]		Message text
               * @param  {String}     [wait='']				Time (in seconds) to wait before auto-close
               * @param  {Function}	[callback=undefined]	A callback function to be invoked when the log is closed.
               *
               * @return {Object} Notification object.
               */
              message: function (message, wait, callback) {
                  return notifier.create(null, callback).push(message, wait);
              },
              /**
               * Creates a new notification message of type 'success'.
               *
               * @param  {String}		[message=undefined]		Message text
               * @param  {String}     [wait='']				Time (in seconds) to wait before auto-close
               * @param  {Function}	[callback=undefined]	A callback function to be invoked when the log is closed.
               *
               * @return {Object} Notification object.
               */
              success: function (message, wait, callback) {
                  return notifier.create('success', callback).push(message, wait);
              },
              /**
               * Creates a new notification message of type 'error'.
               *
               * @param  {String}		[message=undefined]		Message text
               * @param  {String}     [wait='']				Time (in seconds) to wait before auto-close
               * @param  {Function}	[callback=undefined]	A callback function to be invoked when the log is closed.
               *
               * @return {Object} Notification object.
               */
              error: function (message, wait, callback) {
                  return notifier.create('error', callback).push(message, wait);
              },
              /**
               * Creates a new notification message of type 'warning'.
               *
               * @param  {String}		[message=undefined]		Message text
               * @param  {String}     [wait='']				Time (in seconds) to wait before auto-close
               * @param  {Function}	[callback=undefined]	A callback function to be invoked when the log is closed.
               *
               * @return {Object} Notification object.
               */
              warning: function (message, wait, callback) {
                  return notifier.create('warning', callback).push(message, wait);
              },
              /**
               * Dismisses all open notifications
               *
               * @return {undefined}
               */
              dismissAll: function () {
                  notifier.dismissAll();
              }
          };
      }
      var alertify = new Alertify();
  
      /**
      * Alert dialog definition
      *
      * invoked by:
      *	alertify.alert(message);
      *	alertify.alert(title, message);
      *	alertify.alert(message, onok);
      *	alertify.alert(title, message, onok);
       */
      alertify.dialog('alert', function () {
          return {
              main: function (_title, _message, _onok) {
                  var title, message, onok;
                  switch (arguments.length) {
                  case 1:
                      message = _title;
                      break;
                  case 2:
                      if (typeof _message === 'function') {
                          message = _title;
                          onok = _message;
                      } else {
                          title = _title;
                          message = _message;
                      }
                      break;
                  case 3:
                      title = _title;
                      message = _message;
                      onok = _onok;
                      break;
                  }
                  this.set('title', title);
                  this.set('message', message);
                  this.set('onok', onok);
                  return this;
              },
              setup: function () {
                  return {
                      buttons: [
                          {
                              text: alertify.defaults.glossary.ok,
                              key: keys.ESC,
                              invokeOnClose: true,
                              className: alertify.defaults.theme.ok,
                          }
                      ],
                      focus: {
                          element: 0,
                          select: false
                      },
                      options: {
                          maximizable: false,
                          resizable: false
                      }
                  };
              },
              build: function () {
                  // nothing
              },
              prepare: function () {
                  //nothing
              },
              setMessage: function (message) {
                  this.setContent(message);
              },
              settings: {
                  message: undefined,
                  onok: undefined,
                  label: undefined,
              },
              settingUpdated: function (key, oldValue, newValue) {
                  switch (key) {
                  case 'message':
                      this.setMessage(newValue);
                      break;
                  case 'label':
                      if (this.__internal.buttons[0].element) {
                          this.__internal.buttons[0].element.innerHTML = newValue;
                      }
                      break;
                  }
              },
              callback: function (closeEvent) {
                  if (typeof this.get('onok') === 'function') {
                      var returnValue = this.get('onok').call(this, closeEvent);
                      if (typeof returnValue !== 'undefined') {
                          closeEvent.cancel = !returnValue;
                      }
                  }
              }
          };
      });
      /**
       * Confirm dialog object
       *
       *	alertify.confirm(message);
       *	alertify.confirm(message, onok);
       *	alertify.confirm(message, onok, oncancel);
       *	alertify.confirm(title, message, onok, oncancel);
       */
      alertify.dialog('confirm', function () {
  
          var autoConfirm = {
              timer: null,
              index: null,
              text: null,
              duration: null,
              task: function (event, self) {
                  if (self.isOpen()) {
                      self.__internal.buttons[autoConfirm.index].element.innerHTML = autoConfirm.text + ' (&#8207;' + autoConfirm.duration + '&#8207;) ';
                      autoConfirm.duration -= 1;
                      if (autoConfirm.duration === -1) {
                          clearAutoConfirm(self);
                          var button = self.__internal.buttons[autoConfirm.index];
                          var closeEvent = createCloseEvent(autoConfirm.index, button);
  
                          if (typeof self.callback === 'function') {
                              self.callback.apply(self, [closeEvent]);
                          }
                          //close the dialog.
                          if (closeEvent.close !== false) {
                              self.close();
                          }
                      }
                  } else {
                      clearAutoConfirm(self);
                  }
              }
          };
  
          function clearAutoConfirm(self) {
              if (autoConfirm.timer !== null) {
                  clearInterval(autoConfirm.timer);
                  autoConfirm.timer = null;
                  self.__internal.buttons[autoConfirm.index].element.innerHTML = autoConfirm.text;
              }
          }
  
          function startAutoConfirm(self, index, duration) {
              clearAutoConfirm(self);
              autoConfirm.duration = duration;
              autoConfirm.index = index;
              autoConfirm.text = self.__internal.buttons[index].element.innerHTML;
              autoConfirm.timer = setInterval(delegate(self, autoConfirm.task), 1000);
              autoConfirm.task(null, self);
          }
  
  
          return {
              main: function (_title, _message, _onok, _oncancel) {
                  var title, message, onok, oncancel;
                  switch (arguments.length) {
                  case 1:
                      message = _title;
                      break;
                  case 2:
                      message = _title;
                      onok = _message;
                      break;
                  case 3:
                      message = _title;
                      onok = _message;
                      oncancel = _onok;
                      break;
                  case 4:
                      title = _title;
                      message = _message;
                      onok = _onok;
                      oncancel = _oncancel;
                      break;
                  }
                  this.set('title', title);
                  this.set('message', message);
                  this.set('onok', onok);
                  this.set('oncancel', oncancel);
                  return this;
              },
              setup: function () {
                  return {
                      buttons: [
                          {
                              text: alertify.defaults.glossary.ok,
                              key: keys.ENTER,
                              className: alertify.defaults.theme.ok,
                          },
                          {
                              text: alertify.defaults.glossary.cancel,
                              key: keys.ESC,
                              invokeOnClose: true,
                              className: alertify.defaults.theme.cancel,
                          }
                      ],
                      focus: {
                          element: 0,
                          select: false
                      },
                      options: {
                          maximizable: false,
                          resizable: false
                      }
                  };
              },
              build: function () {
                  //nothing
              },
              prepare: function () {
                  //nothing
              },
              setMessage: function (message) {
                  this.setContent(message);
              },
              settings: {
                  message: null,
                  labels: null,
                  onok: null,
                  oncancel: null,
                  defaultFocus: null,
                  reverseButtons: null,
              },
              settingUpdated: function (key, oldValue, newValue) {
                  switch (key) {
                  case 'message':
                      this.setMessage(newValue);
                      break;
                  case 'labels':
                      if ('ok' in newValue && this.__internal.buttons[0].element) {
                          this.__internal.buttons[0].text = newValue.ok;
                          this.__internal.buttons[0].element.innerHTML = newValue.ok;
                      }
                      if ('cancel' in newValue && this.__internal.buttons[1].element) {
                          this.__internal.buttons[1].text = newValue.cancel;
                          this.__internal.buttons[1].element.innerHTML = newValue.cancel;
                      }
                      break;
                  case 'reverseButtons':
                      if (newValue === true) {
                          this.elements.buttons.primary.appendChild(this.__internal.buttons[0].element);
                      } else {
                          this.elements.buttons.primary.appendChild(this.__internal.buttons[1].element);
                      }
                      break;
                  case 'defaultFocus':
                      this.__internal.focus.element = newValue === 'ok' ? 0 : 1;
                      break;
                  }
              },
              callback: function (closeEvent) {
                  clearAutoConfirm(this);
                  var returnValue;
                  switch (closeEvent.index) {
                  case 0:
                      if (typeof this.get('onok') === 'function') {
                          returnValue = this.get('onok').call(this, closeEvent);
                          if (typeof returnValue !== 'undefined') {
                              closeEvent.cancel = !returnValue;
                          }
                      }
                      break;
                  case 1:
                      if (typeof this.get('oncancel') === 'function') {
                          returnValue = this.get('oncancel').call(this, closeEvent);
                          if (typeof returnValue !== 'undefined') {
                              closeEvent.cancel = !returnValue;
                          }
                      }
                      break;
                  }
              },
              autoOk: function (duration) {
                  startAutoConfirm(this, 0, duration);
                  return this;
              },
              autoCancel: function (duration) {
                  startAutoConfirm(this, 1, duration);
                  return this;
              }
          };
      });
      /**
       * Prompt dialog object
       *
       * invoked by:
       *	alertify.prompt(message);
       *	alertify.prompt(message, value);
       *	alertify.prompt(message, value, onok);
       *	alertify.prompt(message, value, onok, oncancel);
       *	alertify.prompt(title, message, value, onok, oncancel);
       */
      alertify.dialog('prompt', function () {
          var input = document.createElement('INPUT');
          var p = document.createElement('P');
          return {
              main: function (_title, _message, _value, _onok, _oncancel) {
                  var title, message, value, onok, oncancel;
                  switch (arguments.length) {
                  case 1:
                      message = _title;
                      break;
                  case 2:
                      message = _title;
                      value = _message;
                      break;
                  case 3:
                      message = _title;
                      value = _message;
                      onok = _value;
                      break;
                  case 4:
                      message = _title;
                      value = _message;
                      onok = _value;
                      oncancel = _onok;
                      break;
                  case 5:
                      title = _title;
                      message = _message;
                      value = _value;
                      onok = _onok;
                      oncancel = _oncancel;
                      break;
                  }
                  this.set('title', title);
                  this.set('message', message);
                  this.set('value', value);
                  this.set('onok', onok);
                  this.set('oncancel', oncancel);
                  return this;
              },
              setup: function () {
                  return {
                      buttons: [
                          {
                              text: alertify.defaults.glossary.ok,
                              key: keys.ENTER,
                              className: alertify.defaults.theme.ok,
                          },
                          {
                              text: alertify.defaults.glossary.cancel,
                              key: keys.ESC,
                              invokeOnClose: true,
                              className: alertify.defaults.theme.cancel,
                          }
                      ],
                      focus: {
                          element: input,
                          select: true
                      },
                      options: {
                          maximizable: false,
                          resizable: false
                      }
                  };
              },
              build: function () {
                  input.className = alertify.defaults.theme.input;
                  input.setAttribute('type', 'text');
                  input.value = this.get('value');
                  this.elements.content.appendChild(p);
                  this.elements.content.appendChild(input);
              },
              prepare: function () {
                  //nothing
              },
              setMessage: function (message) {
                  if (typeof message === 'string') {
                      clearContents(p);
                      p.innerHTML = message;
                  } else if (message instanceof window.HTMLElement && p.firstChild !== message) {
                      clearContents(p);
                      p.appendChild(message);
                  }
              },
              settings: {
                  message: undefined,
                  labels: undefined,
                  onok: undefined,
                  oncancel: undefined,
                  value: '',
                  type:'text',
                  reverseButtons: undefined,
              },
              settingUpdated: function (key, oldValue, newValue) {
                  switch (key) {
                  case 'message':
                      this.setMessage(newValue);
                      break;
                  case 'value':
                      input.value = newValue;
                      break;
                  case 'type':
                      switch (newValue) {
                      case 'text':
                      case 'color':
                      case 'date':
                      case 'datetime-local':
                      case 'email':
                      case 'month':
                      case 'number':
                      case 'password':
                      case 'search':
                      case 'tel':
                      case 'time':
                      case 'week':
                          input.type = newValue;
                          break;
                      default:
                          input.type = 'text';
                          break;
                      }
                      break;
                  case 'labels':
                      if (newValue.ok && this.__internal.buttons[0].element) {
                          this.__internal.buttons[0].element.innerHTML = newValue.ok;
                      }
                      if (newValue.cancel && this.__internal.buttons[1].element) {
                          this.__internal.buttons[1].element.innerHTML = newValue.cancel;
                      }
                      break;
                  case 'reverseButtons':
                      if (newValue === true) {
                          this.elements.buttons.primary.appendChild(this.__internal.buttons[0].element);
                      } else {
                          this.elements.buttons.primary.appendChild(this.__internal.buttons[1].element);
                      }
                      break;
                  }
              },
              callback: function (closeEvent) {
                  var returnValue;
                  switch (closeEvent.index) {
                  case 0:
                      this.settings.value = input.value;
                      if (typeof this.get('onok') === 'function') {
                          returnValue = this.get('onok').call(this, closeEvent, this.settings.value);
                          if (typeof returnValue !== 'undefined') {
                              closeEvent.cancel = !returnValue;
                          }
                      }
                      break;
                  case 1:
                      if (typeof this.get('oncancel') === 'function') {
                          returnValue = this.get('oncancel').call(this, closeEvent);
                          if (typeof returnValue !== 'undefined') {
                              closeEvent.cancel = !returnValue;
                          }
                      }
                      if(!closeEvent.cancel){
                          input.value = this.settings.value;
                      }
                      break;
                  }
              }
          };
      });
  
      // CommonJS
      if ( typeof module === 'object' && typeof module.exports === 'object' ) {
          module.exports = alertify;
      // AMD
      } else if ( typeof define === 'function' && define.amd) {
          define( [], function () {
              return alertify;
          } );
      // window
      } else if ( !window.alertify ) {
          window.alertify = alertify;
      }
  
  } ( typeof window !== 'undefined' ? window : this ) );
  