From e4037f1a77f3b54a789155a66c157b42ac798cfa Mon Sep 17 00:00:00 2001 From: Fahd Date: Sat, 14 Mar 2026 10:25:26 +0000 Subject: [PATCH 1/3] chore: comply with .editorconfig formatting rules --- champion_to_index.json | 344 ++++++++++++++--------------- data/collect.js | 38 ++-- data/download.js | 93 ++++---- data/game.js | 62 +++--- data/match_ids.js | 134 +++++------ data/utils.js | 122 +++++----- lolytics/src/App.jsx | 24 +- lolytics/src/LineChart.jsx | 4 +- lolytics/src/MatchCard.jsx | 14 +- lolytics/src/PurchasePath.css | 2 +- lolytics/src/PurchasePath.jsx | 20 +- lolytics/src/Runes.css | 2 +- lolytics/src/Runes.jsx | 50 ++--- lolytics/src/Scoreboard.css | 106 ++++----- lolytics/src/Scoreboard.jsx | 34 +-- lolytics/src/components/Navbar.jsx | 10 +- lolytics/src/main.jsx | 2 +- lolytics/src/pages/FAQ.jsx | 2 +- lolytics/src/pages/Home.jsx | 158 ++++++------- lolytics/src/pages/Research.jsx | 2 +- model/create_dataset.py | 62 +++--- model/game.py | 321 ++++++++++++++------------- model/metrics.py | 74 +++---- server/match_details.py | 30 +-- server/network.py | 2 +- 25 files changed, 855 insertions(+), 857 deletions(-) diff --git a/champion_to_index.json b/champion_to_index.json index 138edd9..126bda1 100644 --- a/champion_to_index.json +++ b/champion_to_index.json @@ -1,174 +1,174 @@ { - "Aatrox": 0, - "Ahri": 1, - "Akali": 2, - "Akshan": 3, - "Alistar": 4, - "Ambessa": 5, - "Amumu": 6, - "Anivia": 7, - "Annie": 8, - "Aphelios": 9, - "Ashe": 10, - "AurelionSol": 11, - "Aurora": 12, - "Azir": 13, - "Bard": 14, - "Belveth": 15, - "Blitzcrank": 16, - "Brand": 17, - "Braum": 18, - "Briar": 19, - "Caitlyn": 20, - "Camille": 21, - "Cassiopeia": 22, - "Chogath": 23, - "Corki": 24, - "Darius": 25, - "Diana": 26, - "DrMundo": 27, - "Draven": 28, - "Ekko": 29, - "Elise": 30, - "Evelynn": 31, - "Ezreal": 32, - "FiddleSticks": 33, - "Fiora": 34, - "Fizz": 35, - "Galio": 36, - "Gangplank": 37, - "Garen": 38, - "Gnar": 39, - "Gragas": 40, - "Graves": 41, - "Gwen": 42, - "Hecarim": 43, - "Heimerdinger": 44, - "Hwei": 45, - "Illaoi": 46, - "Irelia": 47, - "Ivern": 48, - "Janna": 49, - "JarvanIV": 50, - "Jax": 51, - "Jayce": 52, - "Jhin": 53, - "Jinx": 54, - "KSante": 55, - "Kaisa": 56, - "Kalista": 57, - "Karma": 58, - "Karthus": 59, - "Kassadin": 60, - "Katarina": 61, - "Kayle": 62, - "Kayn": 63, - "Kennen": 64, - "Khazix": 65, - "Kindred": 66, - "Kled": 67, - "KogMaw": 68, - "Leblanc": 69, - "LeeSin": 70, - "Leona": 71, - "Lillia": 72, - "Lissandra": 73, - "Lucian": 74, - "Lulu": 75, - "Lux": 76, - "Malphite": 77, - "Malzahar": 78, - "Maokai": 79, - "MasterYi": 80, - "Mel": 81, - "Milio": 82, - "MissFortune": 83, - "Mordekaiser": 84, - "Morgana": 85, - "Naafiri": 86, - "Nami": 87, - "Nasus": 88, - "Nautilus": 89, - "Neeko": 90, - "Nidalee": 91, - "Nilah": 92, - "Nocturne": 93, - "Nunu": 94, - "Olaf": 95, - "Orianna": 96, - "Ornn": 97, - "Pantheon": 98, - "Poppy": 99, - "Pyke": 100, - "Qiyana": 101, - "Quinn": 102, - "Rakan": 103, - "Rammus": 104, - "RekSai": 105, - "Rell": 106, - "Renata": 107, - "Renekton": 108, - "Rengar": 109, - "Riven": 110, - "Rumble": 111, - "Ryze": 112, - "Samira": 113, - "Sejuani": 114, - "Senna": 115, - "Seraphine": 116, - "Sett": 117, - "Shaco": 118, - "Shen": 119, - "Shyvana": 120, - "Singed": 121, - "Sion": 122, - "Sivir": 123, - "Skarner": 124, - "Smolder": 125, - "Sona": 126, - "Soraka": 127, - "Swain": 128, - "Sylas": 129, - "Syndra": 130, - "TahmKench": 131, - "Taliyah": 132, - "Talon": 133, - "Taric": 134, - "Teemo": 135, - "Thresh": 136, - "Tristana": 137, - "Trundle": 138, - "Tryndamere": 139, - "TwistedFate": 140, - "Twitch": 141, - "Udyr": 142, - "Urgot": 143, - "Varus": 144, - "Vayne": 145, - "Veigar": 146, - "Velkoz": 147, - "Vex": 148, - "Vi": 149, - "Viego": 150, - "Viktor": 151, - "Vladimir": 152, - "Volibear": 153, - "Warwick": 154, - "MonkeyKing": 155, - "Xayah": 156, - "Xerath": 157, - "XinZhao": 158, - "Yasuo": 159, - "Yone": 160, - "Yorick": 161, - "Yunara": 162, - "Yuumi": 163, - "Zaahen": 164, - "Zac": 165, - "Zed": 166, - "Zeri": 167, - "Ziggs": 168, - "Zilean": 169, - "Zoe": 170, - "Zyra": 171 + "Aatrox": 0, + "Ahri": 1, + "Akali": 2, + "Akshan": 3, + "Alistar": 4, + "Ambessa": 5, + "Amumu": 6, + "Anivia": 7, + "Annie": 8, + "Aphelios": 9, + "Ashe": 10, + "AurelionSol": 11, + "Aurora": 12, + "Azir": 13, + "Bard": 14, + "Belveth": 15, + "Blitzcrank": 16, + "Brand": 17, + "Braum": 18, + "Briar": 19, + "Caitlyn": 20, + "Camille": 21, + "Cassiopeia": 22, + "Chogath": 23, + "Corki": 24, + "Darius": 25, + "Diana": 26, + "DrMundo": 27, + "Draven": 28, + "Ekko": 29, + "Elise": 30, + "Evelynn": 31, + "Ezreal": 32, + "FiddleSticks": 33, + "Fiora": 34, + "Fizz": 35, + "Galio": 36, + "Gangplank": 37, + "Garen": 38, + "Gnar": 39, + "Gragas": 40, + "Graves": 41, + "Gwen": 42, + "Hecarim": 43, + "Heimerdinger": 44, + "Hwei": 45, + "Illaoi": 46, + "Irelia": 47, + "Ivern": 48, + "Janna": 49, + "JarvanIV": 50, + "Jax": 51, + "Jayce": 52, + "Jhin": 53, + "Jinx": 54, + "KSante": 55, + "Kaisa": 56, + "Kalista": 57, + "Karma": 58, + "Karthus": 59, + "Kassadin": 60, + "Katarina": 61, + "Kayle": 62, + "Kayn": 63, + "Kennen": 64, + "Khazix": 65, + "Kindred": 66, + "Kled": 67, + "KogMaw": 68, + "Leblanc": 69, + "LeeSin": 70, + "Leona": 71, + "Lillia": 72, + "Lissandra": 73, + "Lucian": 74, + "Lulu": 75, + "Lux": 76, + "Malphite": 77, + "Malzahar": 78, + "Maokai": 79, + "MasterYi": 80, + "Mel": 81, + "Milio": 82, + "MissFortune": 83, + "Mordekaiser": 84, + "Morgana": 85, + "Naafiri": 86, + "Nami": 87, + "Nasus": 88, + "Nautilus": 89, + "Neeko": 90, + "Nidalee": 91, + "Nilah": 92, + "Nocturne": 93, + "Nunu": 94, + "Olaf": 95, + "Orianna": 96, + "Ornn": 97, + "Pantheon": 98, + "Poppy": 99, + "Pyke": 100, + "Qiyana": 101, + "Quinn": 102, + "Rakan": 103, + "Rammus": 104, + "RekSai": 105, + "Rell": 106, + "Renata": 107, + "Renekton": 108, + "Rengar": 109, + "Riven": 110, + "Rumble": 111, + "Ryze": 112, + "Samira": 113, + "Sejuani": 114, + "Senna": 115, + "Seraphine": 116, + "Sett": 117, + "Shaco": 118, + "Shen": 119, + "Shyvana": 120, + "Singed": 121, + "Sion": 122, + "Sivir": 123, + "Skarner": 124, + "Smolder": 125, + "Sona": 126, + "Soraka": 127, + "Swain": 128, + "Sylas": 129, + "Syndra": 130, + "TahmKench": 131, + "Taliyah": 132, + "Talon": 133, + "Taric": 134, + "Teemo": 135, + "Thresh": 136, + "Tristana": 137, + "Trundle": 138, + "Tryndamere": 139, + "TwistedFate": 140, + "Twitch": 141, + "Udyr": 142, + "Urgot": 143, + "Varus": 144, + "Vayne": 145, + "Veigar": 146, + "Velkoz": 147, + "Vex": 148, + "Vi": 149, + "Viego": 150, + "Viktor": 151, + "Vladimir": 152, + "Volibear": 153, + "Warwick": 154, + "MonkeyKing": 155, + "Xayah": 156, + "Xerath": 157, + "XinZhao": 158, + "Yasuo": 159, + "Yone": 160, + "Yorick": 161, + "Yunara": 162, + "Yuumi": 163, + "Zaahen": 164, + "Zac": 165, + "Zed": 166, + "Zeri": 167, + "Ziggs": 168, + "Zilean": 169, + "Zoe": 170, + "Zyra": 171 } diff --git a/data/collect.js b/data/collect.js index 9bd3ee0..c6c09a7 100644 --- a/data/collect.js +++ b/data/collect.js @@ -7,28 +7,28 @@ let all_games = []; let promises = []; for (const rank of ['IRON', 'BRONZE', 'SILVER', 'GOLD', 'PLATINUM', 'EMERALD', 'DIAMOND']) { - for (const tier of ['I', 'II', 'III', 'IV']) { - promises.push(get_ids(rank, tier, API_KEYS[promises.length])); - if (promises.length >= API_KEYS.length) { - const results = await Promise.all(promises); - all_games = all_games.concat(...results); - promises = []; - } - } + for (const tier of ['I', 'II', 'III', 'IV']) { + promises.push(get_ids(rank, tier, API_KEYS[promises.length])); + if (promises.length >= API_KEYS.length) { + const results = await Promise.all(promises); + all_games = all_games.concat(...results); + promises = []; + } + } } if (promises.length > 0) { - const results = await Promise.all(promises); - all_games = all_games.concat(...results); - promises = []; + const results = await Promise.all(promises); + all_games = all_games.concat(...results); + promises = []; } let match_ids = await get_match_id_batch('MASTER', undefined, undefined, API_KEYS[0]); for (const id of match_ids) { - all_games.push({ - match_id: id, - rank: 'MASTER', - }); + all_games.push({ + match_id: id, + rank: 'MASTER', + }); } const seen = new Set(); @@ -37,11 +37,11 @@ const deduped = all_games.filter(o => !seen.has(o.match_id) && seen.add(o.match_ let csv = 'match_id,rank,tier\n'; for (const obj of deduped) { - const match_id = obj.match_id; - const rank = obj.rank; - const tier = obj.tier ?? ''; + const match_id = obj.match_id; + const rank = obj.rank; + const tier = obj.tier ?? ''; - csv += `${match_id},${rank},${tier}\n`; + csv += `${match_id},${rank},${tier}\n`; } fs.writeFileSync('match_ids.csv', csv, 'utf8'); diff --git a/data/download.js b/data/download.js index 75b11af..4974cdc 100644 --- a/data/download.js +++ b/data/download.js @@ -16,61 +16,60 @@ shuffle(lines); const TEST_SPLIT = process.argv[2]; if (TEST_SPLIT > 1) { - console.error('Test split must be less than 1'); - process.exit(-1); + console.error('Test split must be less than 1'); + process.exit(-1); } else if (TEST_SPLIT < 0) { - console.error('Test split must be greater than 0'); - process.exit(-1); + console.error('Test split must be greater than 0'); + process.exit(-1); } const TEST_SIZE = parseInt(lines.length * TEST_SPLIT); console.log(`Downloading dataset with ${TEST_SIZE} test samples`); async function download_games(rows, split) { - let promises = []; - let elos = []; - let index = 0; + let promises = []; + let elos = []; + let index = 0; - for (const line of rows) { - const [match_id, rank, tier] = line.split(','); - - promises.push(get_game_data(match_id, API_KEYS[promises.length])); - elos.push({rank, tier}); - if (promises.length >= API_KEYS.length) { - const results = await Promise.all(promises); - results.forEach((game, i) => { - if (game != null) { - fs.mkdirSync(`dataset/${split}/${elos[i].rank}`, { recursive: true }); - if (elos[i].rank == 'MASTER') { - fs.writeFileSync(`dataset/${split}/${elos[i].rank}/game_${index}.json`, JSON.stringify(game), 'utf8'); - } else { - fs.mkdirSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}`, { recursive: true }); - fs.writeFileSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}/game_${index}.json`, JSON.stringify(game), 'utf8'); - } - index++; - } - }); - promises = []; - elos = []; - } - } - - if (promises.length > 0) { - const results = await Promise.all(promises); - results.forEach((game, i) => { - if (game != null) { - fs.mkdirSync(`dataset/${split}/${elos[i].rank}`, { recursive: true }); - if (elos[i].rank == 'MASTER') { - fs.writeFileSync(`dataset/${split}/${elos[i].rank}/game_${index}.json`, JSON.stringify(game), 'utf8'); - } else { - fs.mkdirSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}`, { recursive: true }); - fs.writeFileSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}/game_${index}.json`, JSON.stringify(game), 'utf8'); - } - index++; - } - }); - } + for (const line of rows) { + const [match_id, rank, tier] = line.split(','); + promises.push(get_game_data(match_id, API_KEYS[promises.length])); + elos.push({rank, tier}); + if (promises.length >= API_KEYS.length) { + const results = await Promise.all(promises); + results.forEach((game, i) => { + if (game != null) { + fs.mkdirSync(`dataset/${split}/${elos[i].rank}`, { recursive: true }); + if (elos[i].rank == 'MASTER') { + fs.writeFileSync(`dataset/${split}/${elos[i].rank}/game_${index}.json`, JSON.stringify(game), 'utf8'); + } else { + fs.mkdirSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}`, { recursive: true }); + fs.writeFileSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}/game_${index}.json`, JSON.stringify(game), 'utf8'); + } + index++; + } + }); + promises = []; + elos = []; + } + } + + if (promises.length > 0) { + const results = await Promise.all(promises); + results.forEach((game, i) => { + if (game != null) { + fs.mkdirSync(`dataset/${split}/${elos[i].rank}`, { recursive: true }); + if (elos[i].rank == 'MASTER') { + fs.writeFileSync(`dataset/${split}/${elos[i].rank}/game_${index}.json`, JSON.stringify(game), 'utf8'); + } else { + fs.mkdirSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}`, { recursive: true }); + fs.writeFileSync(`dataset/${split}/${elos[i].rank}/${elos[i].tier}/game_${index}.json`, JSON.stringify(game), 'utf8'); + } + index++; + } + }); + } } await download_games(lines.slice(0, TEST_SIZE), 'test'); -await download_games(lines.slice(TEST_SIZE), 'train'); \ No newline at end of file +await download_games(lines.slice(TEST_SIZE), 'train'); diff --git a/data/game.js b/data/game.js index a782095..32e2244 100644 --- a/data/game.js +++ b/data/game.js @@ -1,43 +1,43 @@ import { api_call } from './utils.js'; export async function get_game_data(MATCH_ID, key) { - try { - const game = await api_call(`https://europe.api.riotgames.com/lol/match/v5/matches/${MATCH_ID}?api_key=${key}`); + try { + const game = await api_call(`https://europe.api.riotgames.com/lol/match/v5/matches/${MATCH_ID}?api_key=${key}`); - const timeline = await api_call(`https://europe.api.riotgames.com/lol/match/v5/matches/${MATCH_ID}/timeline?api_key=${key}`); + const timeline = await api_call(`https://europe.api.riotgames.com/lol/match/v5/matches/${MATCH_ID}/timeline?api_key=${key}`); - const data = { champions: [], events: [], win: game.info.participants[0].win }; + const data = { champions: [], events: [], win: game.info.participants[0].win }; - for (const participant of game.info.participants) { - data.champions.push(participant.championName); - } + for (const participant of game.info.participants) { + data.champions.push(participant.championName); + } - function is_strong_event(event) { + function is_strong_event(event) { if (event.type == 'ELITE_MONSTER_KILL' && event.killerId == 0) { return false; } - return ['CHAMPION_KILL', 'BUILDING_KILL', 'ELITE_MONSTER_KILL', 'LEVEL_UP', 'ITEM_PURCHASED', 'ITEM_UNDO', 'ITEM_DESTROYED', 'ITEM_SOLD'].includes(event.type); - } - - for (const frame of timeline.info.frames) { - for (const event of frame.events) { - if (event.type == 'CHAMPION_KILL') { - try { - delete event.victimDamageDealt; - delete event.victimDamageReceived; - delete event.victimTeamfightDamageDealt; - delete event.victimTeamfightDamageReceived; - } catch(e) {} - } - if (is_strong_event(event)) { - data.events.push(event); - } - } - } - - return data; - } catch(e) { - return null; - } + return ['CHAMPION_KILL', 'BUILDING_KILL', 'ELITE_MONSTER_KILL', 'LEVEL_UP', 'ITEM_PURCHASED', 'ITEM_UNDO', 'ITEM_DESTROYED', 'ITEM_SOLD'].includes(event.type); + } + + for (const frame of timeline.info.frames) { + for (const event of frame.events) { + if (event.type == 'CHAMPION_KILL') { + try { + delete event.victimDamageDealt; + delete event.victimDamageReceived; + delete event.victimTeamfightDamageDealt; + delete event.victimTeamfightDamageReceived; + } catch(e) {} + } + if (is_strong_event(event)) { + data.events.push(event); + } + } + } + + return data; + } catch(e) { + return null; + } } diff --git a/data/match_ids.js b/data/match_ids.js index da7af15..310046c 100644 --- a/data/match_ids.js +++ b/data/match_ids.js @@ -1,92 +1,92 @@ import { api_call, fetch_with_retries, shuffle } from './utils.js'; async function get_summoner_ids(rank, tier, page, key) { - const summoner_ids = []; - if (rank == 'MASTER') { - const summoner_ids = []; - let response = await fetch_with_retries( - `https://euw1.api.riotgames.com/lol/league/v4/masterleagues/by-queue/RANKED_SOLO_5x5?api_key=${key}`, - ); - if (response == null) { - return []; - } - for (const summoner of response.entries) { - summoner_ids.push(summoner.puuid); - } - shuffle(summoner_ids); - return summoner_ids.slice(0, 800); - } else { - let response = await fetch_with_retries( - `https://euw1.api.riotgames.com/lol/league/v4/entries/RANKED_SOLO_5x5/${rank}/${tier}?page=${page}&api_key=${key}`, - ); - if (response == null) { - return []; - } - for (const summoner of response) { - summoner_ids.push(summoner.puuid); - } - } - shuffle(summoner_ids); - return summoner_ids; + const summoner_ids = []; + if (rank == 'MASTER') { + const summoner_ids = []; + let response = await fetch_with_retries( + `https://euw1.api.riotgames.com/lol/league/v4/masterleagues/by-queue/RANKED_SOLO_5x5?api_key=${key}`, + ); + if (response == null) { + return []; + } + for (const summoner of response.entries) { + summoner_ids.push(summoner.puuid); + } + shuffle(summoner_ids); + return summoner_ids.slice(0, 800); + } else { + let response = await fetch_with_retries( + `https://euw1.api.riotgames.com/lol/league/v4/entries/RANKED_SOLO_5x5/${rank}/${tier}?page=${page}&api_key=${key}`, + ); + if (response == null) { + return []; + } + for (const summoner of response) { + summoner_ids.push(summoner.puuid); + } + } + shuffle(summoner_ids); + return summoner_ids; } async function get_summoner_match_ids(summoner_id, key) { - const now = new Date(); - const twenty_days_ago = new Date(now); - twenty_days_ago.setDate(now.getDate() - 20); + const now = new Date(); + const twenty_days_ago = new Date(now); + twenty_days_ago.setDate(now.getDate() - 20); - const start = Math.floor(twenty_days_ago.getTime() / 1000); + const start = Math.floor(twenty_days_ago.getTime() / 1000); - let match_history = await api_call( - `https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/${summoner_id}/ids?startTime=${start}&queue=420&start=0&count=50&api_key=${key}`, - ); + let match_history = await api_call( + `https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/${summoner_id}/ids?startTime=${start}&queue=420&start=0&count=50&api_key=${key}`, + ); - return match_history; + return match_history; } export async function get_match_id_batch(rank, tier, page, key) { - let match_ids = []; + let match_ids = []; - const summoner_ids = await get_summoner_ids(rank, tier, page, key); + const summoner_ids = await get_summoner_ids(rank, tier, page, key); - if (summoner_ids.length == 0) { - return match_ids; - } + if (summoner_ids.length == 0) { + return match_ids; + } - for (const summoner_id of summoner_ids) { - try { - const ids = await get_summoner_match_ids(summoner_id, key); - match_ids = match_ids.concat(ids); - } catch (e) { - console.log(e); - } - } + for (const summoner_id of summoner_ids) { + try { + const ids = await get_summoner_match_ids(summoner_id, key); + match_ids = match_ids.concat(ids); + } catch (e) { + console.log(e); + } + } - return match_ids.filter((e) => e != null); + return match_ids.filter((e) => e != null); } export async function get_ids(rank, tier, key) { - let match_ids = []; + let match_ids = []; - let n_pages = 4; - if (rank == 'IRON' || rank == 'BRONZE') { - n_pages = 5; - } + let n_pages = 4; + if (rank == 'IRON' || rank == 'BRONZE') { + n_pages = 5; + } - for (let page = 1; page <= n_pages; page++) { - const results = await get_match_id_batch(rank, tier, page, key); - match_ids = match_ids.concat(results); - } + for (let page = 1; page <= n_pages; page++) { + const results = await get_match_id_batch(rank, tier, page, key); + match_ids = match_ids.concat(results); + } - shuffle(match_ids); + shuffle(match_ids); - console.log(`Found ${match_ids.length} ids for ${rank} ${tier}`); + console.log(`Found ${match_ids.length} ids for ${rank} ${tier}`); - return match_ids.map((v, _) => { - return { - match_id: v, - rank, - tier - } - }); + return match_ids.map((v, _) => { + return { + match_id: v, + rank, + tier + } + }); } diff --git a/data/utils.js b/data/utils.js index 2bee330..e2020a4 100644 --- a/data/utils.js +++ b/data/utils.js @@ -1,80 +1,80 @@ const TIME_BETWEEN_REQUESTS = 1300; export function api_call(url) { - return new Promise((resolve, reject) => { - setTimeout(async () => { - try { - const response = await fetch(url); + return new Promise((resolve, reject) => { + setTimeout(async () => { + try { + const response = await fetch(url); - if (!response.ok) { - const error = new Error(`Request failed with status ${response.status}`); - error.response = response; - throw error; - } + if (!response.ok) { + const error = new Error(`Request failed with status ${response.status}`); + error.response = response; + throw error; + } - const json = await response.json(); - resolve(json); - } catch (e) { - reject(e); - } - }, TIME_BETWEEN_REQUESTS); - }); + const json = await response.json(); + resolve(json); + } catch (e) { + reject(e); + } + }, TIME_BETWEEN_REQUESTS); + }); } export function deep_copy(obj) { - if (obj === null || typeof obj !== 'object') { - return obj; - } + if (obj === null || typeof obj !== 'object') { + return obj; + } - if (Array.isArray(obj)) { - const copy = []; - for (let i = 0; i < obj.length; i++) { - copy[i] = deep_copy(obj[i]); - } - return copy; - } + if (Array.isArray(obj)) { + const copy = []; + for (let i = 0; i < obj.length; i++) { + copy[i] = deep_copy(obj[i]); + } + return copy; + } - const copy = {}; - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - copy[key] = deep_copy(obj[key]); - } - } - return copy; + const copy = {}; + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + copy[key] = deep_copy(obj[key]); + } + } + return copy; } export function shuffle(array) { - let current_index = array.length, - random_index; + let current_index = array.length, + random_index; - while (current_index > 0) { - random_index = Math.floor(Math.random() * current_index); - current_index--; - [array[current_index], array[random_index]] = [ - array[random_index], - array[current_index], - ]; - } + while (current_index > 0) { + random_index = Math.floor(Math.random() * current_index); + current_index--; + [array[current_index], array[random_index]] = [ + array[random_index], + array[current_index], + ]; + } - return array; + return array; } export async function fetch_with_retries(url, timeout = 3000) { - for (let attempt = 1; attempt <= 3; attempt++) { - try { - const response = await api_call(url); - return response; - } catch (error) { - if (attempt < 3) { - console.warn( - `Attempt ${attempt} failed. Retrying in ${timeout}ms... ${url}`, - ); - await new Promise((resolve) => setTimeout(resolve, timeout)); - } else { - console.error(`Attempt ${attempt} failed. Returning null.`); - console.log(url); - return null; - } - } - } + for (let attempt = 1; attempt <= 3; attempt++) { + try { + const response = await api_call(url); + return response; + } catch (error) { + if (attempt < 3) { + console.warn( + `Attempt ${attempt} failed. Retrying in ${timeout}ms... ${url}`, + ); + await new Promise((resolve) => setTimeout(resolve, timeout)); + } else { + console.error(`Attempt ${attempt} failed. Returning null.`); + console.log(url); + return null; + } + } + } } diff --git a/lolytics/src/App.jsx b/lolytics/src/App.jsx index eda70d8..718dce4 100644 --- a/lolytics/src/App.jsx +++ b/lolytics/src/App.jsx @@ -1,22 +1,22 @@ -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; -import Navbar from "./components/Navbar"; -import Home from "./pages/Home"; -import Research from "./pages/Research"; -import FAQ from "./pages/FAQ"; -import "./App.css"; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import Navbar from './components/Navbar'; +import Home from './pages/Home'; +import Research from './pages/Research'; +import FAQ from './pages/FAQ'; +import './App.css'; function App() { return ( - } /> - } /> - } /> + } /> + } /> + } /> -