function init() {
  window.File && window.FileReader && window.FileList && window.Blob || $.log("The File APIs are not fully supported in this browser.");
}

function VMconnection(vm_conn, id) {
  function onOpen(evt) {
    sendClientHello();
  }
  function onClose(evt) {
    -1 !== tmrId && (clearInterval(tmrId), tmrId = -1);
  }
  function onError(evt) {
    $.log(evt.data);
  }
  function sendClientHello() {
    client_hello[0] = 16, client_hello[1] = devType, setupSessionKey(), that.doSend(client_hello);
  }
  function setupSessionKey() {
    for (var sessionKey = document.cookie.replace(/(?:(?:^|.*;\s*)sessionKey\s*\=\s*([^;]*).*$)|^.*$/, "$1"), i = 0; i < sessionKey.length; i++) client_hello[2 + i] = sessionKey.charCodeAt(i);
  }
  function keepalive(ka) {
    const KEEPALIVE = 2;
    ka ? flags |= KEEPALIVE : flags &= -3;
  }
  function disconnect(dc) {
    const DISCONNECT = 4;
    dc ? flags |= DISCONNECT : flags &= -5;
  }
  this.file, this.media_sz, this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT, this.event_state = 0,
  this.media, this.wsUri = iLO.getBaseUrl("", "wss:") + "wss/vmport";
  var websocket, flags, devType = vm_conn, vmConnId = id, client_hello = new Uint8Array(34), tmrId = -1, that = this;
  this.getDevType = function() {
    return devType;
  }, this.getVmConnId = function() {
    return vmConnId;
  }, this.getWebsocket = function() {
    return websocket;
  }, this.getTmrId = function() {
    return tmrId;
  }, this.setTmrId = function(id) {
    tmrId = id;
  }, this.setMedia_sz = function(size) {
    this.media_sz = size;
  }, this.setFile = function(f) {
    this.file = f;
  }, this.createWebSocket = function() {
    if (websocket && iLO.isFunction(websocket.close)) try {
      websocket.onclose = function() {}, websocket.close();
    } catch (e) {}
    try {
      websocket = new WebSocket(this.wsUri), websocket.binaryType = "arraybuffer", websocket.onopen = function(evt) {
        onOpen(evt);
      }, websocket.onmessage = function(evt) {
        that.onMessage(evt);
      }, websocket.onerror = function(evt) {
        onError(evt);
      }, websocket.onclose = function(evt) {
        onClose(evt);
      };
    } catch (e) {
      var dlgMsg = iLO.translateString("IRC.error.newWebsocketEx") + "<br />Error: " + e.Message, msgBox = {
        titleKey: "IRC.error.newWebsocketExTitle",
        icon: myIcons.critical,
        message: dlgMsg
      };
      return void iLO.alert(msgBox);
    }
  }, this.client_test_unit_ready = function() {
    this.fdd_state === fddStateEnum.MEDIA_NOT_PRESENT ? that.sendRespHeader(2, 58, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_CHANGED ? (that.sendRespHeader(6, 40, 0, 0),
    this.fdd_state = 2) : that.sendRespHeader(0, 0, 0, 0);
  }, this.sendKeepAlive = function() {
    keepalive(!0), that.sendRespHeader(0, 0, 0, 0), keepalive(!1);
  }, this.closeVMconnection = function() {
    websocket && 1 === websocket.readyState && (showIrcToast({
      text: iLO.translateString("vm.processVMEject"),
      type: "ok",
      position: "bottom-right"
    }), disconnect(!0), that.sendRespHeader(0, 0, 0, 0), disconnect(!1));
  }, this.sendRespHeader = function(sense_key, asc, ascq, length) {
    var magic = 195936478, resp_hdr = new Uint8Array(16);
    resp_hdr[0] = 255 & magic, resp_hdr[1] = magic >> 8 & 255, resp_hdr[2] = magic >> 16 & 255,
    resp_hdr[3] = magic >> 24 & 255, resp_hdr[4] = 255 & flags, resp_hdr[5] = flags >> 8 & 255,
    resp_hdr[6] = flags >> 16 & 255, resp_hdr[7] = flags >> 24 & 255, resp_hdr[8] = this.media,
    resp_hdr[9] = sense_key, resp_hdr[10] = asc, resp_hdr[11] = ascq, resp_hdr[12] = 255 & length,
    resp_hdr[13] = length >> 8 & 255, resp_hdr[14] = length >> 16 & 255, resp_hdr[15] = length >> 24 & 255,
    that.doSend(resp_hdr);
  }, this.doSend = function(message) {
    websocket && websocket.send(message);
  };
}

function VMconnection_fd(vm_conn, id) {
  VMconnection.call(this, vm_conn, id), this.buffer = new Uint8Array(131072), this.lba,
  this.writeLen;
}

function ejectDevice(obj) {
  var id = $(obj).data("id");
  vm_conn[id].closeVMconnection();
}

function imgFileHandler(fileInput) {
  var dlgMsg = "", id = $(fileInput).data("id");
  if (/(\.img)$/i.exec(fileInput.value)) vm_conn[id] = new VMconnection_fd(vmConnType.FLOPPY, id),
  vm_conn[id].setFile(fileInput.files[0]), vm_conn[id].setMedia_sz(fileInput.files[0].size),
  vm_conn[id].createWebSocket(); else if (/(\.iso)$/i.exec(fileInput.value)) vm_conn[id] = new VMconnection(vmConnType.CDROM, id),
  vm_conn[id].setFile(fileInput.files[0]), vm_conn[id].setMedia_sz(fileInput.files[0].size),
  vm_conn[id].createWebSocket(); else {
    dlgMsg = iLO.translateString("IRC.error.UnsupportedFileType");
    var msgBox = {
      titleKey: "IRC.title.Denied",
      icon: myIcons.critical,
      message: dlgMsg,
      closeOnClick: !1
    };
    iLO.alert(msgBox);
  }
}

const SCSI_READ_CAPACITY = 37, SCSI_READ_CAPACITIES = 35, SCSI_SEND_DIAGNOSTIC = 29, SCSI_START_STOP_UNIT = 27, SCSI_TEST_UNIT_READY = 0, SCSI_PA_MEDIA_REMOVAL = 30, SCSI_READ_10 = 40, SCSI_READ_12 = 168, SCSI_WRITE_10 = 42, SCSI_WRITE_12 = 170, CDROM_SECTOR_SIZE = 2048, FLOPPY_SECTOR_SIZE = 512, CDROM_MAX_CHUNK_SIZE = 32768, FLOPPY_MAX_CHUNK_SIZE = 32768;

var fddStateEnum = {
  MEDIA_NOT_PRESENT: 0,
  MEDIA_CHANGED: 1,
  MEDIA_READY: 2
}, vmConnType = {
  FLOPPY: 1,
  CDROM: 2,
  USB: 3
}, maxNumVMConn = 10, vm_conn = new Array(maxNumVMConn);

window.onbeforeunload = function() {
  for (var i = 0; maxNumVMConn > i; i++) if ("undefined" != typeof vm_conn[i] && vm_conn[i].getWebsocket() && iLO.isFunction(vm_conn[i].getWebsocket().close)) try {
    vm_conn[i].getWebsocket().onclose = function() {}, vm_conn[i].getWebsocket().close();
  } catch (e) {}
}, window.addEventListener("load", init, !1), VMconnection.prototype.onMessage = function(evt) {
  var currTmrId = this.getTmrId();
  if (-1 !== currTmrId && (clearInterval(currTmrId), this.setTmrId(-1)), evt.data instanceof Blob) ; else if (evt.data instanceof ArrayBuffer) {
    var byteArray = new Uint8Array(evt.data);
    if (4 === evt.data.byteLength) {
      var status = byteArray[0], zero = byteArray[1], dlgMsg = "";
      if (32 == status && 0 == zero) VMconnection.numDevs++, showIrcToast({
        text: iLO.translateString("vm.imgInserted"),
        type: "ok",
        position: "bottom-right"
      }); else {
        switch (status) {
         case 33:
          dlgMsg = iLO.translateString("IRC.error.DriveInUse");
          break;

         case 34:
          dlgMsg = iLO.translateString("IRC.error.InvalidKey");
          break;

         case 35:
          dlgMsg = iLO.translateString("IRC.error.MediaNotLicensed");
          break;

         case 36:
          dlgMsg = iLO.translateString("IRC.error.KeyExpired");
          break;

         case 37:
          dlgMsg = iLO.translateString("IRC.error.DriveNotConfigured");
          break;

         case 38:
          dlgMsg = iLO.translateString("IRC.error.MediaPermitRequired");
          break;

         default:
          dlgMsg = iLO.translateString("IRC.error.CannotConnectDrive");
        }
        if (dlgMsg.length > 0) {
          var msgBox = {
            titleKey: "IRC.title.UnableToConnect",
            icon: myIcons.critical,
            message: dlgMsg,
            closeOnClick: !1
          };
          iLO.alert(msgBox);
        }
      }
    } else 12 === evt.data.byteLength && this.processSCSIRequest(byteArray);
  }
  currTmrId = setInterval(this.sendKeepAlive, 2e3), this.setTmrId(currTmrId);
}, VMconnection.prototype.processSCSIRequest = function(byteArray) {
  switch (renderer && renderer.onvmactivity && renderer.onvmactivity(), 0 === this.media_sz ? (this.media = 0,
  this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT, this.event_state = 0) : (this.media = 1,
  this.fdd_state++, this.fdd_state > fddStateEnum.MEDIA_READY && (this.fdd_state = fddStateEnum.MEDIA_READY),
  4 === this.event_state && (this.event_state = 0), this.event_state++, this.event_state > 2 && (this.event_state = 2)),
  byteArray[0]) {
   case SCSI_TEST_UNIT_READY:
    this.client_test_unit_ready();
    break;

   case SCSI_START_STOP_UNIT:
    this.client_start_stop_unit(byteArray);
    break;

   case SCSI_PA_MEDIA_REMOVAL:
    this.client_pa_media_removal(byteArray);
    break;

   case SCSI_READ_CAPACITY:
    this.client_read_capacity();
    break;

   case SCSI_READ_10:
   case SCSI_READ_12:
    this.client_read(byteArray);
    break;

   default:
    $.log("UNHANDLED SCSI REQUEST: " + byteArray[0]), this.sendRespHeader(5, 36, 0, 0);
  }
}, VMconnection.prototype.client_read_capacity = function() {
  var sz, data = new Uint8Array(8);
  this.fdd_state === fddStateEnum.MEDIA_NOT_PRESENT ? this.sendRespHeader(2, 58, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_CHANGED ? this.sendRespHeader(6, 40, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_READY && (sz = parseInt(this.media_sz / CDROM_SECTOR_SIZE) - 1,
  data[0] = sz >> 24 & 255, data[1] = sz >> 16 & 255, data[2] = sz >> 8 & 255, data[3] = sz >> 0 & 255,
  data[4] = 0, data[5] = 0, data[6] = 8, data[7] = 0, this.sendRespHeader(0, 0, 0, 8),
  this.doSend(data));
}, VMconnection.prototype.client_read = function(cmd) {
  var that = this, t = cmd[0] == SCSI_READ_12 ? 1 : 0, offset = VMconnection.mk_int32(cmd, 2) * CDROM_SECTOR_SIZE, length = t ? VMconnection.mk_int32(cmd, 6) : VMconnection.mk_int16(cmd, 7);
  length *= CDROM_SECTOR_SIZE;
  var reader = new FileReader(), bytesSent = 0, sendBytes = 0;
  if (offset >= 0 && offset + length <= this.media_sz || ($.log("offset out of range."),
  this.sendRespHeader(5, 33, 0, 0), length = 0), length > 0 && 131072 >= length) {
    reader.onloadend = function(e) {
      for (that.sendRespHeader(0, 0, 0, length); length > bytesSent; ) {
        sendBytes = Math.min(CDROM_MAX_CHUNK_SIZE, length - bytesSent);
        var bytes = new Uint8Array(e.target.result.slice(bytesSent, bytesSent + sendBytes));
        that.doSend(bytes), bytesSent += sendBytes;
      }
    }, reader.onerror = function(e) {
      $.log("reader.onerror", e), that.sendRespHeader(3, 16, 0, 0);
    };
    var blob = that.file.slice(offset, offset + length);
    reader.readAsArrayBuffer(blob);
  } else $.log("Legacy read [not implemented]");
}, VMconnection.prototype.client_start_stop_unit = function(cmd) {
  this.sendRespHeader(0, 0, 0, 0), 2 === (3 & cmd[4]) && (this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT,
  this.event_state = 4, this.closeVMconnection());
}, VMconnection.prototype.client_pa_media_removal = function(cmd) {
  0 !== (1 & cmd[4]), this.sendRespHeader(0, 0, 0, 0);
}, VMconnection.numDevs = 0, VMconnection.mk_int32 = function(cmd, pos) {
  var temp0 = cmd[pos + 0], temp1 = cmd[pos + 1], temp2 = cmd[pos + 2], temp3 = cmd[pos + 3], result = (255 & temp0) << 24 | (255 & temp1) << 16 | (255 & temp2) << 8 | 255 & temp3;
  return result;
}, VMconnection.mk_int16 = function(cmd, pos) {
  var temp0 = cmd[pos + 0], temp1 = cmd[pos + 1], result = (255 & temp0) << 8 | 255 & temp1;
  return result;
}, VMconnection.convertNumArrayToHexString = function(list) {
  for (var result = [], i = 0; i < list.length; i++) result.push(list[i].toString(16));
  return result.join(",");
}, VMconnection_fd.prototype.onMessage = function(evt) {
  var currTmrId = this.getTmrId();
  if (-1 !== currTmrId && (clearInterval(currTmrId), this.setTmrId(-1)), evt.data instanceof Blob) ; else if (evt.data instanceof ArrayBuffer) {
    var byteArray = new Uint8Array(evt.data);
    if (4 === evt.data.byteLength) {
      var status = byteArray[0], zero = byteArray[1], dlgMsg = "";
      if (32 == status && 0 == zero) VMconnection.numDevs++, showIrcToast({
        text: iLO.translateString("vm.imgInserted"),
        type: "ok",
        position: "bottom-right"
      }); else {
        switch (status) {
         case 33:
          dlgMsg = iLO.translateString("IRC.error.DriveInUse");
          break;

         case 34:
          dlgMsg = iLO.translateString("IRC.error.InvalidKey");
          break;

         case 35:
          dlgMsg = iLO.translateString("IRC.error.MediaNotLicensed");
          break;

         case 36:
          dlgMsg = iLO.translateString("IRC.error.KeyExpired");
          break;

         case 37:
          dlgMsg = iLO.translateString("IRC.error.DriveNotConfigured");
          break;

         case 38:
          dlgMsg = iLO.translateString("IRC.error.MediaPermitRequired");
          break;

         default:
          dlgMsg = iLO.translateString("IRC.error.CannotConnectDrive");
        }
        if (dlgMsg.length > 0) {
          var msgBox = {
            titleKey: "IRC.title.UnableToConnect",
            icon: myIcons.critical,
            message: dlgMsg,
            closeOnClick: !1
          };
          iLO.alert(msgBox);
        }
      }
    } else 12 === evt.data.byteLength ? this.processSCSIRequest(byteArray) : evt.data.byteLength >= FLOPPY_SECTOR_SIZE && this.client_getWriteData(byteArray);
  }
  currTmrId = setInterval(this.sendKeepAlive, 2e3), this.setTmrId(currTmrId);
}, VMconnection_fd.prototype.processSCSIRequest = function(byteArray) {
  switch (renderer && renderer.onvmactivity && renderer.onvmactivity(), this.media_sz <= 0 ? (this.media = 0,
  this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT) : (this.media = 36, this.fdd_state++,
  this.fdd_state > fddStateEnum.MEDIA_READY && (this.fdd_state = fddStateEnum.MEDIA_READY)),
  byteArray[0]) {
   case SCSI_TEST_UNIT_READY:
    this.client_test_unit_ready();
    break;

   case SCSI_START_STOP_UNIT:
    this.client_start_stop_unit(byteArray);
    break;

   case SCSI_PA_MEDIA_REMOVAL:
    this.client_pa_media_removal(byteArray);
    break;

   case SCSI_READ_CAPACITIES:
    this.client_read_capacities();
    break;

   case SCSI_READ_CAPACITY:
    this.client_read_capacity();
    break;

   case SCSI_READ_10:
   case SCSI_READ_12:
    this.client_read(byteArray);
    break;

   case SCSI_WRITE_10:
   case SCSI_WRITE_12:
    this.client_getWriteLen(byteArray);
    break;

   default:
    this.sendRespHeader(5, 36, 0, 0);
  }
}, VMconnection_fd.prototype.client_read_capacities = function() {
  var sz, rcs_resp = new Uint8Array([ 0, 0, 0, 16, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 11, 64, 0, 0, 2, 0 ]);
  this.fdd_state !== fddStateEnum.MEDIA_CHANGED ? this.sendRespHeader(0, 0, 0, rcs_resp.length) : (this.sendRespHeader(6, 40, 0, rcs_resp.length),
  this.fdd_state = fddStateEnum.MEDIA_READY), sz = parseInt(this.media_sz / FLOPPY_SECTOR_SIZE),
  rcs_resp[4] = sz >> 24 & 255, rcs_resp[5] = sz >> 16 & 255, rcs_resp[6] = sz >> 8 & 255,
  rcs_resp[7] = sz >> 0 & 255, rcs_resp[10] = 2, rcs_resp[11] = 0, this.doSend(rcs_resp);
}, VMconnection_fd.prototype.client_read_capacity = function() {
  var sz, data = new Uint8Array(8);
  this.fdd_state === fddStateEnum.MEDIA_NOT_PRESENT ? this.sendRespHeader(2, 58, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_CHANGED ? this.sendRespHeader(6, 40, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_READY && (sz = parseInt(this.media_sz / FLOPPY_SECTOR_SIZE) - 1,
  data[0] = sz >> 24 & 255, data[1] = sz >> 16 & 255, data[2] = sz >> 8 & 255, data[3] = sz >> 0 & 255,
  data[6] = 2, this.sendRespHeader(0, 0, 0, 8), this.doSend(data));
}, VMconnection_fd.prototype.client_read = function(cmd) {
  var that = this, t = cmd[0] == SCSI_READ_12 ? 1 : 0, offset = VMconnection.mk_int32(cmd, 2) * FLOPPY_SECTOR_SIZE, length = t ? VMconnection.mk_int32(cmd, 6) : VMconnection.mk_int16(cmd, 7);
  length *= FLOPPY_SECTOR_SIZE;
  var reader = new FileReader(), bytesSent = 0, sendBytes = 0;
  if (offset >= 0 && offset < this.media_sz) {
    reader.onloadend = function(e) {
      for (that.sendRespHeader(0, 0, 0, length); length > bytesSent; ) {
        sendBytes = Math.min(FLOPPY_MAX_CHUNK_SIZE, length - bytesSent);
        var bytes = new Uint8Array(e.target.result.slice(bytesSent, bytesSent + sendBytes));
        that.doSend(bytes), bytesSent += sendBytes;
      }
    }, reader.onerror = function(e) {
      that.sendRespHeader(3, 16, 0, 0);
    };
    var blob = this.file.slice(offset, offset + length);
    reader.readAsArrayBuffer(blob);
  } else this.sendRespHeader(5, 33, 0, 0);
}, VMconnection_fd.prototype.client_start_stop_unit = function(cmd) {
  this.sendRespHeader(0, 0, 0, 0), 2 === (3 & cmd[4]) && (this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT,
  this.closeVMconnection());
}, VMconnection_fd.prototype.client_pa_media_removal = function(cmd) {
  0 !== (2 & cmd[4]) ? this.sendRespHeader(5, 36, 0, 0) : this.sendRespHeader(0, 0, 0, 0);
}, VMconnection_fd.prototype.client_getWriteLen = function(cmd) {
  var t = 170 === cmd[0];
  this.lba = VMconnection.mk_int32(cmd, 2) * FLOPPY_SECTOR_SIZE, this.writeLen = t ? VMconnection.mk_int32(cmd, 6) : VMconnection.mk_int16(cmd, 7),
  this.writeLen *= FLOPPY_SECTOR_SIZE;
}, VMconnection_fd.prototype.client_getWriteData = function(cmd) {
  var numRead = cmd.length;
  "undefined" == typeof this.client_getWriteData.offset && (this.client_getWriteData.offset = 0);
  for (var i = this.client_getWriteData.offset; numRead > i; i++) this.buffer[i] = cmd[i];
  this.client_getWriteData.offset += numRead, this.writeLen -= numRead, this.writeLen <= 0 && this.client_fileWrite(this.buffer);
}, VMconnection_fd.prototype.client_fileWrite = function(buffer) {
  this.sendRespHeader(0, 0, 0, 0);
};