text: /**
   * bootbox.js [v4.2.0]
   *
   * http://bootboxjs.com/license.txt
   */
  
  // @see https://github.com/makeusabrew/bootbox/issues/180
  // @see https://github.com/makeusabrew/bootbox/issues/186
  (function (root, factory) {
  
      "use strict";
      if (typeof define === "function" && define.amd) {
          // AMD. Register as an anonymous module.
          define(["jquery"], factory);
      } else if (typeof exports === "object") {
          // Node. Does not work with strict CommonJS, but
          // only CommonJS-like environments that support module.exports,
          // like Node.
          module.exports = factory(require("jquery"));
      } else {
          // Browser globals (root is window)
          root.bootbox = factory(root.jQuery);
      }
  
  }(this, function init($, undefined) {
  
      "use strict";
  
      // the base DOM structure needed to create a modal
      var templates = {
          dialog: "<div class='bootbox modal' tabindex='-1' role='dialog'>" +
              "<div class='modal-dialog'>" +
              "<div class='modal-content'>" +
              "<div class='modal-body'><div class='bootbox-body'></div></div>" +
              "</div>" +
              "</div>" +
              "</div>",
          header: "<div class='modal-header'>" +
              "<h4 class='modal-title'></h4>" +
              "</div>",
          footer: "<div class='modal-footer'></div>",
          closeButton: "<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>&times;</button>",
          form: "<form class='bootbox-form'></form>",
          inputs: {
              text: "<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />",
              textarea: "<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>",
              email: "<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />",
              select: "<select class='bootbox-input bootbox-input-select form-control'></select>",
              checkbox: "<div class='checkbox'><label><input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>",
              date: "<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />",
              time: "<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />",
              number: "<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />",
              password: "<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />"
          }
      };
  
      var defaults = {
          // default language
          locale: "en",
          // show backdrop or not
          backdrop: true,
          // animate the modal in/out
          animate: true,
          // additional class string applied to the top level dialog
          className: null,
          // whether or not to include a close button
          closeButton: true,
          // show the dialog immediately by default
          show: true,
          // dialog container
          container: "body"
      };
  
      // our public object; augmented after our private API
      var exports = {};
  
      /**
       * @private
       */
      function _t(key) {
          var locale = locales[defaults.locale];
          return locale ? locale[key] : locales.en[key];
      }
  
      function processCallback(e, dialog, callback) {
          e.stopPropagation();
          e.preventDefault();
  
          // by default we assume a callback will get rid of the dialog,
          // although it is given the opportunity to override this
  
          // so, if the callback can be invoked and it *explicitly returns false*
          // then we'll set a flag to keep the dialog active...
          var preserveDialog = $.isFunction(callback) && callback(e) === false;
  
          // ... otherwise we'll bin it
          if (!preserveDialog) {
              dialog.modal("hide");
          }
      }
  
      function getKeyLength(obj) {
          // @TODO defer to Object.keys(x).length if available?
          var k, t = 0;
          for (k in obj) {
              t++;
          }
          return t;
      }
  
      function each(collection, iterator) {
          var index = 0;
          $.each(collection, function (key, value) {
              iterator(key, value, index++);
          });
      }
  
      function sanitize(options) {
          var buttons;
          var total;
  
          if (typeof options !== "object") {
              throw new Error("Please supply an object of options");
          }
  
          if (!options.message) {
              throw new Error("Please specify a message");
          }
  
          // make sure any supplied options take precedence over defaults
          options = $.extend({}, defaults, options);
  
          if (!options.buttons) {
              options.buttons = {};
          }
  
          // we only support Bootstrap's "static" and false backdrop args
          // supporting true would mean you could dismiss the dialog without
          // explicitly interacting with it
          options.backdrop = options.backdrop ? "static" : false;
  
          buttons = options.buttons;
  
          total = getKeyLength(buttons);
  
          each(buttons, function (key, button, index) {
  
              if ($.isFunction(button)) {
                  // short form, assume value is our callback. Since button
                  // isn't an object it isn't a reference either so re-assign it
                  button = buttons[key] = {
                      callback: button
                  };
              }
  
              // before any further checks make sure by now button is the correct type
              if ($.type(button) !== "object") {
                  throw new Error("button with key " + key + " must be an object");
              }
  
              if (!button.label) {
                  // the lack of an explicit label means we'll assume the key is good enough
                  button.label = key;
              }
  
              if (!button.className) {
                  if (total <= 2 && index === total - 1) {
                      // always add a primary to the main option in a two-button dialog
                      button.className = "btn-primary";
                  } else {
                      button.className = "btn-default";
                  }
              }
          });
  
          return options;
      }
  
      /**
       * map a flexible set of arguments into a single returned object
       * if args.length is already one just return it, otherwise
       * use the properties argument to map the unnamed args to
       * object properties
       * so in the latter case:
       * mapArguments(["foo", $.noop], ["message", "callback"])
       * -> { message: "foo", callback: $.noop }
       */
      function mapArguments(args, properties) {
          var argn = args.length;
          var options = {};
  
          if (argn < 1 || argn > 2) {
              throw new Error("Invalid argument length");
          }
  
          if (argn === 2 || typeof args[0] === "string") {
              options[properties[0]] = args[0];
              options[properties[1]] = args[1];
          } else {
              options = args[0];
          }
  
          return options;
      }
  
      /**
       * merge a set of default dialog options with user supplied arguments
       */
      function mergeArguments(defaults, args, properties) {
          return $.extend(
              // deep merge
              true,
              // ensure the target is an empty, unreferenced object
              {},
              // the base options object for this type of dialog (often just buttons)
              defaults,
              // args could be an object or array; if it's an array properties will
              // map it to a proper options object
              mapArguments(
                  args,
                  properties
              )
          );
      }
  
      /**
       * this entry-level method makes heavy use of composition to take a simple
       * range of inputs and return valid options suitable for passing to bootbox.dialog
       */
      function mergeDialogOptions(className, labels, properties, args) {
          //  build up a base set of dialog properties
          var baseOptions = {
              className: "bootbox-" + className,
              buttons: createLabels.apply(null, labels)
          };
  
          // ensure the buttons properties generated, *after* merging
          // with user args are still valid against the supplied labels
          return validateButtons(
              // merge the generated base properties with user supplied arguments
              mergeArguments(
                  baseOptions,
                  args,
                  // if args.length > 1, properties specify how each arg maps to an object key
                  properties
              ),
              labels
          );
      }
  
      /**
       * from a given list of arguments return a suitable object of button labels
       * all this does is normalise the given labels and translate them where possible
       * e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" }
       */
      function createLabels() {
          var buttons = {};
  
          for (var i = 0, j = arguments.length; i < j; i++) {
              var argument = arguments[i];
              var key = argument.toLowerCase();
              var value = argument.toUpperCase();
  
              buttons[key] = {
                  label: _t(value)
              };
          }
  
          return buttons;
      }
  
      function validateButtons(options, buttons) {
          var allowedButtons = {};
          each(buttons, function (key, value) {
              allowedButtons[value] = true;
          });
  
          each(options.buttons, function (key) {
              if (allowedButtons[key] === undefined) {
                  throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")");
              }
          });
  
          return options;
      }
  
      exports.alert = function () {
          var options;
  
          options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments);
  
          if (options.callback && !$.isFunction(options.callback)) {
              throw new Error("alert requires callback property to be a function when provided");
          }
  
          /**
           * overrides
           */
          options.buttons.ok.callback = options.onEscape = function () {
              if ($.isFunction(options.callback)) {
                  return options.callback();
              }
              return true;
          };
  
          return exports.dialog(options);
      };
  
      exports.confirm = function () {
          var options;
  
          options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments);
  
          /**
           * overrides; undo anything the user tried to set they shouldn't have
           */
          options.buttons.cancel.callback = options.onEscape = function () {
              return options.callback(false);
          };
  
          options.buttons.confirm.callback = function () {
              return options.callback(true);
          };
  
          // confirm specific validation
          if (!$.isFunction(options.callback)) {
              throw new Error("confirm requires a callback");
          }
  
          return exports.dialog(options);
      };
  
      exports.prompt = function () {
          var options;
          var defaults;
          var dialog;
          var form;
          var input;
          var shouldShow;
          var inputOptions;
  
          // we have to create our form first otherwise
          // its value is undefined when gearing up our options
          // @TODO this could be solved by allowing message to
          // be a function instead...
          form = $(templates.form);
  
          // prompt defaults are more complex than others in that
          // users can override more defaults
          // @TODO I don't like that prompt has to do a lot of heavy
          // lifting which mergeDialogOptions can *almost* support already
          // just because of 'value' and 'inputType' - can we refactor?
          defaults = {
              className: "bootbox-prompt",
              buttons: createLabels("cancel", "confirm"),
              value: "",
              inputType: "text"
          };
  
          options = validateButtons(
              mergeArguments(defaults, arguments, ["title", "callback"]),
              ["cancel", "confirm"]
          );
  
          // capture the user's show value; we always set this to false before
          // spawning the dialog to give us a chance to attach some handlers to
          // it, but we need to make sure we respect a preference not to show it
          shouldShow = (options.show === undefined) ? true : options.show;
  
          // check if the browser supports the option.inputType
          var html5inputs = ["date", "time", "number"];
          var i = document.createElement("input");
          i.setAttribute("type", options.inputType);
          if (html5inputs[options.inputType]) {
              options.inputType = i.type;
          }
  
          /**
           * overrides; undo anything the user tried to set they shouldn't have
           */
          options.message = form;
  
          options.buttons.cancel.callback = options.onEscape = function () {
              return options.callback(null);
          };
  
          options.buttons.confirm.callback = function () {
              var value;
  
              switch (options.inputType) {
                  case "text":
                  case "textarea":
                  case "email":
                  case "select":
                  case "date":
                  case "time":
                  case "number":
                  case "password":
                      value = input.val();
                      break;
  
                  case "checkbox":
                      var checkedItems = input.find("input:checked");
  
                      // we assume that checkboxes are always multiple,
                      // hence we default to an empty array
                      value = [];
  
                      each(checkedItems, function (_, item) {
                          value.push($(item).val());
                      });
                      break;
              }
  
              return options.callback(value);
          };
  
          options.show = false;
  
          // prompt specific validation
          if (!options.title) {
              throw new Error("prompt requires a title");
          }
  
          if (!$.isFunction(options.callback)) {
              throw new Error("prompt requires a callback");
          }
  
          if (!templates.inputs[options.inputType]) {
              throw new Error("invalid prompt type");
          }
  
          // create the input based on the supplied type
          input = $(templates.inputs[options.inputType]);
  
          switch (options.inputType) {
              case "text":
              case "textarea":
              case "email":
              case "date":
              case "time":
              case "number":
              case "password":
                  input.val(options.value);
                  break;
  
              case "select":
                  var groups = {};
                  inputOptions = options.inputOptions || [];
  
                  if (!inputOptions.length) {
                      throw new Error("prompt with select requires options");
                  }
  
                  each(inputOptions, function (_, option) {
  
                      // assume the element to attach to is the input...
                      var elem = input;
  
                      if (option.value === undefined || option.text === undefined) {
                          throw new Error("given options in wrong format");
                      }
  
  
                      // ... but override that element if this option sits in a group
  
                      if (option.group) {
                          // initialise group if necessary
                          if (!groups[option.group]) {
                              groups[option.group] = $("<optgroup/>").attr("label", option.group);
                          }
  
                          elem = groups[option.group];
                      }
  
                      elem.append("<option value='" + option.value + "'>" + option.text + "</option>");
                  });
  
                  each(groups, function (_, group) {
                      input.append(group);
                  });
  
                  // safe to set a select's value as per a normal input
                  input.val(options.value);
                  break;
  
              case "checkbox":
                  var values = $.isArray(options.value) ? options.value : [options.value];
                  inputOptions = options.inputOptions || [];
  
                  if (!inputOptions.length) {
                      throw new Error("prompt with checkbox requires options");
                  }
  
                  if (!inputOptions[0].value || !inputOptions[0].text) {
                      throw new Error("given options in wrong format");
                  }
  
                  // checkboxes have to nest within a containing element, so
                  // they break the rules a bit and we end up re-assigning
                  // our 'input' element to this container instead
                  input = $("<div/>");
  
                  each(inputOptions, function (_, option) {
                      var checkbox = $(templates.inputs[options.inputType]);
  
                      checkbox.find("input").attr("value", option.value);
                      checkbox.find("label").append(option.text);
  
                      // we've ensured values is an array so we can always iterate over it
                      each(values, function (_, value) {
                          if (value === option.value) {
                              checkbox.find("input").prop("checked", true);
                          }
                      });
  
                      input.append(checkbox);
                  });
                  break;
          }
  
          if (options.placeholder) {
              input.attr("placeholder", options.placeholder);
          }
  
          if (options.pattern) {
              input.attr("pattern", options.pattern);
          }
  
          // now place it in our form
          form.append(input);
  
          form.on("submit", function (e) {
              e.preventDefault();
              // @TODO can we actually click *the* button object instead?
              // e.g. buttons.confirm.click() or similar
              dialog.find(".btn-primary").click();
          });
  
          dialog = exports.dialog(options);
  
          // clear the existing handler focusing the submit button...
          dialog.off("shown.bs.modal");
  
          // ...and replace it with one focusing our input, if possible
          dialog.on("shown.bs.modal", function () {
              input.focus();
          });
  
          if (shouldShow === true) {
              dialog.modal("show");
          }
  
          return dialog;
      };
  
      exports.dialog = function (options) {
          options = sanitize(options);
  
          var dialog = $(templates.dialog);
          var body = dialog.find(".modal-body");
          var buttons = options.buttons;
          var buttonStr = "";
          var callbacks = {
              onEscape: options.onEscape
          };
  
          each(buttons, function (key, button) {
  
              // @TODO I don't like this string appending to itself; bit dirty. Needs reworking
              // can we just build up button elements instead? slower but neater. Then button
              // can just become a template too
              buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
              callbacks[key] = button.callback;
          });
  
          body.find(".bootbox-body").html(options.message);
  
          if (options.animate === true) {
              dialog.addClass("fade");
          }
  
          if (options.className) {
              dialog.addClass(options.className);
          }
  
          if (options.title) {
              body.before(templates.header);
          }
  
          if (options.closeButton) {
              var closeButton = $(templates.closeButton);
  
              if (options.title) {
                  dialog.find(".modal-header").prepend(closeButton);
              } else {
                  closeButton.css("margin-top", "-10px").prependTo(body);
              }
          }
  
          if (options.title) {
              dialog.find(".modal-title").html(options.title);
          }
  
          if (buttonStr.length) {
              body.after(templates.footer);
              dialog.find(".modal-footer").html(buttonStr);
          }
  
  
          /**
           * Bootstrap event listeners; used handle extra
           * setup & teardown required after the underlying
           * modal has performed certain actions
           */
  
          dialog.on("hidden.bs.modal", function (e) {
              // ensure we don't accidentally intercept hidden events triggered
              // by children of the current dialog. We shouldn't anymore now BS
              // namespaces its events; but still worth doing
              if (e.target === this) {
                  dialog.remove();
              }
          });
  
          /*
           dialog.on("show.bs.modal", function() {
           // sadly this doesn't work; show is called *just* before
           // the backdrop is added so we'd need a setTimeout hack or
           // otherwise... leaving in as would be nice
           if (options.backdrop) {
           dialog.next(".modal-backdrop").addClass("bootbox-backdrop");
           }
           });
           */
  
          dialog.on("shown.bs.modal", function () {
              dialog.find(".btn-primary:first").focus();
          });
  
          /**
           * Bootbox event listeners; experimental and may not last
           * just an attempt to decouple some behaviours from their
           * respective triggers
           */
  
          dialog.on("escape.close.bb", function (e) {
              if (callbacks.onEscape) {
                  processCallback(e, dialog, callbacks.onEscape);
              }
          });
  
          /**
           * Standard jQuery event listeners; used to handle user
           * interaction with our dialog
           */
  
          dialog.on("click", ".modal-footer button", function (e) {
              var callbackKey = $(this).data("bb-handler");
  
              processCallback(e, dialog, callbacks[callbackKey]);
  
          });
  
          dialog.on("click", ".bootbox-close-button", function (e) {
              // onEscape might be falsy but that's fine; the fact is
              // if the user has managed to click the close button we
              // have to close the dialog, callback or not
              processCallback(e, dialog, callbacks.onEscape);
          });
  
          dialog.on("keyup", function (e) {
              if (e.which === 27) {
                  dialog.trigger("escape.close.bb");
              }
          });
  
          // the remainder of this method simply deals with adding our
          // dialogent to the DOM, augmenting it with Bootstrap's modal
          // functionality and then giving the resulting object back
          // to our caller
  
          $(options.container).append(dialog);
  
          dialog.modal({
              backdrop: options.backdrop,
              keyboard: false,
              show: false
          });
  
          if (options.show) {
              dialog.modal("show");
          }
  
          // @TODO should we return the raw element here or should
          // we wrap it in an object on which we can expose some neater
          // methods, e.g. var d = bootbox.alert(); d.hide(); instead
          // of d.modal("hide");
  
          /*
           function BBDialog(elem) {
           this.elem = elem;
           }
  
           BBDialog.prototype = {
           hide: function() {
           return this.elem.modal("hide");
           },
           show: function() {
           return this.elem.modal("show");
           }
           };
           */
  
          return dialog;
  
      };
  
      exports.setDefaults = function () {
          var values = {};
  
          if (arguments.length === 2) {
              // allow passing of single key/value...
              values[arguments[0]] = arguments[1];
          } else {
              // ... and as an object too
              values = arguments[0];
          }
  
          $.extend(defaults, values);
      };
  
      exports.hideAll = function () {
          $(".bootbox").modal("hide");
      };
  
  
      /**
       * standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
       * unlikely to be required. If this gets too large it can be split out into separate JS files.
       */
      var locales = {
          br: {
              OK: "OK",
              CANCEL: "Cancelar",
              CONFIRM: "Sim"
          },
          da: {
              OK: "OK",
              CANCEL: "Annuller",
              CONFIRM: "Accepter"
          },
          de: {
              OK: "OK",
              CANCEL: "Abbrechen",
              CONFIRM: "Akzeptieren"
          },
          en: {
              OK: "OK",
              CANCEL: "Cancel",
              CONFIRM: "OK"
          },
          es: {
              OK: "OK",
              CANCEL: "Cancelar",
              CONFIRM: "Aceptar"
          },
          fi: {
              OK: "OK",
              CANCEL: "Peruuta",
              CONFIRM: "OK"
          },
          fr: {
              OK: "OK",
              CANCEL: "Annuler",
              CONFIRM: "D'accord"
          },
          he: {
              OK: "אישור",
              CANCEL: "ביטול",
              CONFIRM: "אישור"
          },
          it: {
              OK: "OK",
              CANCEL: "Annulla",
              CONFIRM: "Conferma"
          },
          lt: {
              OK: "Gerai",
              CANCEL: "Atšaukti",
              CONFIRM: "Patvirtinti"
          },
          lv: {
              OK: "Labi",
              CANCEL: "Atcelt",
              CONFIRM: "Apstiprināt"
          },
          nl: {
              OK: "OK",
              CANCEL: "Annuleren",
              CONFIRM: "Accepteren"
          },
          no: {
              OK: "OK",
              CANCEL: "Avbryt",
              CONFIRM: "OK"
          },
          pl: {
              OK: "OK",
              CANCEL: "Anuluj",
              CONFIRM: "Potwierdź"
          },
          ru: {
              OK: "OK",
              CANCEL: "Отмена",
              CONFIRM: "Применить"
          },
          sv: {
              OK: "OK",
              CANCEL: "Avbryt",
              CONFIRM: "OK"
          },
          tr: {
              OK: "Tamam",
              CANCEL: "İptal",
              CONFIRM: "Onayla"
          },
          zh_CN: {
              OK: "OK",
              CANCEL: "取消",
              CONFIRM: "确认"
          },
          zh_TW: {
              OK: "OK",
              CANCEL: "取消",
              CONFIRM: "確認"
          }
      };
  
      exports.init = function (_$) {
          return init(_$ || $);
      };
  
      return exports;
  }));
  