@firestone-hs/bgs-global-stats 1.0.33 → 1.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,11 @@ export declare const handleNewStats: (event: any, context: Context) => Promise<{
8
8
  statusCode: number;
9
9
  body: any;
10
10
  }>;
11
+ export declare const buildWarbandStats: (rows: readonly InternalBgsRow[]) => readonly {
12
+ turn: number;
13
+ dataPoints: number;
14
+ totalStats: number;
15
+ }[];
11
16
  export declare const buildCombatWinrate: (rows: readonly InternalBgsRow[]) => readonly {
12
17
  turn: number;
13
18
  dataPoints: number;
@@ -277,7 +277,7 @@ const buildHeroStats = (rows) => {
277
277
  const ref = groupedRows[0];
278
278
  const placementDistribution = common_1.buildPlacementDistribution(groupedRows);
279
279
  const combatWinrate = exports.buildCombatWinrate(groupedRows);
280
- const warbandStats = buildWarbandStats(groupedRows);
280
+ const warbandStats = exports.buildWarbandStats(groupedRows);
281
281
  return {
282
282
  cardId: util_functions_1.normalizeHeroCardId(ref.heroCardId, allCards),
283
283
  totalMatches: groupedRows.length,
@@ -288,7 +288,7 @@ const buildHeroStats = (rows) => {
288
288
  });
289
289
  return result;
290
290
  };
291
- const buildWarbandStats = (rows) => {
291
+ exports.buildWarbandStats = (rows) => {
292
292
  var _a, _b, _c;
293
293
  const data = {};
294
294
  const validRows = rows.filter(row => row.id > 5348374);
@@ -1 +1 @@
1
- {"version":3,"file":"build-battlegrounds-hero-stats-new.js","sourceRoot":"/","sources":["build-battlegrounds-hero-stats-new.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { getConnection, groupByFunction, http, logBeforeTimeout, logger, S3 } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds, Race } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { ServerlessMysql } from 'serverless-mysql';\r\nimport { Readable } from 'stream';\r\nimport { gzipSync } from 'zlib';\r\nimport { BgsGlobalHeroStat2, BgsGlobalStats2, MmrPercentile } from './bgs-global-stats';\r\nimport { buildMmrPercentiles, buildPlacementDistribution, filterRowsForTimePeriod, PatchInfo } from './common';\r\nimport { InternalBgsRow } from './internal-model';\r\nimport { handleQuests } from './quests';\r\nimport { handleQuestsV2 } from './quests-v2/quests-v2';\r\nimport { handleStatsV2 } from './stats-v2/stats-v2';\r\nimport { formatDate, normalizeHeroCardId } from './utils/util-functions';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allTimePeriods: ('all-time' | 'past-three' | 'past-seven' | 'last-patch')[] = [\r\n\t'all-time',\r\n\t'past-three',\r\n\t'past-seven',\r\n\t'last-patch',\r\n];\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\tlogger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\tconst lastPatch = await getLastBattlegroundsPatch();\r\n\r\n\tif (event.quests) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuests(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.questsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuestsV2(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.statsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleStatsV2(timePeriod, rows, lastPatch, allCards);\r\n\t\t}\r\n\t} else if (event.permutation) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handlePermutation(event.permutation, timePeriod, event.allTribes, rows, lastPatch);\r\n\t\t}\r\n\t} else {\r\n\t\tconst mysql = await getConnection();\r\n\t\tconst rows: readonly InternalBgsRow[] = await loadRows(mysql);\r\n\t\tawait mysql.end();\r\n\t\tawait saveRowsOnS3(rows);\r\n\t\tawait dispatchNewLambdas(rows, context);\r\n\t\tawait dispatchQuestsLambda(rows, context);\r\n\t\tawait dispatchQuestsV2Lambda(rows, context);\r\n\t\tawait dispatchStatsV2Lambda(rows, context);\r\n\t}\r\n\r\n\tcleanup();\r\n\treturn { statusCode: 200, body: null };\r\n};\r\n\r\nconst dispatchQuestsLambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquests: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquestsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tstatsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchNewLambdas = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst allTribes = extractAllTribes(rows);\r\n\tlogger.log('all tribes', allTribes);\r\n\tconst tribePermutations: ('all' | Race[])[] = ['all', ...combine(allTribes, 5)];\r\n\tlogger.log('tribe permutations, should be 127 (126 + 1), because 9 tribes', tribePermutations.length);\r\n\tfor (const tribes of tribePermutations) {\r\n\t\tlogger.log('handling tribes', tribes, tribes !== 'all' && tribes.join('-'));\r\n\t\t// if (tribes !== 'all') {\r\n\t\t// \tcontinue;\r\n\t\t// }\r\n\t\tconst newEvent = {\r\n\t\t\tpermutation: tribes,\r\n\t\t\tallTribes: allTribes,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tlogger.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\tlogger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst handlePermutation = async (\r\n\ttribes: 'all' | readonly Race[],\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\tallTribes: readonly Race[],\r\n\trows: readonly InternalBgsRow[],\r\n\tlastPatch: PatchInfo,\r\n) => {\r\n\tconsole.log('total rows', rows.length);\r\n\tconst rowsForTimePeriod = filterRowsForTimePeriod(rows, timePeriod, lastPatch);\r\n\tconsole.log('rows for time period', rowsForTimePeriod.length);\r\n\tconst tribesStr = tribes === 'all' ? null : tribes.join(',');\r\n\tconst rowsWithTribes = !!tribesStr\r\n\t\t? rowsForTimePeriod.filter(row => !!row.tribes).filter(row => row.tribes === tribesStr)\r\n\t\t: rowsForTimePeriod;\r\n\tconsole.log('rowsWithTribes', rowsWithTribes.length);\r\n\tconst mmrPercentiles: readonly MmrPercentile[] = buildMmrPercentiles(rowsWithTribes);\r\n\tlogger.log('handling permutation', tribes, timePeriod, rows?.length, rowsWithTribes?.length);\r\n\tconst stats: readonly BgsGlobalHeroStat2[] = buildHeroes(rowsWithTribes, mmrPercentiles).map(stat => ({\r\n\t\t...stat,\r\n\t\ttribes: tribes === 'all' ? allTribes : tribes,\r\n\t\tdate: timePeriod,\r\n\t}));\r\n\tconst statsForTribes: BgsGlobalStats2 = {\r\n\t\tlastUpdateDate: formatDate(new Date()),\r\n\t\tmmrPercentiles: mmrPercentiles,\r\n\t\theroStats: stats,\r\n\t\tallTribes: allTribes,\r\n\t\ttotalMatches: stats.map(s => s.totalMatches).reduce((a, b) => a + b, 0),\r\n\t};\r\n\tlogger.log('\\tbuilt stats', statsForTribes.totalMatches, statsForTribes.heroStats?.length);\r\n\tconst tribesSuffix = tribes === 'all' ? 'all-tribes' : tribes.join('-');\r\n\tconst timeSuffix = timePeriod;\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(statsForTribes)),\r\n\t\t'static.zerotoheroes.com',\r\n\t\t`api/bgs/heroes/bgs-global-stats-${tribesSuffix}-${timeSuffix}.gz.json`,\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n\r\nconst saveRowsOnS3 = async (rows: readonly InternalBgsRow[]) => {\r\n\tlogger.log('saving rows on s3', rows.length);\r\n\tawait s3.writeArrayAsMultipart(rows, 'static.zerotoheroes.com', `api/bgs/working-rows.json`, 'application/json');\r\n\tlogger.log('file saved');\r\n};\r\n\r\nconst readRowsFromS3 = async (): Promise<readonly InternalBgsRow[]> => {\r\n\treturn new Promise<readonly InternalBgsRow[]>((resolve, reject) => {\r\n\t\tlet parseErrors = 0;\r\n\t\tlet totalParsed = 0;\r\n\t\tconst stream: Readable = s3.readStream('static.zerotoheroes.com', `api/bgs/working-rows.json`);\r\n\t\tconst result: InternalBgsRow[] = [];\r\n\t\tlet previousString = '';\r\n\t\tstream\r\n\t\t\t.on('data', chunk => {\r\n\t\t\t\tconst str = Buffer.from(chunk).toString('utf-8');\r\n\t\t\t\tconst newStr = previousString + str;\r\n\t\t\t\tconst split = newStr.split('\\n');\r\n\t\t\t\tconst rows: readonly InternalBgsRow[] = split.slice(0, split.length - 1).map(row => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst result = JSON.parse(row);\r\n\t\t\t\t\t\ttotalParsed++;\r\n\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\t// logger.warn('could not parse row', row);\r\n\t\t\t\t\t\tparseErrors++;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tpreviousString = split[split.length - 1];\r\n\t\t\t\t// logger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresult.push(...rows);\r\n\t\t\t})\r\n\t\t\t.on('end', () => {\r\n\t\t\t\tconst finalResult = result.filter(row => !!row);\r\n\t\t\t\tlogger.log('stream end', result.length, finalResult.length);\r\n\t\t\t\tlogger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresolve(finalResult);\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\n// https://stackoverflow.com/a/47204248/548701\r\nconst combine = <T>(input: readonly T[], chooseN: number): T[][] => {\r\n\tconst finalResult: T[][] = [];\r\n\r\n\tconst intermediateResult = [];\r\n\tintermediateResult.length = chooseN;\r\n\tconst combineInternal = <T>(input: readonly T[], chooseN: number, start = 0): void => {\r\n\t\tif (chooseN === 0) {\r\n\t\t\tfinalResult.push([...intermediateResult].sort());\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfor (let i = start; i <= input.length - chooseN; i++) {\r\n\t\t\tintermediateResult[intermediateResult.length - chooseN] = input[i];\r\n\t\t\tcombineInternal(input, chooseN - 1, i + 1);\r\n\t\t}\r\n\t};\r\n\tcombineInternal(input, chooseN, 0);\r\n\r\n\treturn finalResult;\r\n};\r\n\r\nconst extractAllTribes = (rows: readonly InternalBgsRow[]): readonly Race[] => {\r\n\treturn [\r\n\t\t...new Set(\r\n\t\t\trows\r\n\t\t\t\t.map(row => row.tribes)\r\n\t\t\t\t.filter(tribes => !!tribes?.length)\r\n\t\t\t\t.map(tribes => tribes.split(',').map(strTribe => parseInt(strTribe) as Race))\r\n\t\t\t\t.reduce((a, b) => [...new Set(a.concat(b))], []),\r\n\t\t),\r\n\t];\r\n};\r\n\r\nconst buildHeroes = (\r\n\trows: readonly InternalBgsRow[],\r\n\tmmrPercentiles: readonly MmrPercentile[],\r\n): readonly BgsGlobalHeroStat2[] => {\r\n\tconst mappedByMmr = mmrPercentiles.map(\r\n\t\tmmrPercentile =>\r\n\t\t\t[\r\n\t\t\t\tmmrPercentile,\r\n\t\t\t\t// So that we also include rows where data collection failed\r\n\t\t\t\trows.filter(row => mmrPercentile.percentile === 100 || row.rating >= mmrPercentile.mmr),\r\n\t\t\t] as [MmrPercentile, readonly InternalBgsRow[]],\r\n\t);\r\n\t// logger.log('mappedByMmr');\r\n\treturn mappedByMmr\r\n\t\t.map(([mmr, rows]) => {\r\n\t\t\tlogger.log('building heroes for mmr', mmr.percentile, rows.length);\r\n\t\t\treturn buildHeroStats(rows).map(stat => ({\r\n\t\t\t\t...stat,\r\n\t\t\t\tmmrPercentile: mmr.percentile,\r\n\t\t\t}));\r\n\t\t})\r\n\t\t.reduce((a, b) => [...a, ...b], []);\r\n};\r\n\r\nconst buildHeroStats = (rows: readonly InternalBgsRow[]): readonly BgsGlobalHeroStat2[] => {\r\n\tconst grouped: { [groupingKey: string]: readonly InternalBgsRow[] } = groupByFunction(\r\n\t\t// (row: InternalBgsRow) => `${row.heroCardId}-${row.darkmoonPrizes}`,\r\n\t\t(row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards),\r\n\t)(rows);\r\n\t// logger.log('grouped', Object.keys(grouped).length);\r\n\r\n\tconst result = Object.values(grouped).map(groupedRows => {\r\n\t\tconst ref = groupedRows[0];\r\n\t\tconst placementDistribution = buildPlacementDistribution(groupedRows);\r\n\t\tconst combatWinrate = buildCombatWinrate(groupedRows);\r\n\t\tconst warbandStats = buildWarbandStats(groupedRows);\r\n\t\treturn {\r\n\t\t\tcardId: normalizeHeroCardId(ref.heroCardId, allCards),\r\n\t\t\ttotalMatches: groupedRows.length,\r\n\t\t\tplacementDistribution: placementDistribution,\r\n\t\t\tcombatWinrate: combatWinrate,\r\n\t\t\twarbandStats: warbandStats,\r\n\t\t} as BgsGlobalHeroStat2;\r\n\t});\r\n\t// logger.log('built result');\r\n\treturn result;\r\n};\r\n\r\nconst buildWarbandStats = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalStats: number }[] => {\r\n\tconst data: { [turn: string]: { dataPoints: number; totalStats: number } } = {};\r\n\t// Before that, there was an issue with disconnects, where the first turn after the\r\n\t// reconnect would be turn 0, leading to an inflation of early turn stats\r\n\tconst validRows = rows.filter(row => row.id > 5348374);\r\n\tfor (const row of validRows) {\r\n\t\tif (!row.warbandStats?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst parsed: readonly { turn: number; totalStats: number }[] = JSON.parse(row.warbandStats);\r\n\t\tif (!parsed?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.totalStats == null || isNaN(turnInfo.totalStats)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// To avoid polluting the stats with big Tarecgosa outliers\r\n\t\t\tif (turnInfo.totalStats > 20000) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalStats: 0 };\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalStats = existingInfo.totalStats + Math.round(turnInfo.totalStats);\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t}\r\n\t}\r\n\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalStats: data[turn].totalStats,\r\n\t}));\r\n\treturn result;\r\n};\r\n\r\nexport const buildCombatWinrate = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalWinrate: number }[] => {\r\n\tconst ref = rows[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_000';\r\n\r\n\tconst data: { [turn: string]: { dataPoints: number; totalWinrate: number } } = {};\r\n\tfor (const row of rows) {\r\n\t\t// logger.debug('building combatWinrate', row);\r\n\t\tif (!row.combatWinrate?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tlet parsed: readonly { turn: number; winrate: number }[] = null;\r\n\t\ttry {\r\n\t\t\tparsed = JSON.parse(row.combatWinrate);\r\n\t\t\t// logger.debug('parsed', parsed);\r\n\t\t\tif (!parsed?.length) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t} catch (e) {\r\n\t\t\tlogger.error('Could not parse combat winrate', row.id, e);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// if (debug) {\r\n\t\t// \tlogger.log('handling combat winrate', parsed);\r\n\t\t// }\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.winrate == null) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t turnInfo', turnInfo);\r\n\t\t\t// }\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalWinrate: 0 };\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo', existingInfo);\r\n\t\t\t// }\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalWinrate = existingInfo.totalWinrate + Math.round(turnInfo.winrate);\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo after', existingInfo);\r\n\t\t\t// }\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t data', data);\r\n\t\t\t// }\r\n\t\t}\r\n\t}\r\n\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t data', data);\r\n\t// }\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalWinrate: data[turn].totalWinrate,\r\n\t}));\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t result', result);\r\n\t// }\r\n\treturn result;\r\n};\r\n\r\nconst loadRows = async (mysql: ServerlessMysql): Promise<readonly InternalBgsRow[]> => {\r\n\t// We actually use all the fields\r\n\tconst query = `\r\n\t\tSELECT *\r\n\t\tFROM bgs_run_stats\r\n\t\tWHERE creationDate > DATE_SUB(NOW(), INTERVAL 30 DAY);\r\n\t`;\r\n\tlogger.log('running query', query);\r\n\tconst rows: readonly InternalBgsRow[] = await mysql.query(query);\r\n\tlogger.log('rows', rows?.length, rows[0]);\r\n\treturn rows\r\n\t\t.filter(row => row.heroCardId.startsWith('TB_BaconShop_') || row.heroCardId.startsWith('BG'))\r\n\t\t.filter(\r\n\t\t\trow =>\r\n\t\t\t\trow.heroCardId !== CardIds.ArannaStarseeker_ArannaUnleashedTokenBattlegrounds &&\r\n\t\t\t\trow.heroCardId !== CardIds.QueenAzshara_NagaQueenAzsharaToken,\r\n\t\t)\r\n\t\t.map(row => ({\r\n\t\t\t...row,\r\n\t\t\theroCardId: normalizeHeroCardId(row.heroCardId, allCards),\r\n\t\t}));\r\n};\r\n\r\nconst getLastBattlegroundsPatch = async (): Promise<PatchInfo> => {\r\n\tconst patchInfo = await http(`https://static.zerotoheroes.com/hearthstone/data/patches.json`);\r\n\tconst structuredPatch = JSON.parse(patchInfo);\r\n\tconst patchNumber = structuredPatch.currentBattlegroundsMetaPatch;\r\n\treturn structuredPatch.patches.find(patch => patch.number === patchNumber);\r\n};\r\n"]}
1
+ {"version":3,"file":"build-battlegrounds-hero-stats-new.js","sourceRoot":"/","sources":["build-battlegrounds-hero-stats-new.ts"],"names":[],"mappings":";;;;;AACA,qEAAoH;AACpH,iEAA8E;AAE9E,sDAA0B;AAG1B,+BAAgC;AAEhC,qCAA+G;AAE/G,qCAAwC;AACxC,qDAAuD;AACvD,kDAAoD;AACpD,2DAAyE;AAE5D,QAAA,EAAE,GAAG,IAAI,qBAAE,EAAE,CAAC;AAC3B,MAAM,QAAQ,GAAG,IAAI,gCAAe,EAAE,CAAC;AACvC,MAAM,MAAM,GAAG,IAAI,iBAAG,CAAC,MAAM,EAAE,CAAC;AAEhC,MAAM,cAAc,GAAgE;IACnF,UAAU;IACV,YAAY;IACZ,YAAY;IACZ,YAAY;CACZ,CAAC;AAKF,kBAAe,KAAK,EAAE,KAAK,EAAE,OAAgB,EAAgB,EAAE;IAC9D,MAAM,sBAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC,CAAC;AAEW,QAAA,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,OAAgB,EAAE,EAAE;;IAC/D,MAAM,OAAO,GAAG,mCAAgB,CAAC,OAAO,CAAC,CAAC;IAC1C,yBAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3B,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAC;IACnC,MAAM,SAAS,GAAG,MAAM,yBAAyB,EAAE,CAAC;IAEpD,IAAI,KAAK,CAAC,MAAM,EAAE;QACjB,MAAM,IAAI,GAA8B,MAAM,cAAc,EAAE,CAAC;QAC/D,yBAAM,CAAC,GAAG,CAAC,WAAW,QAAE,IAAI,0CAAE,MAAM,CAAC,CAAC;QACtC,KAAK,MAAM,UAAU,IAAI,cAAc,EAAE;YACxC,MAAM,qBAAY,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;SAChD;KACD;SAAM,IAAI,KAAK,CAAC,QAAQ,EAAE;QAC1B,MAAM,IAAI,GAA8B,MAAM,cAAc,EAAE,CAAC;QAC/D,yBAAM,CAAC,GAAG,CAAC,WAAW,QAAE,IAAI,0CAAE,MAAM,CAAC,CAAC;QACtC,KAAK,MAAM,UAAU,IAAI,cAAc,EAAE;YACxC,MAAM,0BAAc,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;SAClD;KACD;SAAM,IAAI,KAAK,CAAC,OAAO,EAAE;QACzB,MAAM,IAAI,GAA8B,MAAM,cAAc,EAAE,CAAC;QAC/D,yBAAM,CAAC,GAAG,CAAC,WAAW,QAAE,IAAI,0CAAE,MAAM,CAAC,CAAC;QACtC,KAAK,MAAM,UAAU,IAAI,cAAc,EAAE;YACxC,MAAM,wBAAa,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;SAC3D;KACD;SAAM,IAAI,KAAK,CAAC,WAAW,EAAE;QAC7B,MAAM,IAAI,GAA8B,MAAM,cAAc,EAAE,CAAC;QAC/D,yBAAM,CAAC,GAAG,CAAC,WAAW,QAAE,IAAI,0CAAE,MAAM,CAAC,CAAC;QACtC,KAAK,MAAM,UAAU,IAAI,cAAc,EAAE;YACxC,MAAM,iBAAiB,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;SACzF;KACD;SAAM;QACN,MAAM,KAAK,GAAG,MAAM,gCAAa,EAAE,CAAC;QACpC,MAAM,IAAI,GAA8B,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9D,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC;QAClB,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;KAC3C;IAED,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,KAAK,EAAE,IAA+B,EAAE,OAAgB,EAAE,EAAE;IACxF,MAAM,QAAQ,GAAG;QAChB,MAAM,EAAE,IAAI;KACZ,CAAC;IACF,MAAM,MAAM,GAAG;QACd,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,OAAO;QACvB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KACjC,CAAC;IACF,yBAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,MAAM;SACzB,MAAM,CAAC;QACP,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,OAAO;QACvB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KACjC,CAAC;SACD,OAAO,EAAE,CAAC;IACZ,yBAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,KAAK,EAAE,IAA+B,EAAE,OAAgB,EAAE,EAAE;IAC1F,MAAM,QAAQ,GAAG;QAChB,QAAQ,EAAE,IAAI;KACd,CAAC;IACF,MAAM,MAAM,GAAG;QACd,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,OAAO;QACvB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KACjC,CAAC;IACF,yBAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,MAAM;SACzB,MAAM,CAAC;QACP,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,OAAO;QACvB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KACjC,CAAC;SACD,OAAO,EAAE,CAAC;IACZ,yBAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,EAAE,IAA+B,EAAE,OAAgB,EAAE,EAAE;IACzF,MAAM,QAAQ,GAAG;QAChB,OAAO,EAAE,IAAI;KACb,CAAC;IACF,MAAM,MAAM,GAAG;QACd,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,OAAO;QACvB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KACjC,CAAC;IACF,yBAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,MAAM;SACzB,MAAM,CAAC;QACP,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,OAAO;QACvB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KACjC,CAAC;SACD,OAAO,EAAE,CAAC;IACZ,yBAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,KAAK,EAAE,IAA+B,EAAE,OAAgB,EAAE,EAAE;IACtF,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzC,yBAAM,CAAC,GAAG,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IACpC,MAAM,iBAAiB,GAAuB,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAChF,yBAAM,CAAC,GAAG,CAAC,+DAA+D,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACtG,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE;QACvC,yBAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,EAAE,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAI5E,MAAM,QAAQ,GAAG;YAChB,WAAW,EAAE,MAAM;YACnB,SAAS,EAAE,SAAS;SACpB,CAAC;QACF,MAAM,MAAM,GAAG;YACd,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;QACF,yBAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,MAAM;aACzB,MAAM,CAAC;YACP,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;aACD,OAAO,EAAE,CAAC;QACZ,yBAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;KAC1C;AACF,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,KAAK,EAC9B,MAA+B,EAC/B,UAAmE,EACnE,SAA0B,EAC1B,IAA+B,EAC/B,SAAoB,EACnB,EAAE;;IACH,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,iBAAiB,GAAG,gCAAuB,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,cAAc,GAAG,CAAC,CAAC,SAAS;QACjC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;QACvF,CAAC,CAAC,iBAAiB,CAAC;IACrB,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACrD,MAAM,cAAc,GAA6B,4BAAmB,CAAC,cAAc,CAAC,CAAC;IACrF,yBAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,MAAM,EAAE,UAAU,QAAE,IAAI,0CAAE,MAAM,QAAE,cAAc,0CAAE,MAAM,CAAC,CAAC;IAC7F,MAAM,KAAK,GAAkC,WAAW,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrG,GAAG,IAAI;QACP,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;QAC7C,IAAI,EAAE,UAAU;KAChB,CAAC,CAAC,CAAC;IACJ,MAAM,cAAc,GAAoB;QACvC,cAAc,EAAE,2BAAU,CAAC,IAAI,IAAI,EAAE,CAAC;QACtC,cAAc,EAAE,cAAc;QAC9B,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,SAAS;QACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;KACvE,CAAC;IACF,yBAAM,CAAC,GAAG,CAAC,eAAe,EAAE,cAAc,CAAC,YAAY,QAAE,cAAc,CAAC,SAAS,0CAAE,MAAM,CAAC,CAAC;IAC3F,MAAM,YAAY,GAAG,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,UAAU,CAAC;IAC9B,MAAM,UAAE,CAAC,SAAS,CACjB,eAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,EACxC,yBAAyB,EACzB,mCAAmC,YAAY,IAAI,UAAU,UAAU,EACvE,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,KAAK,EAAE,IAA+B,EAAE,EAAE;IAC9D,yBAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,UAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,kBAAkB,CAAC,CAAC;IACjH,yBAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,KAAK,IAAwC,EAAE;IACrE,OAAO,IAAI,OAAO,CAA4B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACjE,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,MAAM,MAAM,GAAa,UAAE,CAAC,UAAU,CAAC,yBAAyB,EAAE,2BAA2B,CAAC,CAAC;QAC/F,MAAM,MAAM,GAAqB,EAAE,CAAC;QACpC,IAAI,cAAc,GAAG,EAAE,CAAC;QACxB,MAAM;aACJ,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;YACnB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACjD,MAAM,MAAM,GAAG,cAAc,GAAG,GAAG,CAAC;YACpC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,IAAI,GAA8B,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;gBAClF,IAAI;oBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAC/B,WAAW,EAAE,CAAC;oBACd,OAAO,MAAM,CAAC;iBACd;gBAAC,OAAO,CAAC,EAAE;oBAEX,WAAW,EAAE,CAAC;iBACd;YACF,CAAC,CAAC,CAAC;YACH,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAEzC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC;aACD,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACf,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAChD,yBAAM,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;YAC5D,yBAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC;YACxE,OAAO,CAAC,WAAW,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC;AAGF,MAAM,OAAO,GAAG,CAAI,KAAmB,EAAE,OAAe,EAAS,EAAE;IAClE,MAAM,WAAW,GAAU,EAAE,CAAC;IAE9B,MAAM,kBAAkB,GAAG,EAAE,CAAC;IAC9B,kBAAkB,CAAC,MAAM,GAAG,OAAO,CAAC;IACpC,MAAM,eAAe,GAAG,CAAI,KAAmB,EAAE,OAAe,EAAE,KAAK,GAAG,CAAC,EAAQ,EAAE;QACpF,IAAI,OAAO,KAAK,CAAC,EAAE;YAClB,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACjD,OAAO;SACP;QACD,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE;YACrD,kBAAkB,CAAC,kBAAkB,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACnE,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;SAC3C;IACF,CAAC,CAAC;IACF,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAEnC,OAAO,WAAW,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,IAA+B,EAAmB,EAAE;IAC7E,OAAO;QACN,GAAG,IAAI,GAAG,CACT,IAAI;aACF,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;aACtB,MAAM,CAAC,MAAM,CAAC,EAAE,WAAC,OAAA,CAAC,QAAC,MAAM,0CAAE,MAAM,CAAA,CAAA,EAAA,CAAC;aAClC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAS,CAAC,CAAC;aAC5E,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACjD;KACD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CACnB,IAA+B,EAC/B,cAAwC,EACR,EAAE;IAClC,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CACrC,aAAa,CAAC,EAAE,CACf;QACC,aAAa;QAEb,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,CAAC,UAAU,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC,GAAG,CAAC;KACzC,CAChD,CAAC;IAEF,OAAO,WAAW;SAChB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE;QACpB,yBAAM,CAAC,GAAG,CAAC,yBAAyB,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACnE,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACxC,GAAG,IAAI;YACP,aAAa,EAAE,GAAG,CAAC,UAAU;SAC7B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,IAA+B,EAAiC,EAAE;IACzF,MAAM,OAAO,GAAyD,kCAAe,CAEpF,CAAC,GAAmB,EAAE,EAAE,CAAC,oCAAmB,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CACtE,CAAC,IAAI,CAAC,CAAC;IAGR,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;QACvD,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,qBAAqB,GAAG,mCAA0B,CAAC,WAAW,CAAC,CAAC;QACtE,MAAM,aAAa,GAAG,0BAAkB,CAAC,WAAW,CAAC,CAAC;QACtD,MAAM,YAAY,GAAG,yBAAiB,CAAC,WAAW,CAAC,CAAC;QACpD,OAAO;YACN,MAAM,EAAE,oCAAmB,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC;YACrD,YAAY,EAAE,WAAW,CAAC,MAAM;YAChC,qBAAqB,EAAE,qBAAqB;YAC5C,aAAa,EAAE,aAAa;YAC5B,YAAY,EAAE,YAAY;SACJ,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEW,QAAA,iBAAiB,GAAG,CAChC,IAA+B,EACuC,EAAE;;IACxE,MAAM,IAAI,GAAmE,EAAE,CAAC;IAGhF,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE;QAC5B,IAAI,QAAC,GAAG,CAAC,YAAY,0CAAE,MAAM,CAAA,EAAE;YAC9B,SAAS;SACT;QAED,MAAM,MAAM,GAAoD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC7F,IAAI,QAAC,MAAM,0CAAE,MAAM,CAAA,EAAE;YACpB,SAAS;SACT;QAED,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE;YAC9B,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;gBACrF,SAAS;aACT;YAED,IAAI,QAAQ,CAAC,UAAU,GAAG,KAAK,EAAE;gBAChC,SAAS;aACT;YACD,MAAM,YAAY,SAAG,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,uCAAI,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,EAAA,CAAC;YAClF,YAAY,CAAC,UAAU,GAAG,YAAY,CAAC,UAAU,GAAG,CAAC,CAAC;YACtD,YAAY,CAAC,UAAU,GAAG,YAAY,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YACpF,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC;SACxC;KACD;IAED,MAAM,MAAM,GAA+D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzG,IAAI,EAAE,CAAC,IAAI;QACX,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU;QACjC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU;KACjC,CAAC,CAAC,CAAC;IACJ,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEW,QAAA,kBAAkB,GAAG,CACjC,IAA+B,EACyC,EAAE;;IAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,KAAK,eAAe,CAAC;IAEjD,MAAM,IAAI,GAAqE,EAAE,CAAC;IAClF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;QAEvB,IAAI,QAAC,GAAG,CAAC,aAAa,0CAAE,MAAM,CAAA,EAAE;YAC/B,SAAS;SACT;QAED,IAAI,MAAM,GAAiD,IAAI,CAAC;QAChE,IAAI;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAEvC,IAAI,QAAC,MAAM,0CAAE,MAAM,CAAA,EAAE;gBACpB,SAAS;aACT;SACD;QAAC,OAAO,CAAC,EAAE;YACX,yBAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1D,SAAS;SACT;QAMD,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE;YAC9B,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE;gBACpD,SAAS;aACT;YAID,MAAM,YAAY,SAAG,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,uCAAI,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAA,CAAC;YAIpF,YAAY,CAAC,UAAU,GAAG,YAAY,CAAC,UAAU,GAAG,CAAC,CAAC;YACtD,YAAY,CAAC,YAAY,GAAG,YAAY,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAIrF,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC;SAIxC;KACD;IAKD,MAAM,MAAM,GAAiE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3G,IAAI,EAAE,CAAC,IAAI;QACX,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU;QACjC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,YAAY;KACrC,CAAC,CAAC,CAAC;IAIJ,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,KAAK,EAAE,KAAsB,EAAsC,EAAE;;IAErF,MAAM,KAAK,GAAG;;;;EAIb,CAAC;IACF,yBAAM,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACnC,MAAM,IAAI,GAA8B,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjE,yBAAM,CAAC,GAAG,CAAC,MAAM,QAAE,IAAI,0CAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,OAAO,IAAI;SACT,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;SAC5F,MAAM,CACN,GAAG,CAAC,EAAE,CACL,GAAG,CAAC,UAAU,4BAA+D;QAC7E,GAAG,CAAC,UAAU,qBAA+C,CAC9D;SACA,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACZ,GAAG,GAAG;QACN,UAAU,EAAE,oCAAmB,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC;KACzD,CAAC,CAAC,CAAC;AACN,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,KAAK,IAAwB,EAAE;IAChE,MAAM,SAAS,GAAG,MAAM,uBAAI,CAAC,+DAA+D,CAAC,CAAC;IAC9F,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,eAAe,CAAC,6BAA6B,CAAC;IAClE,OAAO,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;AAC5E,CAAC,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { getConnection, groupByFunction, http, logBeforeTimeout, logger, S3 } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds, Race } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { ServerlessMysql } from 'serverless-mysql';\r\nimport { Readable } from 'stream';\r\nimport { gzipSync } from 'zlib';\r\nimport { BgsGlobalHeroStat2, BgsGlobalStats2, MmrPercentile } from './bgs-global-stats';\r\nimport { buildMmrPercentiles, buildPlacementDistribution, filterRowsForTimePeriod, PatchInfo } from './common';\r\nimport { InternalBgsRow } from './internal-model';\r\nimport { handleQuests } from './quests';\r\nimport { handleQuestsV2 } from './quests-v2/quests-v2';\r\nimport { handleStatsV2 } from './stats-v2/stats-v2';\r\nimport { formatDate, normalizeHeroCardId } from './utils/util-functions';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allTimePeriods: ('all-time' | 'past-three' | 'past-seven' | 'last-patch')[] = [\r\n\t'all-time',\r\n\t'past-three',\r\n\t'past-seven',\r\n\t'last-patch',\r\n];\r\n\r\n// This example demonstrates a NodeJS 8.10 async handler[1], however of course you could use\r\n// the more traditional callback-style handler.\r\n// [1]: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\tlogger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\tconst lastPatch = await getLastBattlegroundsPatch();\r\n\r\n\tif (event.quests) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuests(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.questsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleQuestsV2(timePeriod, rows, lastPatch);\r\n\t\t}\r\n\t} else if (event.statsV2) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handleStatsV2(timePeriod, rows, lastPatch, allCards);\r\n\t\t}\r\n\t} else if (event.permutation) {\r\n\t\tconst rows: readonly InternalBgsRow[] = await readRowsFromS3();\r\n\t\tlogger.log('read rows', rows?.length);\r\n\t\tfor (const timePeriod of allTimePeriods) {\r\n\t\t\tawait handlePermutation(event.permutation, timePeriod, event.allTribes, rows, lastPatch);\r\n\t\t}\r\n\t} else {\r\n\t\tconst mysql = await getConnection();\r\n\t\tconst rows: readonly InternalBgsRow[] = await loadRows(mysql);\r\n\t\tawait mysql.end();\r\n\t\tawait saveRowsOnS3(rows);\r\n\t\tawait dispatchNewLambdas(rows, context);\r\n\t\tawait dispatchQuestsLambda(rows, context);\r\n\t\tawait dispatchQuestsV2Lambda(rows, context);\r\n\t\tawait dispatchStatsV2Lambda(rows, context);\r\n\t}\r\n\r\n\tcleanup();\r\n\treturn { statusCode: 200, body: null };\r\n};\r\n\r\nconst dispatchQuestsLambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquests: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tquestsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst newEvent = {\r\n\t\tstatsV2: true,\r\n\t};\r\n\tconst params = {\r\n\t\tFunctionName: context.functionName,\r\n\t\tInvocationType: 'Event',\r\n\t\tLogType: 'Tail',\r\n\t\tPayload: JSON.stringify(newEvent),\r\n\t};\r\n\tlogger.log('\\tinvoking lambda', params);\r\n\tconst result = await lambda\r\n\t\t.invoke({\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t})\r\n\t\t.promise();\r\n\tlogger.log('\\tinvocation result', result);\r\n};\r\n\r\nconst dispatchNewLambdas = async (rows: readonly InternalBgsRow[], context: Context) => {\r\n\tconst allTribes = extractAllTribes(rows);\r\n\tlogger.log('all tribes', allTribes);\r\n\tconst tribePermutations: ('all' | Race[])[] = ['all', ...combine(allTribes, 5)];\r\n\tlogger.log('tribe permutations, should be 127 (126 + 1), because 9 tribes', tribePermutations.length);\r\n\tfor (const tribes of tribePermutations) {\r\n\t\tlogger.log('handling tribes', tribes, tribes !== 'all' && tribes.join('-'));\r\n\t\t// if (tribes !== 'all') {\r\n\t\t// \tcontinue;\r\n\t\t// }\r\n\t\tconst newEvent = {\r\n\t\t\tpermutation: tribes,\r\n\t\t\tallTribes: allTribes,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tlogger.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\tlogger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst handlePermutation = async (\r\n\ttribes: 'all' | readonly Race[],\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\tallTribes: readonly Race[],\r\n\trows: readonly InternalBgsRow[],\r\n\tlastPatch: PatchInfo,\r\n) => {\r\n\tconsole.log('total rows', rows.length);\r\n\tconst rowsForTimePeriod = filterRowsForTimePeriod(rows, timePeriod, lastPatch);\r\n\tconsole.log('rows for time period', rowsForTimePeriod.length);\r\n\tconst tribesStr = tribes === 'all' ? null : tribes.join(',');\r\n\tconst rowsWithTribes = !!tribesStr\r\n\t\t? rowsForTimePeriod.filter(row => !!row.tribes).filter(row => row.tribes === tribesStr)\r\n\t\t: rowsForTimePeriod;\r\n\tconsole.log('rowsWithTribes', rowsWithTribes.length);\r\n\tconst mmrPercentiles: readonly MmrPercentile[] = buildMmrPercentiles(rowsWithTribes);\r\n\tlogger.log('handling permutation', tribes, timePeriod, rows?.length, rowsWithTribes?.length);\r\n\tconst stats: readonly BgsGlobalHeroStat2[] = buildHeroes(rowsWithTribes, mmrPercentiles).map(stat => ({\r\n\t\t...stat,\r\n\t\ttribes: tribes === 'all' ? allTribes : tribes,\r\n\t\tdate: timePeriod,\r\n\t}));\r\n\tconst statsForTribes: BgsGlobalStats2 = {\r\n\t\tlastUpdateDate: formatDate(new Date()),\r\n\t\tmmrPercentiles: mmrPercentiles,\r\n\t\theroStats: stats,\r\n\t\tallTribes: allTribes,\r\n\t\ttotalMatches: stats.map(s => s.totalMatches).reduce((a, b) => a + b, 0),\r\n\t};\r\n\tlogger.log('\\tbuilt stats', statsForTribes.totalMatches, statsForTribes.heroStats?.length);\r\n\tconst tribesSuffix = tribes === 'all' ? 'all-tribes' : tribes.join('-');\r\n\tconst timeSuffix = timePeriod;\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(statsForTribes)),\r\n\t\t'static.zerotoheroes.com',\r\n\t\t`api/bgs/heroes/bgs-global-stats-${tribesSuffix}-${timeSuffix}.gz.json`,\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n\r\nconst saveRowsOnS3 = async (rows: readonly InternalBgsRow[]) => {\r\n\tlogger.log('saving rows on s3', rows.length);\r\n\tawait s3.writeArrayAsMultipart(rows, 'static.zerotoheroes.com', `api/bgs/working-rows.json`, 'application/json');\r\n\tlogger.log('file saved');\r\n};\r\n\r\nconst readRowsFromS3 = async (): Promise<readonly InternalBgsRow[]> => {\r\n\treturn new Promise<readonly InternalBgsRow[]>((resolve, reject) => {\r\n\t\tlet parseErrors = 0;\r\n\t\tlet totalParsed = 0;\r\n\t\tconst stream: Readable = s3.readStream('static.zerotoheroes.com', `api/bgs/working-rows.json`);\r\n\t\tconst result: InternalBgsRow[] = [];\r\n\t\tlet previousString = '';\r\n\t\tstream\r\n\t\t\t.on('data', chunk => {\r\n\t\t\t\tconst str = Buffer.from(chunk).toString('utf-8');\r\n\t\t\t\tconst newStr = previousString + str;\r\n\t\t\t\tconst split = newStr.split('\\n');\r\n\t\t\t\tconst rows: readonly InternalBgsRow[] = split.slice(0, split.length - 1).map(row => {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tconst result = JSON.parse(row);\r\n\t\t\t\t\t\ttotalParsed++;\r\n\t\t\t\t\t\treturn result;\r\n\t\t\t\t\t} catch (e) {\r\n\t\t\t\t\t\t// logger.warn('could not parse row', row);\r\n\t\t\t\t\t\tparseErrors++;\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\tpreviousString = split[split.length - 1];\r\n\t\t\t\t// logger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresult.push(...rows);\r\n\t\t\t})\r\n\t\t\t.on('end', () => {\r\n\t\t\t\tconst finalResult = result.filter(row => !!row);\r\n\t\t\t\tlogger.log('stream end', result.length, finalResult.length);\r\n\t\t\t\tlogger.log('parsing errors', parseErrors, 'and successes', totalParsed);\r\n\t\t\t\tresolve(finalResult);\r\n\t\t\t});\r\n\t});\r\n};\r\n\r\n// https://stackoverflow.com/a/47204248/548701\r\nconst combine = <T>(input: readonly T[], chooseN: number): T[][] => {\r\n\tconst finalResult: T[][] = [];\r\n\r\n\tconst intermediateResult = [];\r\n\tintermediateResult.length = chooseN;\r\n\tconst combineInternal = <T>(input: readonly T[], chooseN: number, start = 0): void => {\r\n\t\tif (chooseN === 0) {\r\n\t\t\tfinalResult.push([...intermediateResult].sort());\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tfor (let i = start; i <= input.length - chooseN; i++) {\r\n\t\t\tintermediateResult[intermediateResult.length - chooseN] = input[i];\r\n\t\t\tcombineInternal(input, chooseN - 1, i + 1);\r\n\t\t}\r\n\t};\r\n\tcombineInternal(input, chooseN, 0);\r\n\r\n\treturn finalResult;\r\n};\r\n\r\nconst extractAllTribes = (rows: readonly InternalBgsRow[]): readonly Race[] => {\r\n\treturn [\r\n\t\t...new Set(\r\n\t\t\trows\r\n\t\t\t\t.map(row => row.tribes)\r\n\t\t\t\t.filter(tribes => !!tribes?.length)\r\n\t\t\t\t.map(tribes => tribes.split(',').map(strTribe => parseInt(strTribe) as Race))\r\n\t\t\t\t.reduce((a, b) => [...new Set(a.concat(b))], []),\r\n\t\t),\r\n\t];\r\n};\r\n\r\nconst buildHeroes = (\r\n\trows: readonly InternalBgsRow[],\r\n\tmmrPercentiles: readonly MmrPercentile[],\r\n): readonly BgsGlobalHeroStat2[] => {\r\n\tconst mappedByMmr = mmrPercentiles.map(\r\n\t\tmmrPercentile =>\r\n\t\t\t[\r\n\t\t\t\tmmrPercentile,\r\n\t\t\t\t// So that we also include rows where data collection failed\r\n\t\t\t\trows.filter(row => mmrPercentile.percentile === 100 || row.rating >= mmrPercentile.mmr),\r\n\t\t\t] as [MmrPercentile, readonly InternalBgsRow[]],\r\n\t);\r\n\t// logger.log('mappedByMmr');\r\n\treturn mappedByMmr\r\n\t\t.map(([mmr, rows]) => {\r\n\t\t\tlogger.log('building heroes for mmr', mmr.percentile, rows.length);\r\n\t\t\treturn buildHeroStats(rows).map(stat => ({\r\n\t\t\t\t...stat,\r\n\t\t\t\tmmrPercentile: mmr.percentile,\r\n\t\t\t}));\r\n\t\t})\r\n\t\t.reduce((a, b) => [...a, ...b], []);\r\n};\r\n\r\nconst buildHeroStats = (rows: readonly InternalBgsRow[]): readonly BgsGlobalHeroStat2[] => {\r\n\tconst grouped: { [groupingKey: string]: readonly InternalBgsRow[] } = groupByFunction(\r\n\t\t// (row: InternalBgsRow) => `${row.heroCardId}-${row.darkmoonPrizes}`,\r\n\t\t(row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards),\r\n\t)(rows);\r\n\t// logger.log('grouped', Object.keys(grouped).length);\r\n\r\n\tconst result = Object.values(grouped).map(groupedRows => {\r\n\t\tconst ref = groupedRows[0];\r\n\t\tconst placementDistribution = buildPlacementDistribution(groupedRows);\r\n\t\tconst combatWinrate = buildCombatWinrate(groupedRows);\r\n\t\tconst warbandStats = buildWarbandStats(groupedRows);\r\n\t\treturn {\r\n\t\t\tcardId: normalizeHeroCardId(ref.heroCardId, allCards),\r\n\t\t\ttotalMatches: groupedRows.length,\r\n\t\t\tplacementDistribution: placementDistribution,\r\n\t\t\tcombatWinrate: combatWinrate,\r\n\t\t\twarbandStats: warbandStats,\r\n\t\t} as BgsGlobalHeroStat2;\r\n\t});\r\n\t// logger.log('built result');\r\n\treturn result;\r\n};\r\n\r\nexport const buildWarbandStats = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalStats: number }[] => {\r\n\tconst data: { [turn: string]: { dataPoints: number; totalStats: number } } = {};\r\n\t// Before that, there was an issue with disconnects, where the first turn after the\r\n\t// reconnect would be turn 0, leading to an inflation of early turn stats\r\n\tconst validRows = rows.filter(row => row.id > 5348374);\r\n\tfor (const row of validRows) {\r\n\t\tif (!row.warbandStats?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst parsed: readonly { turn: number; totalStats: number }[] = JSON.parse(row.warbandStats);\r\n\t\tif (!parsed?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.totalStats == null || isNaN(turnInfo.totalStats)) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// To avoid polluting the stats with big Tarecgosa outliers\r\n\t\t\tif (turnInfo.totalStats > 20000) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalStats: 0 };\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalStats = existingInfo.totalStats + Math.round(turnInfo.totalStats);\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t}\r\n\t}\r\n\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalStats: data[turn].totalStats,\r\n\t}));\r\n\treturn result;\r\n};\r\n\r\nexport const buildCombatWinrate = (\r\n\trows: readonly InternalBgsRow[],\r\n): readonly { turn: number; dataPoints: number; totalWinrate: number }[] => {\r\n\tconst ref = rows[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_000';\r\n\r\n\tconst data: { [turn: string]: { dataPoints: number; totalWinrate: number } } = {};\r\n\tfor (const row of rows) {\r\n\t\t// logger.debug('building combatWinrate', row);\r\n\t\tif (!row.combatWinrate?.length) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tlet parsed: readonly { turn: number; winrate: number }[] = null;\r\n\t\ttry {\r\n\t\t\tparsed = JSON.parse(row.combatWinrate);\r\n\t\t\t// logger.debug('parsed', parsed);\r\n\t\t\tif (!parsed?.length) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t} catch (e) {\r\n\t\t\tlogger.error('Could not parse combat winrate', row.id, e);\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// if (debug) {\r\n\t\t// \tlogger.log('handling combat winrate', parsed);\r\n\t\t// }\r\n\r\n\t\tfor (const turnInfo of parsed) {\r\n\t\t\tif (turnInfo.turn === 0 || turnInfo.winrate == null) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t turnInfo', turnInfo);\r\n\t\t\t// }\r\n\t\t\tconst existingInfo = data['' + turnInfo.turn] ?? { dataPoints: 0, totalWinrate: 0 };\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo', existingInfo);\r\n\t\t\t// }\r\n\t\t\texistingInfo.dataPoints = existingInfo.dataPoints + 1;\r\n\t\t\texistingInfo.totalWinrate = existingInfo.totalWinrate + Math.round(turnInfo.winrate);\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t existingInfo after', existingInfo);\r\n\t\t\t// }\r\n\t\t\tdata['' + turnInfo.turn] = existingInfo;\r\n\t\t\t// if (debug) {\r\n\t\t\t// \tlogger.log('\\t data', data);\r\n\t\t\t// }\r\n\t\t}\r\n\t}\r\n\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t data', data);\r\n\t// }\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = Object.keys(data).map(turn => ({\r\n\t\tturn: +turn,\r\n\t\tdataPoints: data[turn].dataPoints,\r\n\t\ttotalWinrate: data[turn].totalWinrate,\r\n\t}));\r\n\t// if (debug) {\r\n\t// \tlogger.log('\\t result', result);\r\n\t// }\r\n\treturn result;\r\n};\r\n\r\nconst loadRows = async (mysql: ServerlessMysql): Promise<readonly InternalBgsRow[]> => {\r\n\t// We actually use all the fields\r\n\tconst query = `\r\n\t\tSELECT *\r\n\t\tFROM bgs_run_stats\r\n\t\tWHERE creationDate > DATE_SUB(NOW(), INTERVAL 30 DAY);\r\n\t`;\r\n\tlogger.log('running query', query);\r\n\tconst rows: readonly InternalBgsRow[] = await mysql.query(query);\r\n\tlogger.log('rows', rows?.length, rows[0]);\r\n\treturn rows\r\n\t\t.filter(row => row.heroCardId.startsWith('TB_BaconShop_') || row.heroCardId.startsWith('BG'))\r\n\t\t.filter(\r\n\t\t\trow =>\r\n\t\t\t\trow.heroCardId !== CardIds.ArannaStarseeker_ArannaUnleashedTokenBattlegrounds &&\r\n\t\t\t\trow.heroCardId !== CardIds.QueenAzshara_NagaQueenAzsharaToken,\r\n\t\t)\r\n\t\t.map(row => ({\r\n\t\t\t...row,\r\n\t\t\theroCardId: normalizeHeroCardId(row.heroCardId, allCards),\r\n\t\t}));\r\n};\r\n\r\nconst getLastBattlegroundsPatch = async (): Promise<PatchInfo> => {\r\n\tconst patchInfo = await http(`https://static.zerotoheroes.com/hearthstone/data/patches.json`);\r\n\tconst structuredPatch = JSON.parse(patchInfo);\r\n\tconst patchNumber = structuredPatch.currentBattlegroundsMetaPatch;\r\n\treturn structuredPatch.patches.find(patch => patch.number === patchNumber);\r\n};\r\n"]}
@@ -7,12 +7,11 @@ const data_filter_1 = require("./data-filter");
7
7
  const stats_buikder_1 = require("./stats-buikder");
8
8
  exports.QUESTS_BUCKET = `static.zerotoheroes.com`;
9
9
  exports.handleQuestsV2 = async (timePeriod, rows, lastPatch) => {
10
- var _a, _b;
10
+ var _a;
11
11
  const rowsWithQuests = rows
12
12
  .filter(row => row.quests)
13
13
  .filter(row => { var _a; return !!((_a = row.bgsHeroQuestRewards) === null || _a === void 0 ? void 0 : _a.length); })
14
14
  .filter(row => { var _a; return !!((_a = row.bgsQuestsDifficulties) === null || _a === void 0 ? void 0 : _a.length); });
15
- console.log('total relevant rows', (_a = rowsWithQuests) === null || _a === void 0 ? void 0 : _a.length);
16
15
  const statResult = await data_filter_1.buildSplitStats(rowsWithQuests, timePeriod, lastPatch, (data) => stats_buikder_1.buildStats(data));
17
16
  const stats = statResult.stats;
18
17
  const statsForQuests = {
@@ -21,7 +20,7 @@ exports.handleQuestsV2 = async (timePeriod, rows, lastPatch) => {
21
20
  questStats: stats,
22
21
  dataPoints: rowsWithQuests.length,
23
22
  };
24
- aws_lambda_utils_1.logger.log('\tbuilt stats', statsForQuests.dataPoints, (_b = statsForQuests.questStats) === null || _b === void 0 ? void 0 : _b.length);
23
+ aws_lambda_utils_1.logger.log('\tbuilt stats', statsForQuests.dataPoints, (_a = statsForQuests.questStats) === null || _a === void 0 ? void 0 : _a.length);
25
24
  const timeSuffix = timePeriod;
26
25
  await build_battlegrounds_hero_stats_new_1.s3.writeFile(zlib_1.gzipSync(JSON.stringify(statsForQuests)), exports.QUESTS_BUCKET, `api/bgs/quests/bgs-quests-v2-${timeSuffix}.gz.json`, 'application/json', 'gzip');
27
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"quests-v2.js","sourceRoot":"/","sources":["quests-v2/quests-v2.ts"],"names":[],"mappings":";;AAAA,qEAAwD;AACxD,+BAAgC;AAChC,8FAA2D;AAI3D,+CAAgD;AAChD,mDAA6C;AAEhC,QAAA,aAAa,GAAG,yBAAyB,CAAC;AAE1C,QAAA,cAAc,GAAG,KAAK,EAClC,UAAmE,EACnE,IAA+B,EAC/B,SAAoB,EACnB,EAAE;;IACH,MAAM,cAAc,GAAG,IAAI;SACzB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;SACzB,MAAM,CAAC,GAAG,CAAC,EAAE,WAAC,OAAA,CAAC,QAAC,GAAG,CAAC,mBAAmB,0CAAE,MAAM,CAAA,CAAA,EAAA,CAAC;SAChD,MAAM,CAAC,GAAG,CAAC,EAAE,WAAC,OAAA,CAAC,QAAC,GAAG,CAAC,qBAAqB,0CAAE,MAAM,CAAA,CAAA,EAAA,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,qBAAqB,QAAE,cAAc,0CAAE,MAAM,CAAC,CAAC;IAE3D,MAAM,UAAU,GAAG,MAAM,6BAAe,CAAC,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,IAAsB,EAAE,EAAE,CAC1G,0BAAU,CAAC,IAAI,CAAC,CAChB,CAAC;IACF,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;IAC/B,MAAM,cAAc,GAAkB;QACrC,cAAc,EAAE,IAAI,IAAI,EAAE;QAC1B,cAAc,EAAE,UAAU,CAAC,cAAc;QACzC,UAAU,EAAE,KAAK;QACjB,UAAU,EAAE,cAAc,CAAC,MAAM;KACjC,CAAC;IACF,yBAAM,CAAC,GAAG,CAAC,eAAe,EAAE,cAAc,CAAC,UAAU,QAAE,cAAc,CAAC,UAAU,0CAAE,MAAM,CAAC,CAAC;IAC1F,MAAM,UAAU,GAAG,UAAU,CAAC;IAC9B,MAAM,uCAAE,CAAC,SAAS,CACjB,eAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,EACxC,qBAAa,EACb,gCAAgC,UAAU,UAAU,EACpD,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { logger } from '@firestone-hs/aws-lambda-utils';\r\nimport { gzipSync } from 'zlib';\r\nimport { s3 } from '../build-battlegrounds-hero-stats-new';\r\nimport { PatchInfo } from '../common';\r\nimport { InternalBgsRow } from '../internal-model';\r\nimport { BgsQuestStats } from './bgs-quest-stat';\r\nimport { buildSplitStats } from './data-filter';\r\nimport { buildStats } from './stats-buikder';\r\n\r\nexport const QUESTS_BUCKET = `static.zerotoheroes.com`;\r\n\r\nexport const handleQuestsV2 = async (\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\trows: readonly InternalBgsRow[],\r\n\tlastPatch: PatchInfo,\r\n) => {\r\n\tconst rowsWithQuests = rows\r\n\t\t.filter(row => row.quests)\r\n\t\t.filter(row => !!row.bgsHeroQuestRewards?.length)\r\n\t\t.filter(row => !!row.bgsQuestsDifficulties?.length);\r\n\tconsole.log('total relevant rows', rowsWithQuests?.length);\r\n\r\n\tconst statResult = await buildSplitStats(rowsWithQuests, timePeriod, lastPatch, (data: InternalBgsRow[]) =>\r\n\t\tbuildStats(data),\r\n\t);\r\n\tconst stats = statResult.stats;\r\n\tconst statsForQuests: BgsQuestStats = {\r\n\t\tlastUpdateDate: new Date(),\r\n\t\tmmrPercentiles: statResult.mmrPercentiles,\r\n\t\tquestStats: stats,\r\n\t\tdataPoints: rowsWithQuests.length,\r\n\t};\r\n\tlogger.log('\\tbuilt stats', statsForQuests.dataPoints, statsForQuests.questStats?.length);\r\n\tconst timeSuffix = timePeriod;\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(statsForQuests)),\r\n\t\tQUESTS_BUCKET,\r\n\t\t`api/bgs/quests/bgs-quests-v2-${timeSuffix}.gz.json`,\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n"]}
1
+ {"version":3,"file":"quests-v2.js","sourceRoot":"/","sources":["quests-v2/quests-v2.ts"],"names":[],"mappings":";;AAAA,qEAAwD;AACxD,+BAAgC;AAChC,8FAA2D;AAI3D,+CAAgD;AAChD,mDAA6C;AAEhC,QAAA,aAAa,GAAG,yBAAyB,CAAC;AAE1C,QAAA,cAAc,GAAG,KAAK,EAClC,UAAmE,EACnE,IAA+B,EAC/B,SAAoB,EACnB,EAAE;;IACH,MAAM,cAAc,GAAG,IAAI;SACzB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;SACzB,MAAM,CAAC,GAAG,CAAC,EAAE,WAAC,OAAA,CAAC,QAAC,GAAG,CAAC,mBAAmB,0CAAE,MAAM,CAAA,CAAA,EAAA,CAAC;SAChD,MAAM,CAAC,GAAG,CAAC,EAAE,WAAC,OAAA,CAAC,QAAC,GAAG,CAAC,qBAAqB,0CAAE,MAAM,CAAA,CAAA,EAAA,CAAC,CAAC;IAGrD,MAAM,UAAU,GAAG,MAAM,6BAAe,CAAC,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,IAAsB,EAAE,EAAE,CAC1G,0BAAU,CAAC,IAAI,CAAC,CAChB,CAAC;IACF,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;IAC/B,MAAM,cAAc,GAAkB;QACrC,cAAc,EAAE,IAAI,IAAI,EAAE;QAC1B,cAAc,EAAE,UAAU,CAAC,cAAc;QACzC,UAAU,EAAE,KAAK;QACjB,UAAU,EAAE,cAAc,CAAC,MAAM;KACjC,CAAC;IACF,yBAAM,CAAC,GAAG,CAAC,eAAe,EAAE,cAAc,CAAC,UAAU,QAAE,cAAc,CAAC,UAAU,0CAAE,MAAM,CAAC,CAAC;IAC1F,MAAM,UAAU,GAAG,UAAU,CAAC;IAC9B,MAAM,uCAAE,CAAC,SAAS,CACjB,eAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,EACxC,qBAAa,EACb,gCAAgC,UAAU,UAAU,EACpD,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC","sourcesContent":["import { logger } from '@firestone-hs/aws-lambda-utils';\r\nimport { gzipSync } from 'zlib';\r\nimport { s3 } from '../build-battlegrounds-hero-stats-new';\r\nimport { PatchInfo } from '../common';\r\nimport { InternalBgsRow } from '../internal-model';\r\nimport { BgsQuestStats } from './bgs-quest-stat';\r\nimport { buildSplitStats } from './data-filter';\r\nimport { buildStats } from './stats-buikder';\r\n\r\nexport const QUESTS_BUCKET = `static.zerotoheroes.com`;\r\n\r\nexport const handleQuestsV2 = async (\r\n\ttimePeriod: 'all-time' | 'past-three' | 'past-seven' | 'last-patch',\r\n\trows: readonly InternalBgsRow[],\r\n\tlastPatch: PatchInfo,\r\n) => {\r\n\tconst rowsWithQuests = rows\r\n\t\t.filter(row => row.quests)\r\n\t\t.filter(row => !!row.bgsHeroQuestRewards?.length)\r\n\t\t.filter(row => !!row.bgsQuestsDifficulties?.length);\r\n\t// console.log('total relevant rows', rowsWithQuests?.length);\r\n\r\n\tconst statResult = await buildSplitStats(rowsWithQuests, timePeriod, lastPatch, (data: InternalBgsRow[]) =>\r\n\t\tbuildStats(data),\r\n\t);\r\n\tconst stats = statResult.stats;\r\n\tconst statsForQuests: BgsQuestStats = {\r\n\t\tlastUpdateDate: new Date(),\r\n\t\tmmrPercentiles: statResult.mmrPercentiles,\r\n\t\tquestStats: stats,\r\n\t\tdataPoints: rowsWithQuests.length,\r\n\t};\r\n\tlogger.log('\\tbuilt stats', statsForQuests.dataPoints, statsForQuests.questStats?.length);\r\n\tconst timeSuffix = timePeriod;\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(statsForQuests)),\r\n\t\tQUESTS_BUCKET,\r\n\t\t`api/bgs/quests/bgs-quests-v2-${timeSuffix}.gz.json`,\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n"]}
@@ -11,6 +11,9 @@ export interface BgsGlobalHeroStat {
11
11
  readonly heroCardId: string;
12
12
  readonly dataPoints: number;
13
13
  readonly averagePosition: number;
14
+ readonly standardDeviation: number;
15
+ readonly standardDeviationOfTheMean: number;
16
+ readonly conservativePositionEstimate: number;
14
17
  readonly placementDistribution: readonly {
15
18
  rank: number;
16
19
  percentage: number;
@@ -19,11 +22,16 @@ export interface BgsGlobalHeroStat {
19
22
  turn: number;
20
23
  winrate: number;
21
24
  }[];
25
+ readonly warbandStats: readonly {
26
+ turn: number;
27
+ averageStats: number;
28
+ }[];
22
29
  readonly tribeStats: readonly BgsHeroTribeStat[];
23
30
  }
24
31
  export interface BgsHeroTribeStat {
25
32
  readonly tribe: Race;
26
33
  readonly dataPoints: number;
34
+ readonly dataPointsOnMissingTribe: number;
27
35
  readonly averagePosition: number;
28
36
  readonly impactAveragePosition: number;
29
37
  readonly placementDistribution: readonly {
@@ -42,4 +50,12 @@ export interface BgsHeroTribeStat {
42
50
  turn: number;
43
51
  impact: number;
44
52
  }[];
53
+ readonly warbandStats: readonly {
54
+ turn: number;
55
+ averageStats: number;
56
+ }[];
57
+ readonly impactWarbandStats: readonly {
58
+ turn: number;
59
+ impact: number;
60
+ }[];
45
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bgs-hero-stat.js","sourceRoot":"/","sources":["stats-v2/bgs-hero-stat.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { MmrPercentile } from '../bgs-global-stats';\r\nimport { WithMmrAndTimePeriod } from '../quests-v2/charged-stat';\r\n\r\nexport interface BgsHeroStatsV2 {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly heroStats: readonly WithMmrAndTimePeriod<BgsGlobalHeroStat>[];\r\n}\r\n\r\nexport interface BgsGlobalHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\t// // Same\r\n\t// readonly warbandStats: readonly { turn: number; dataPoints: number; totalStats: number }[];\r\n\treadonly tribeStats: readonly BgsHeroTribeStat[];\r\n}\r\n\r\nexport interface BgsHeroTribeStat {\r\n\treadonly tribe: Race;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly impactAveragePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly impactPlacementDistribution: readonly { rank: number; impact: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\treadonly impactCombatWinrate: readonly { turn: number; impact: number }[];\r\n}\r\n"]}
1
+ {"version":3,"file":"bgs-hero-stat.js","sourceRoot":"/","sources":["stats-v2/bgs-hero-stat.ts"],"names":[],"mappings":"","sourcesContent":["import { Race } from '@firestone-hs/reference-data';\r\nimport { MmrPercentile } from '../bgs-global-stats';\r\nimport { WithMmrAndTimePeriod } from '../quests-v2/charged-stat';\r\n\r\nexport interface BgsHeroStatsV2 {\r\n\treadonly lastUpdateDate: Date;\r\n\treadonly mmrPercentiles: readonly MmrPercentile[];\r\n\treadonly dataPoints: number;\r\n\treadonly heroStats: readonly WithMmrAndTimePeriod<BgsGlobalHeroStat>[];\r\n}\r\n\r\nexport interface BgsGlobalHeroStat {\r\n\treadonly heroCardId: string;\r\n\treadonly dataPoints: number;\r\n\treadonly averagePosition: number;\r\n\treadonly standardDeviation: number;\r\n\treadonly standardDeviationOfTheMean: number;\r\n\treadonly conservativePositionEstimate: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\treadonly warbandStats: readonly { turn: number; averageStats: number }[];\r\n\treadonly tribeStats: readonly BgsHeroTribeStat[];\r\n}\r\n\r\nexport interface BgsHeroTribeStat {\r\n\treadonly tribe: Race;\r\n\treadonly dataPoints: number;\r\n\treadonly dataPointsOnMissingTribe: number;\r\n\treadonly averagePosition: number;\r\n\treadonly impactAveragePosition: number;\r\n\treadonly placementDistribution: readonly { rank: number; percentage: number }[];\r\n\treadonly impactPlacementDistribution: readonly { rank: number; impact: number }[];\r\n\treadonly combatWinrate: readonly { turn: number; winrate: number }[];\r\n\treadonly impactCombatWinrate: readonly { turn: number; impact: number }[];\r\n\treadonly warbandStats: readonly { turn: number; averageStats: number }[];\r\n\treadonly impactWarbandStats: readonly { turn: number; impact: number }[];\r\n}\r\n"]}
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
4
- const reference_data_1 = require("@firestone-hs/reference-data");
5
4
  const build_battlegrounds_hero_stats_new_1 = require("../build-battlegrounds-hero-stats-new");
6
5
  const common_1 = require("../common");
7
6
  const util_functions_1 = require("../utils/util-functions");
@@ -18,22 +17,33 @@ const buildStatsForSingleHero = (rows) => {
18
17
  turn: info.turn,
19
18
  winrate: info.totalWinrate / info.dataPoints,
20
19
  }));
20
+ const rawWarbandStats = build_battlegrounds_hero_stats_new_1.buildWarbandStats(rows);
21
+ const warbandStats = rawWarbandStats.map(info => ({
22
+ turn: info.turn,
23
+ averageStats: info.totalStats / info.dataPoints,
24
+ }));
25
+ const allRanks = rows.map(r => r.rank);
26
+ const allDeviations = allRanks.map(r => averagePosition - r);
27
+ const squareDeviations = allDeviations.map(d => Math.pow(d, 2));
28
+ const sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);
29
+ const variance = sumOfSquares / rows.length;
30
+ const standardDeviation = Math.sqrt(variance);
31
+ const standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);
21
32
  const result = {
22
33
  heroCardId: ref.heroCardId,
23
34
  dataPoints: rows.length,
24
35
  averagePosition: averagePosition,
36
+ standardDeviation: standardDeviation,
37
+ standardDeviationOfTheMean: standardDeviationOfTheMean,
38
+ conservativePositionEstimate: averagePosition + 3 * standardDeviationOfTheMean,
25
39
  placementDistribution: placementDistribution,
26
40
  combatWinrate: combatWinrate,
27
- tribeStats: buildTribeStats(rows, averagePosition, placementDistribution, combatWinrate),
41
+ warbandStats: warbandStats,
42
+ tribeStats: buildTribeStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats),
28
43
  };
