<commit_before>import SPECS from 'game/SPECS';
import RACES from 'game/RACES';
import TALENT_ROWS from 'game/TALENT_ROWS';
import GEAR_SLOTS from 'game/GEAR_SLOTS';
import traitIdMap from 'common/TraitIdMap';
import SPELLS from 'common/SPELLS';
import { findByBossId } from 'raids/index';
import Entity from './Entity';

class Combatant extends Entity {
  get id() {
    return this._combatantInfo.sourceID;
  }
  get name() {
    return this._combatantInfo.name;
  }
  get specId() {
    return this._combatantInfo.specID;
  }
  get spec() {
    return SPECS[this.specId];
  }
  get race() {
    if (!this.owner.characterProfile) {
      return null;
    }
    const raceId = this.owner.characterProfile.race;
    let race = Object.values(RACES).find(race => race.id === raceId);
    if (!this.owner.boss) {
      return race;
    }
    const boss = findByBossId(this.owner.boss.id);
    if (boss && boss.fight.raceTranslation) {
      race = boss.fight.raceTranslation(race, this.spec);
    }
    return race;
  }
  get characterProfile() {
    return this.owner.characterProfile;
  }

  _combatantInfo = null;
  constructor(parser, combatantInfo) {
    super(parser);

    const playerInfo = parser.players.find(player => player.id === combatantInfo.sourceID);
    this._combatantInfo = {
      // In super rare cases `playerInfo` can be undefined, not taking this into account would cause the log to be unparsable
      name: playerInfo && playerInfo.name,
      ...combatantInfo,
    };

    this._parseTalents(combatantInfo.talents);
    this._parseTraits(combatantInfo.artifact);
    this._parseEssences(combatantInfo.heartOfAzeroth);
    this._parseGear(combatantInfo.gear);
    this._parsePrepullBuffs(combatantInfo.auras);
  }

  // region Talents
  _talentsByRow = {};
  _parseTalents(talents) {
    talents.forEach(({ id }, index) => {
      this._talentsByRow[index] = id;
    });
  }
  get talents() {
    return Object.values(this._talentsByRow);
  }
  _getTalent(row) {
    return this._talentsByRow[row];
  }
  get lv15Talent() {
    return this._getTalent(TALENT_ROWS.LV15);
  }
  get lv30Talent() {
    return this._getTalent(TALENT_ROWS.LV30);
  }
  get lv45Talent() {
    return this._getTalent(TALENT_ROWS.LV45);
  }
  get lv60Talent() {
    return this._getTalent(TALENT_ROWS.LV60);
  }
  get lv75Talent() {
    return this._getTalent(TALENT_ROWS.LV75);
  }
  get lv90Talent() {
    return this._getTalent(TALENT_ROWS.LV90);
  }
  get lv100Talent() {
    return this._getTalent(TALENT_ROWS.LV100);
  }
  hasTalent(spell) {
    const spellId = spell instanceof Object ? spell.id : spell;
    return !!Object.keys(this._talentsByRow).find(row => this._talentsByRow[row] === spellId);
  }
  // endregion

  // region Traits
  traitsBySpellId = {};
  _parseTraits(traits) {
    traits.forEach(({ traitID, rank }) => {
      const spellId = traitIdMap[traitID];
      if (spellId === undefined) {
        return;
      }
      if (!this.traitsBySpellId[spellId]) {
        this.traitsBySpellId[spellId] = [];
      }
      this.traitsBySpellId[spellId].push(rank);
    });
  }
  hasTrait(spellId) {
    return !!this.traitsBySpellId[spellId];
  }
  traitRanks(spellId) {
    return this.traitsBySpellId[spellId];
  }
  // endregion

