<commit_before>import find from 'lodash/find'
import forEach from 'lodash/forEach'
import fromEvent from 'promise-toolbox/fromEvent'
import xml2js from 'xml2js'
import { ensureArray } from 'utils'
import { readVmdkGrainTable } from 'xo-vmdk-to-vhd'

// ===================================================================

// See: http://opennodecloud.com/howto/2013/12/25/howto-ON-ovf-reference.html
// See: http://www.dmtf.org/sites/default/files/standards/documents/DSP0243_1.0.0.pdf
// See: http://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.0.pdf

// ===================================================================

const MEMORY_UNIT_TO_FACTOR = {
  k: 1024,
  m: 1048576,
  g: 1073741824,
  t: 1099511627776,
}

const RESOURCE_TYPE_TO_HANDLER = {
  // CPU.
  '3': (data, { 'rasd:VirtualQuantity': nCpus }) => {
    data.nCpus = +nCpus
  },
  // RAM.
  '4': (
    data,
    { 'rasd:AllocationUnits': unit, 'rasd:VirtualQuantity': quantity }
  ) => {
    data.memory = quantity * allocationUnitsToFactor(unit)
  },
  // Network.
  '10': (
    { networks },
    { 'rasd:AutomaticAllocation': enabled, 'rasd:Connection': name }
  ) => {
    if (enabled) {
      networks.push(name)
    }
  },
  // Disk.
  '17': (
    { disks },
    {
      'rasd:AddressOnParent': position,
      'rasd:Description': description = 'No description',
      'rasd:ElementName': name,
      'rasd:HostResource': resource,
    }
  ) => {
    const diskId = resource.match(/^(?:ovf:)?\/disk\/(.+)$/)
    const disk = diskId && disks[diskId[1]]

    if (disk) {
      disk.descriptionLabel = description
      disk.nameLabel = name
      disk.position = +position
    } else {
      // TODO: Log error in U.I.
      console.error(`No disk found: '${diskId}'.`)
    }
  },
}

const allocationUnitsToFactor = unit => {
  const intValue = unit.match(/\^([0-9]+)$/)
  return intValue != null
    ? Math.pow(2, intValue[1])
    : MEMORY_UNIT_TO_FACTOR[unit.charAt(0).toLowerCase()]
}

const filterDisks = disks => {
  for (const diskId in disks) {
    if (disks[diskId].position == null) {
      // TODO: Log error in U.I.
      console.error(`No position specified for '${diskId}'.`)
      delete disks[diskId]
    }
  }
}

// ===================================================================
/* global FileReader, TextDecoder */

async function readFileFragment (file, start = 0, end) {
  const reader = new FileReader()
  reader.readAsArrayBuffer(file.slice(start, end))
  return (await fromEvent(reader, 'loadend')).target.result
}

function parseTarHeader (header) {
  const textDecoder = new TextDecoder('ascii')
  const fileName = textDecoder.decode(header.slice(0, 100)).split('\0')[0]
  if (fileName.length === 0) {
    return null
  }
  const fileSize = parseInt(textDecoder.decode(header.slice(124, 124 + 11)), 8)
  return { fileName, fileSize }
}

async function parseOVF (fileFragment) {
  const textDecoder = new TextDecoder('utf-8')
  const xmlString = textDecoder.decode(await readFileFragment(fileFragment))
  return new Promise((resolve, reject) =>
    xml2js.parseString(
      xmlString,
      { mergeAttrs: true, explicitArray: false },
      (err, res) => {
        if (err) {
          reject(err)
          return
        }

        const {
          Envelope: {<commit_msg>fix(xo-web): avoid using TextDecoder (#3718)<commit_after>import find from 'lodash/find'
import forEach from 'lodash/forEach'
import fromEvent from 'promise-toolbox/fromEvent'
import xml2js from 'xml2js'
import { ensureArray } from 'utils'
import { readVmdkGrainTable } from 'xo-vmdk-to-vhd'

// ===================================================================

// See: http://opennodecloud.com/howto/2013/12/25/howto-ON-ovf-reference.html
// See: http://www.dmtf.org/sites/default/files/standards/documents/DSP0243_1.0.0.pdf
// See: http://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.0.pdf

// ===================================================================

const MEMORY_UNIT_TO_FACTOR = {
  k: 1024,
  m: 1048576,
  g: 1073741824,
  t: 1099511627776,
}

const RESOURCE_TYPE_TO_HANDLER = {
  // CPU.
  '3': (data, { 'rasd:VirtualQuantity': nCpus }) => {
    data.nCpus = +nCpus
  },
  // RAM.
  '4': (
    data,
    { 'rasd:AllocationUnits': unit, 'rasd:VirtualQuantity': quantity }
  ) => {
    data.memory = quantity * allocationUnitsToFactor(unit)
  },
  // Network.
  '10': (
    { networks },
    { 'rasd:AutomaticAllocation': enabled, 'rasd:Connection': name }
  ) => {
    if (enabled) {
      networks.push(name)
    }
  },
  // Disk.
  '17': (
    { disks },
    {
      'rasd:AddressOnParent': position,
      'rasd:Description': description = 'No description',
      'rasd:ElementName': name,
      'rasd:HostResource': resource,
    }
  ) => {
    const diskId = resource.match(/^(?:ovf:)?\/disk\/(.+)$/)
    const disk = diskId && disks[diskId[1]]

    if (disk) {
      disk.descriptionLabel = description
      disk.nameLabel = name
      disk.position = +position
    } else {
      // TODO: Log error in U.I.
      console.error(`No disk found: '${diskId}'.`)
    }
  },
}

const allocationUnitsToFactor = unit => {
  const intValue = unit.match(/\^([0-9]+)$/)
  return intValue != null
    ? Math.pow(2, intValue[1])
    : MEMORY_UNIT_TO_FACTOR[unit.charAt(0).toLowerCase()]
}

const filterDisks = disks => {
  for (const diskId in disks) {
    if (disks[diskId].position == null) {
      // TODO: Log error in U.I.
      console.error(`No position specified for '${diskId}'.`)
      delete disks[diskId]
    }
  }
}

// ===================================================================
/* global FileReader */

async function readFileFragment (file, start = 0, end) {
  const reader = new FileReader()
  reader.readAsArrayBuffer(file.slice(start, end))
  return (await fromEvent(reader, 'loadend')).target.result
}

function parseTarHeader (header) {
  const fileName = Buffer.from(header.slice(0, 100))
    .toString('ascii')
    .split('\0')[0]
  if (fileName.length === 0) {
    return null
  }
  const fileSize = parseInt(
    Buffer.from(header.slice(124, 124 + 11)).toString('ascii'),
    8
  )
  return { fileName, fileSize }
}

async function parseOVF (fileFragment) {
  const xmlString = Buffer.from(await readFileFragment(fileFragment)).toString()
  return new Promise((resolve, reject) =>
    xml2js.parseString(
      xmlString,
      { mergeAttrs: true, explicitArray: false },
      (err, res) => {
        if (err) {
          reject(err)
          return
        }

        const {
          Envelope: {
{'fraction_non_alphanumeric': 0.20889159561510354, 'fraction_numerical': 0.027557856272838, 'mean_word_length': 3.2028150991682662, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2760936', 'n_tokens_mistral': 2330, 'n_tokens_neox': 2197, 'n_words': 432}