<commit_before>import * as _ from 'lodash';
import { DimItem, DimSockets, DimGridNode } from './item-types';
import { t } from 'i18next';
import * as Papa from 'papaparse';
import { getActivePlatform } from '../accounts/platform.service';
import { getItemInfoSource, TagValue } from './dim-item-info';
import { DimStore } from './store-types';

// step node names we'll hide, we'll leave "* Chroma" for now though, since we don't otherwise indicate Chroma
const FILTER_NODE_NAMES = [
  'Upgrade Defense',
  'Ascend',
  'Infuse',
  'Increase Intellect',
  'Increase Discipline',
  'Increase Strength',
  'Twist Fate',
  'The Life Exotic',
  'Reforge Artifact',
  'Reforge Shell',
  'Deactivate Chroma',
  'Kinetic Damage',
  'Solar Damage',
  'Arc Damage',
  'Void Damage',
  'Default Shader',
  'Default Ornament',
  'Empty Mod Socket',
  'No Projection'
];

const events = ['', 'Dawning', 'Crimson Days', 'Solstice of Heroes', 'Festival of the Lost'];

function capitalizeFirstLetter(str: string) {
  if (!str || str.length === 0) {
    return '';
  }
  return str.charAt(0).toUpperCase() + str.slice(1);
}

function downloadCsv(filename: string, csv: string) {
  filename = `${filename}.csv`;
  const pom = document.createElement('a');
  pom.setAttribute('href', `data:text/csv;charset=utf-8,${encodeURIComponent(csv)}`);
  pom.setAttribute('download', filename);
  document.body.appendChild(pom);
  pom.click();
  document.body.removeChild(pom);
}

function buildSocketNames(sockets: DimSockets): string[] {
  const socketItems = sockets.sockets.map((s) =>
    s.plugOptions
      .filter((p) => !FILTER_NODE_NAMES.some((n) => n === p.plugItem.displayProperties.name))
      .map((p) =>
        s.plug && s.plug.plugItem.hash && p.plugItem.hash === s.plug.plugItem.hash
          ? `${p.plugItem.displayProperties.name}*`
          : p.plugItem.displayProperties.name
      )
  );

  return _.flatten(socketItems);
}

function buildNodeNames(nodes: DimGridNode[]): string[] {
  return _.compact(
    nodes.map((node) => {
      if (FILTER_NODE_NAMES.includes(node.name)) {
        return;
      }
      return node.activated ? `${node.name}*` : node.name;
    })
  );
}

function getMaxPerks(items: DimItem[]) {
  // We need to always emit enough columns for all perks
  return (
    _.max(
      items.map(
        (item) =>
          (item.talentGrid
            ? buildNodeNames(item.talentGrid.nodes)
            : item.isDestiny2() && item.sockets
            ? buildSocketNames(item.sockets)
            : []
          ).length
      )
    ) || 0
  );
}

function addPerks(row: object, item: DimItem, maxPerks: number) {
  const perks = item.talentGrid
    ? buildNodeNames(item.talentGrid.nodes)
    : item.isDestiny2() && item.sockets
    ? buildSocketNames(item.sockets)
    : [];

  _.times(maxPerks, (index) => {
    row[`Perks ${index}`] = perks[index];
  });
}

function downloadGhost(items: DimItem[], nameMap: { [key: string]: string }) {
  // We need to always emit enough columns for all perks
  const maxPerks = getMaxPerks(items);

  const data = items.map((item) => {
    const row: any = {
      Name: item.name,
      Hash: item.hash,
      Id: item.id,
      Tag: item.dimInfo.tag,
      Tier: item.tier,
      Owner: nameMap[item.owner],
      Locked: item.locked,
      Equipped: item.equipped
    };

    addPerks(row, item, maxPerks);

    return row;
  });

  downloadCsv('destinyGhosts', Papa.unparse(data));
}