  // region Essences
  essencesByTraitID = {};
  _parseEssences(essences) {
    if(essences === undefined) {
      return;
    }
    essences.forEach((essence) => {
      if (!!this.essencesByTraitID[essence.traitID]) {
        essence.isMajor = true;
      }
      this.essencesByTraitID[essence.traitID] = essence;
      //essence = {icon:string, isMajor:bool, rank:int, slot:int, spellID:int, traitID:int}
    });
  }
  hasEssence(traitId) {
    return !!this.essencesByTraitID[traitId];
  }
  hasMajor(traitId) {
    return this.essencesByTraitID[traitId].isMajor;
  }
  essenceRank(traitId) {
    return this.essencesByTraitID[traitId] && this.essencesByTraitID[traitId].rank;
  }
  // endregion

  // region Gear
  _gearItemsBySlotId = {};
  _parseGear(gear) {
    gear.forEach((item, index) => {
      this._gearItemsBySlotId[index] = item;
    });
  }
  _getGearItemBySlotId(slotId) {
    return this._gearItemsBySlotId[slotId];
  }
  _getGearItemGemsBySlotId(slotId) {
    if (this._gearItemsBySlotId[slotId].gems) {
      return this._gearItemsBySlotId[slotId].gems;
    }
    return undefined;
  }
  get gear() {
    return Object.values(this._gearItemsBySlotId);
  }
  get head() {
    return this._getGearItemBySlotId(GEAR_SLOTS.HEAD);
  }
  hasHead(itemId) {
    return this.head && this.head.id === itemId;
  }
  get neck() {
    return this._getGearItemBySlotId(GEAR_SLOTS.NECK);
  }
  hasNeck(itemId) {
    return this.neck && this.neck.id === itemId;
  }
  get shoulder() {
    return this._getGearItemBySlotId(GEAR_SLOTS.SHOULDER);
  }
  hasShoulder(itemId) {
    return this.shoulder && this.shoulder.id === itemId;
  }
  get back() {
    return this._getGearItemBySlotId(GEAR_SLOTS.BACK);
  }
  hasBack(itemId) {<commit_msg>proper fix<commit_after>import SPECS from 'game/SPECS';
import RACES from 'game/RACES';
import TALENT_ROWS from 'game/TALENT_ROWS';
import GEAR_SLOTS from 'game/GEAR_SLOTS';
import traitIdMap from 'common/TraitIdMap';
import SPELLS from 'common/SPELLS';
import { findByBossId } from 'raids/index';
import Entity from './Entity';

class Combatant extends Entity {
  get id() {
    return this._combatantInfo.sourceID;
  }
  get name() {
    return this._combatantInfo.name;
  }
  get specId() {
    return this._combatantInfo.specID;
  }
  get spec() {
    return SPECS[this.specId];
  }
  get race() {
    if (!this.owner.characterProfile) {
      return null;
    }
    const raceId = this.owner.characterProfile.race;
    let race = Object.values(RACES).find(race => race.id === raceId);
    if (!this.owner.boss) {
      return race;
    }
    const boss = findByBossId(this.owner.boss.id);
    if (boss && boss.fight.raceTranslation) {
      race = boss.fight.raceTranslation(race, this.spec);
    }
    return race;
  }
  get characterProfile() {
    return this.owner.characterProfile;
  }

  _combatantInfo = null;
  constructor(parser, combatantInfo) {
    super(parser);

    const playerInfo = parser.players.find(player => player.id === combatantInfo.sourceID);
    this._combatantInfo = {
      // In super rare cases `playerInfo` can be undefined, not taking this into account would cause the log to be unparsable
      name: playerInfo && playerInfo.name,
      ...combatantInfo,
    };

    this._parseTalents(combatantInfo.talents);
    this._parseTraits(combatantInfo.artifact);
    this._parseEssences(combatantInfo.heartOfAzeroth);
    this._parseGear(combatantInfo.gear);
    this._parsePrepullBuffs(combatantInfo.auras);
  }

  // region Talents
  _talentsByRow = {};
  _parseTalents(talents) {
    talents.forEach(({ id }, index) => {
      this._talentsByRow[index] = id;
    });
  }
  get talents() {
    return Object.values(this._talentsByRow);
  }
  _getTalent(row) {
    return this._talentsByRow[row];
  }
  get lv15Talent() {
    return this._getTalent(TALENT_ROWS.LV15);
  }
  get lv30Talent() {
    return this._getTalent(TALENT_ROWS.LV30);
  }
  get lv45Talent() {
    return this._getTalent(TALENT_ROWS.LV45);
  }
  get lv60Talent() {
    return this._getTalent(TALENT_ROWS.LV60);
  }
  get lv75Talent() {
    return this._getTalent(TALENT_ROWS.LV75);
  }
  get lv90Talent() {
    return this._getTalent(TALENT_ROWS.LV90);
  }
  get lv100Talent() {
    return this._getTalent(TALENT_ROWS.LV100);
  }
  hasTalent(spell) {
    const spellId = spell instanceof Object ? spell.id : spell;
    return !!Object.keys(this._talentsByRow).find(row => this._talentsByRow[row] === spellId);
  }
  // endregion

  // region Traits
  traitsBySpellId = {};
  _parseTraits(traits) {
    traits.forEach(({ traitID, rank }) => {
      const spellId = traitIdMap[traitID];
      if (spellId === undefined) {
        return;
      }
      if (!this.traitsBySpellId[spellId]) {
        this.traitsBySpellId[spellId] = [];
      }
      this.traitsBySpellId[spellId].push(rank);
    });
  }
  hasTrait(spellId) {
    return !!this.traitsBySpellId[spellId];
  }
  traitRanks(spellId) {
    return this.traitsBySpellId[spellId];
  }
  // endregion

  // region Essences
  essencesByTraitID = {};
  _parseEssences(essences) {
    if(essences === undefined) {
      return;
    }
    essences.forEach((essence) => {
      if (!!this.essencesByTraitID[essence.traitID]) {
        essence.isMajor = true;
      }
      this.essencesByTraitID[essence.traitID] = essence;
      //essence = {icon:string, isMajor:bool, rank:int, slot:int, spellID:int, traitID:int}
    });
  }
  hasEssence(traitId) {
    return !!this.essencesByTraitID[traitId];
  }
  hasMajor(traitId) {
    return this.essencesByTraitID[traitId].isMajor;
  }
  essenceRank(traitId) {
    return this.essencesByTraitID[traitId] && this.essencesByTraitID[traitId].rank;
  }
  // endregion

  // region Gear
  _gearItemsBySlotId = {};
  _parseGear(gear) {
    gear.forEach((item, index) => {
      this._gearItemsBySlotId[index] = item;
    });
  }
  _getGearItemBySlotId(slotId) {
    return this._gearItemsBySlotId[slotId];
  }
  _getGearItemGemsBySlotId(slotId) {
    if (this._gearItemsBySlotId[slotId]) {
      return this._gearItemsBySlotId[slotId].gems;
    }
    return undefined;
  }
  get gear() {
    return Object.values(this._gearItemsBySlotId);
  }
  get head() {
    return this._getGearItemBySlotId(GEAR_SLOTS.HEAD);
  }
  hasHead(itemId) {
    return this.head && this.head.id === itemId;
  }
  get neck() {
    return this._getGearItemBySlotId(GEAR_SLOTS.NECK);
  }
  hasNeck(itemId) {
    return this.neck && this.neck.id === itemId;
  }
  get shoulder() {
    return this._getGearItemBySlotId(GEAR_SLOTS.SHOULDER);
  }
  hasShoulder(itemId) {
    return this.shoulder && this.shoulder.id === itemId;
  }
  get back() {
    return this._getGearItemBySlotId(GEAR_SLOTS.BACK);
  }
  hasBack(itemId) {
{'fraction_non_alphanumeric': 0.13131009615384615, 'fraction_numerical': 0.006009615384615385, 'mean_word_length': 3.290932531155995, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '1181462', 'n_tokens_mistral': 3794, 'n_tokens_neox': 3703, 'n_words': 587}