29
- if (ref.heroCardId === "TB_BaconShop_HERO_18") {
30
- console.debug('Patches sanity', result);
31
- console.debug('Patches sanity', result.tribeStats.map(t => t.impactAveragePosition * t.dataPoints).reduce((a, b) => a + b, 0));
32
- console.debug('Patches sanity', rows.filter(r => !r.tribes.includes('' + reference_data_1.Race.PIRATE)).length, rows.filter(r => !r.tribes.includes('' + reference_data_1.Race.PIRATE)));
33
- }
34
44
  return result;
35
45
  };
36
- const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution, refCombatWinrate) => {
46
+ const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution, refCombatWinrate, refWarbandStats) => {
37
47
  const uniqueTribes = [...new Set(rows.flatMap(r => r.tribes.split(',')).map(r => parseInt(r)))];
38
48
  return uniqueTribes.map(tribe => {
39
49
  const rowsForTribe = rows.filter(r => r.tribes.split(',').includes('' + tribe));
@@ -45,6 +55,11 @@ const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution, ref
45
55
  turn: info.turn,
46
56
  winrate: info.totalWinrate / info.dataPoints,
47
57
  }));
58
+ const rawWarbandStats = build_battlegrounds_hero_stats_new_1.buildWarbandStats(rowsForTribe);
59
+ const warbandStats = rawWarbandStats.map(info => ({
60
+ turn: info.turn,
61
+ averageStats: info.totalStats / info.dataPoints,
62
+ }));
48
63
  return {
49
64
  tribe: tribe,
50
65
  dataPoints: rowsForTribe.length,
@@ -56,7 +71,6 @@ const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution, ref
56
71
  var _a, _b;
57
72
  const newPlacementInfo = placementDistribution.find(p2 => p2.rank === p.rank);
58
73
  if (!newPlacementInfo) {
59
- console.log('missing placement info', placementDistribution, p);
60
74
  }
61
75
  return {
62
76
  rank: p.rank,
@@ -68,13 +82,23 @@ const buildTribeStats = (rows, refAveragePosition, refPlacementDistribution, ref
68
82
  var _a, _b;
69
83
  const newCombatWinrate = combatWinrate.find(c2 => c2.turn === c.turn);
70
84
  if (!newCombatWinrate) {
71
- console.debug('missing winrate info', combatWinrate);
72
85
  }
73
86
  return {
74
87
  turn: c.turn,
75
88
  impact: (_b = (_a = newCombatWinrate) === null || _a === void 0 ? void 0 : _a.winrate, (_b !== null && _b !== void 0 ? _b : 0)) - c.winrate,
76
89
  };
77
90
  }),
91
+ warbandStats: warbandStats,
92
+ impactWarbandStats: refWarbandStats.map(c => {
93
+ var _a, _b;
94
+ const newWarbandStats = warbandStats.find(c2 => c2.turn === c.turn);
95
+ if (!newWarbandStats) {
96
+ }
97
+ return {
98
+ turn: c.turn,
99
+ impact: (_b = (_a = newWarbandStats) === null || _a === void 0 ? void 0 : _a.averageStats, (_b !== null && _b !== void 0 ? _b : 0)) - c.averageStats,
100
+ };
101
+ }),
78
102
  };