function equippable(item: DimItem) {
  let equippable = item.classTypeName;
  if (!equippable || equippable === 'unknown') {
    equippable =
      !equippable || equippable === 'unknown' ? 'Any' : capitalizeFirstLetter(equippable);
  }
  return equippable;<commit_msg>add notes to the ghost csv<commit_after>import * as _ from 'lodash';
import { DimItem, DimSockets, DimGridNode } from './item-types';
import { t } from 'i18next';
import * as Papa from 'papaparse';
import { getActivePlatform } from '../accounts/platform.service';
import { getItemInfoSource, TagValue } from './dim-item-info';
import { DimStore } from './store-types';

// step node names we'll hide, we'll leave "* Chroma" for now though, since we don't otherwise indicate Chroma
const FILTER_NODE_NAMES = [
  'Upgrade Defense',
  'Ascend',
  'Infuse',
  'Increase Intellect',
  'Increase Discipline',
  'Increase Strength',
  'Twist Fate',
  'The Life Exotic',
  'Reforge Artifact',
  'Reforge Shell',
  'Deactivate Chroma',
  'Kinetic Damage',
  'Solar Damage',
  'Arc Damage',
  'Void Damage',
  'Default Shader',
  'Default Ornament',
  'Empty Mod Socket',
  'No Projection'
];

const events = ['', 'Dawning', 'Crimson Days', 'Solstice of Heroes', 'Festival of the Lost'];

function capitalizeFirstLetter(str: string) {
  if (!str || str.length === 0) {
    return '';
  }
  return str.charAt(0).toUpperCase() + str.slice(1);
}

function downloadCsv(filename: string, csv: string) {
  filename = `${filename}.csv`;
  const pom = document.createElement('a');
  pom.setAttribute('href', `data:text/csv;charset=utf-8,${encodeURIComponent(csv)}`);
  pom.setAttribute('download', filename);
  document.body.appendChild(pom);
  pom.click();
  document.body.removeChild(pom);
}

function buildSocketNames(sockets: DimSockets): string[] {
  const socketItems = sockets.sockets.map((s) =>
    s.plugOptions
      .filter((p) => !FILTER_NODE_NAMES.some((n) => n === p.plugItem.displayProperties.name))
      .map((p) =>
        s.plug && s.plug.plugItem.hash && p.plugItem.hash === s.plug.plugItem.hash
          ? `${p.plugItem.displayProperties.name}*`
          : p.plugItem.displayProperties.name
      )
  );

  return _.flatten(socketItems);
}

function buildNodeNames(nodes: DimGridNode[]): string[] {
  return _.compact(
    nodes.map((node) => {
      if (FILTER_NODE_NAMES.includes(node.name)) {
        return;
      }
      return node.activated ? `${node.name}*` : node.name;
    })
  );
}

function getMaxPerks(items: DimItem[]) {
  // We need to always emit enough columns for all perks
  return (
    _.max(
      items.map(
        (item) =>
          (item.talentGrid
            ? buildNodeNames(item.talentGrid.nodes)
            : item.isDestiny2() && item.sockets
            ? buildSocketNames(item.sockets)
            : []
          ).length
      )
    ) || 0
  );
}

function addPerks(row: object, item: DimItem, maxPerks: number) {
  const perks = item.talentGrid
    ? buildNodeNames(item.talentGrid.nodes)
    : item.isDestiny2() && item.sockets
    ? buildSocketNames(item.sockets)
    : [];

  _.times(maxPerks, (index) => {
    row[`Perks ${index}`] = perks[index];
  });
}

function downloadGhost(items: DimItem[], nameMap: { [key: string]: string }) {
  // We need to always emit enough columns for all perks
  const maxPerks = getMaxPerks(items);

  const data = items.map((item) => {
    const row: any = {
      Name: item.name,
      Hash: item.hash,
      Id: item.id,
      Tag: item.dimInfo.tag,
      Tier: item.tier,
      Owner: nameMap[item.owner],
      Locked: item.locked,
      Equipped: item.equipped,
      Notes: item.dimInfo.notes
    };

    addPerks(row, item, maxPerks);

    return row;
  });

  downloadCsv('destinyGhosts', Papa.unparse(data));
}

function equippable(item: DimItem) {
  let equippable = item.classTypeName;
  if (!equippable || equippable === 'unknown') {
    equippable =
      !equippable || equippable === 'unknown' ? 'Any' : capitalizeFirstLetter(equippable);
  }
  return equippable;
{'fraction_non_alphanumeric': 0.15417558886509636, 'fraction_numerical': 0.0024089935760171306, 'mean_word_length': 3.2556947608200457, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4759785', 'n_tokens_mistral': 2566, 'n_tokens_neox': 2509, 'n_words': 554}