function addAlert(
    addToEl, alertMessage,
    type = "primary",
    timeout = 5,
    info = undefined,
    onAdd, onClose
  ) {
    function setAttributes(el, attrs) {
      if (!attrs)
        return;
      for (var key in attrs) 
        el.setAttribute(key, attrs[key]);
    }
    function addElement({
      tag = "div", parent = null,
      classes = [], attrs = {},
      innerText = null,
      children = []
    } = {}) {
      let result = document.createElement(tag);
      result.innerText = innerText;
      result.classList.add(...classes);
      setAttributes(result, attrs)
      parent?.appendChild(result);
      result.append(...(children?.filter(c => c) ?? []));
      return result;
    }

    if (!info && ["success", "danger", "warning", "info"].includes(type.toLowerCase()))
      info = type.charAt(0).toUpperCase() + type.slice(1);

    let alertDiv = null;
    addElement(
    { 
      parent: addToEl, classes: ["container"],
      children: 
      [
        alertDiv = addElement(
        {
          classes: ["alert", "alert-" + type, "alert-dismissible", "fade", "show"], role: "alert",
          children: 
          [
            info ? addElement({tag: "strong", innerText: info + " "}) : null,
            addElement({tag: "a", innerText: alertMessage}),
            addElement({ tag: "button", classes: ["btn-close"], attrs: {"type": "button", "data-bs-dismiss": "alert", "aria-label": "Close" }})
          ]
        })
      ]
    });

    if (onClose)
      alertDiv.addEventListener("closed.bs.alert", onClose);
    if (onAdd)
      onAdd();
    if (timeout > 0)
    {
      var bootstrapAlert = new bootstrap.Alert(alertDiv);
      setTimeout(() => bootstrapAlert.close(), timeout * 1000);
    }
  }