79
103
  });
80
104
  };
@@ -1 +1 @@
1
- {"version":3,"file":"stats-buikder.js","sourceRoot":"/","sources":["stats-v2/stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds, Race } from '@firestone-hs/reference-data';\r\nimport { buildCombatWinrate } from '../build-battlegrounds-hero-stats-new';\r\nimport { buildPlacementDistributionWithPercentages } from '../common';\r\nimport { InternalBgsRow } from '../internal-model';\r\nimport { normalizeHeroCardId } from '../utils/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from './bgs-hero-stat';\r\n\r\nexport const buildStats = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap(data => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map(r => r.rank));\r\n\tconst placementDistribution = buildPlacementDistributionWithPercentages(rows);\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\tconst combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map(info => ({\r\n\t\tturn: info.turn,\r\n\t\twinrate: info.totalWinrate / info.dataPoints,\r\n\t}));\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: averagePosition,\r\n\t\tplacementDistribution: placementDistribution,\r\n\t\tcombatWinrate: combatWinrate,\r\n\t\ttribeStats: buildTribeStats(rows, averagePosition, placementDistribution, combatWinrate),\r\n\t};\r\n\tif (ref.heroCardId === CardIds.PatchesThePirateBattlegrounds) {\r\n\t\tconsole.debug('Patches sanity', result);\r\n\t\tconsole.debug(\r\n\t\t\t'Patches sanity',\r\n\t\t\tresult.tribeStats.map(t => t.impactAveragePosition * t.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\t);\r\n\t\tconsole.debug(\r\n\t\t\t'Patches sanity',\r\n\t\t\trows.filter(r => !r.tribes.includes('' + Race.PIRATE)).length,\r\n\t\t\trows.filter(r => !r.tribes.includes('' + Race.PIRATE)),\r\n\t\t);\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (\r\n\trows: readonly InternalBgsRow[],\r\n\trefAveragePosition: number,\r\n\trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n\trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap(r => r.tribes.split(',')).map(r => parseInt(r)))];\r\n\treturn uniqueTribes.map(tribe => {\r\n\t\tconst rowsForTribe = rows.filter(r => r.tribes.split(',').includes('' + tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter(r => !r.tribes.split(',').includes('' + tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map(r => r.rank));\r\n\t\tconst placementDistribution = buildPlacementDistributionWithPercentages(rowsForTribe);\r\n\t\tconst rawCombatWinrates = buildCombatWinrate(rowsForTribe);\r\n\t\tconst combatWinrate = rawCombatWinrates.map(info => ({\r\n\t\t\tturn: info.turn,\r\n\t\t\twinrate: info.totalWinrate / info.dataPoints,\r\n\t\t}));\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\tplacementDistribution: placementDistribution,\r\n\t\t\timpactPlacementDistribution: refPlacementDistribution.map(p => {\r\n\t\t\t\tconst newPlacementInfo = placementDistribution.find(p2 => p2.rank === p.rank);\r\n\t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n\t\t\t\tif (!newPlacementInfo) {\r\n\t\t\t\t\tconsole.log('missing placement info', placementDistribution, p);\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\trank: p.rank,\r\n\t\t\t\t\timpact: (newPlacementInfo?.percentage ?? 0) - p.percentage,\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t\tcombatWinrate: combatWinrate,\r\n\t\t\timpactCombatWinrate: refCombatWinrate.map(c => {\r\n\t\t\t\tconst newCombatWinrate = combatWinrate.find(c2 => c2.turn === c.turn);\r\n\t\t\t\tif (!newCombatWinrate) {\r\n\t\t\t\t\tconsole.debug('missing winrate info', combatWinrate);\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\tturn: c.turn,\r\n\t\t\t\t\timpact: (newCombatWinrate?.winrate ?? 0) - c.winrate,\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t};\r\n\t});\r\n};\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
1
+ {"version":3,"file":"stats-buikder.js","sourceRoot":"/","sources":["stats-v2/stats-buikder.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, Race } from '@firestone-hs/reference-data';\r\nimport { buildCombatWinrate, buildWarbandStats } from '../build-battlegrounds-hero-stats-new';\r\nimport { buildPlacementDistributionWithPercentages } from '../common';\r\nimport { InternalBgsRow } from '../internal-model';\r\nimport { normalizeHeroCardId } from '../utils/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroTribeStat } from './bgs-hero-stat';\r\n\r\nexport const buildStats = (\r\n\trows: readonly InternalBgsRow[],\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst groupedByHero: {\r\n\t\t[questCardId: string]: readonly InternalBgsRow[];\r\n\t} = groupByFunction((row: InternalBgsRow) => normalizeHeroCardId(row.heroCardId, allCards))(rows);\r\n\treturn Object.values(groupedByHero).flatMap(data => buildStatsForSingleHero(data));\r\n};\r\n\r\n// All rows here belong to a single hero\r\nconst buildStatsForSingleHero = (rows: readonly InternalBgsRow[]): BgsGlobalHeroStat => {\r\n\tconst ref = rows[0];\r\n\tconst averagePosition = average(rows.map(r => r.rank));\r\n\tconst placementDistribution = buildPlacementDistributionWithPercentages(rows);\r\n\tconst rawCombatWinrates = buildCombatWinrate(rows);\r\n\tconst combatWinrate: readonly { turn: number; winrate: number }[] = rawCombatWinrates.map(info => ({\r\n\t\tturn: info.turn,\r\n\t\twinrate: info.totalWinrate / info.dataPoints,\r\n\t}));\r\n\tconst rawWarbandStats = buildWarbandStats(rows);\r\n\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map(info => ({\r\n\t\tturn: info.turn,\r\n\t\taverageStats: info.totalStats / info.dataPoints,\r\n\t}));\r\n\r\n\tconst allRanks = rows.map(r => r.rank);\r\n\tconst allDeviations = allRanks.map(r => averagePosition - r);\r\n\tconst squareDeviations = allDeviations.map(d => Math.pow(d, 2));\r\n\tconst sumOfSquares = squareDeviations.reduce((a, b) => a + b, 0);\r\n\tconst variance = sumOfSquares / rows.length;\r\n\tconst standardDeviation = Math.sqrt(variance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(rows.length);\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: rows.length,\r\n\t\taveragePosition: averagePosition,\r\n\t\tstandardDeviation: standardDeviation,\r\n\t\tstandardDeviationOfTheMean: standardDeviationOfTheMean,\r\n\t\tconservativePositionEstimate: averagePosition + 3 * standardDeviationOfTheMean,\r\n\t\tplacementDistribution: placementDistribution,\r\n\t\tcombatWinrate: combatWinrate,\r\n\t\twarbandStats: warbandStats,\r\n\t\ttribeStats: buildTribeStats(rows, averagePosition, placementDistribution, combatWinrate, warbandStats),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst buildTribeStats = (\r\n\trows: readonly InternalBgsRow[],\r\n\trefAveragePosition: number,\r\n\trefPlacementDistribution: readonly { rank: number; percentage: number }[],\r\n\trefCombatWinrate: readonly { turn: number; winrate: number }[],\r\n\trefWarbandStats: readonly { turn: number; averageStats: number }[],\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst uniqueTribes: readonly Race[] = [...new Set(rows.flatMap(r => r.tribes.split(',')).map(r => parseInt(r)))];\r\n\treturn uniqueTribes.map(tribe => {\r\n\t\tconst rowsForTribe = rows.filter(r => r.tribes.split(',').includes('' + tribe));\r\n\t\tconst rowsWithoutTribe = rows.filter(r => !r.tribes.split(',').includes('' + tribe));\r\n\t\tconst averagePosition = average(rowsForTribe.map(r => r.rank));\r\n\t\tconst placementDistribution = buildPlacementDistributionWithPercentages(rowsForTribe);\r\n\t\tconst rawCombatWinrates = buildCombatWinrate(rowsForTribe);\r\n\t\tconst combatWinrate = rawCombatWinrates.map(info => ({\r\n\t\t\tturn: info.turn,\r\n\t\t\twinrate: info.totalWinrate / info.dataPoints,\r\n\t\t}));\r\n\t\tconst rawWarbandStats = buildWarbandStats(rowsForTribe);\r\n\t\tconst warbandStats: readonly { turn: number; averageStats: number }[] = rawWarbandStats.map(info => ({\r\n\t\t\tturn: info.turn,\r\n\t\t\taverageStats: info.totalStats / info.dataPoints,\r\n\t\t}));\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: rowsForTribe.length,\r\n\t\t\tdataPointsOnMissingTribe: rowsWithoutTribe.length,\r\n\t\t\taveragePosition: averagePosition,\r\n\t\t\timpactAveragePosition: averagePosition - refAveragePosition,\r\n\t\t\tplacementDistribution: placementDistribution,\r\n\t\t\timpactPlacementDistribution: refPlacementDistribution.map(p => {\r\n\t\t\t\tconst newPlacementInfo = placementDistribution.find(p2 => p2.rank === p.rank);\r\n\t\t\t\t// Cna happen when there isn't a lot of data points, typically for high MMR\r\n\t\t\t\tif (!newPlacementInfo) {\r\n\t\t\t\t\t// console.log('missing placement info', placementDistribution, p);\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\trank: p.rank,\r\n\t\t\t\t\timpact: (newPlacementInfo?.percentage ?? 0) - p.percentage,\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t\tcombatWinrate: combatWinrate,\r\n\t\t\timpactCombatWinrate: refCombatWinrate.map(c => {\r\n\t\t\t\tconst newCombatWinrate = combatWinrate.find(c2 => c2.turn === c.turn);\r\n\t\t\t\tif (!newCombatWinrate) {\r\n\t\t\t\t\t// console.debug('missing winrate info', combatWinrate);\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\tturn: c.turn,\r\n\t\t\t\t\timpact: (newCombatWinrate?.winrate ?? 0) - c.winrate,\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t\twarbandStats: warbandStats,\r\n\t\t\timpactWarbandStats: refWarbandStats.map(c => {\r\n\t\t\t\tconst newWarbandStats = warbandStats.find(c2 => c2.turn === c.turn);\r\n\t\t\t\tif (!newWarbandStats) {\r\n\t\t\t\t\t// console.debug('missing warband info', warbandStats);\r\n\t\t\t\t}\r\n\t\t\t\treturn {\r\n\t\t\t\t\tturn: c.turn,\r\n\t\t\t\t\timpact: (newWarbandStats?.averageStats ?? 0) - c.averageStats,\r\n\t\t\t\t};\r\n\t\t\t}),\r\n\t\t};\r\n\t});\r\n};\r\n\r\nconst average = (data: readonly number[]): number => {\r\n\treturn data.reduce((a, b) => a + b, 0) / data.length;\r\n};\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firestone-hs/bgs-global-stats",
3
- "version": "1.0.33",
3
+ "version": "1.0.36",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "lint": "eslint --color --fix --ext .ts .",
@@ -79,4 +79,4 @@
79
79
  "node"
80
80
  ]
81
81
  }
82
- }
82
+ }