1let compactFormatter = Intl.NumberFormat('en', { notation: 'compact' }); 2 3function sample_compact_number(value) { 4 switch (value) { 5 case "Overall": 6 return "Overall"; 7 case "100": 8 return "Top 100"; 9 case "1000": 10 return "Top 1K"; 11 case "10000": 12 return "Top 10K"; 13 case "100000": 14 return "Top 100K"; 15 case "1000000": 16 return "Top 1M"; 17 case "Prime": 18 return "Prime"; 19 default: 20 return value; 21 // let new_value = compactFormatter.format(value); 22 // return new_value !== "NaN" ? ("Top " + new_value) : value; 23 } 24} 25 26function reverse_sample_name(value) { 27 switch (value) { 28 case "Sample - Overall": 29 return "Overall"; 30 case "FPL Data": 31 return "Official FPL API" 32 case "Sample - Top 100": 33 case "Top 100": 34 return 100; 35 case "Sample - Top 1K": 36 case "Top 1K": 37 return 1000; 38 case "Sample - Top 10K": 39 case "Top 10K": 40 return 10000; 41 case "Sample - Top 100K": 42 case "Top 100K": 43 return 100000; 44 case "Sample - Top 1M": 45 case "Top 1M": 46 return 1000000; 47 case "Sample - Prime": 48 case "Prime": 49 return "Prime"; 50 default: 51 return value.includes("Sample - ") ? value.replace("Sample - ", "") : value; 52 } 53} 54 55function autosubbed_team(team_picks, autosub_dict) { 56 57 let sub_replacements = [] 58 let cap_replacements = [] 59 let split_team = _.groupBy(team_picks, (i) => i.multiplier > 0) 60 let lineup = split_team[true] 61 let bench = split_team[false] || [] 62 for (let i of lineup) { 63 let id = i.element; 64 let info = autosub_dict[id]; 65 if (info === undefined) { 66 continue; 67 } 68 if (info.autosub) { 69 let original_mult = i.multiplier; 70 i.multiplier = 0; 71 if (i.is_captain) { 72 i.is_captain = false; 73 let vc = lineup.find(j => j.is_vice_captain && autosub_dict[j.element].autosub == false); 74 if (vc && vc.multiplier > 0) { 75 vc.is_captain = true; 76 vc.is_vice_captain = false; 77 if (vc.multiplier <= 1) { 78 vc.multiplier = original_mult; 79 } 80 cap_replacements.push([id, vc.element]) 81 } 82 } 83 let target_pos = info.element_type; 84 let current_cnt = team_picks.filter(j => j.multiplier > 0 && (autosub_dict[j.element] && autosub_dict[j.element].element_type == target_pos)).length; 85 if (element_type[target_pos].min > current_cnt || target_pos == "1") { 86 // only this type 87 let player_to_enter = bench.find(j => autosub_dict[j.element] && autosub_dict[j.element].element_type == target_pos && autosub_dict[j.element].autosub == false) 88 if (player_to_enter) { 89 player_to_enter.multiplier = 1; 90 bench = bench.filter(i => i.element != player_to_enter.element) 91 sub_replacements.push([id, player_to_enter.element]) 92 } 93 } else { 94 // anyone on bench 95 let player_to_enter = bench.find(j => autosub_dict[j.element] && autosub_dict[j.element].element_type != "1" && autosub_dict[j.element].autosub == false) 96 if (player_to_enter) { 97 player_to_enter.multiplier = 1; 98 bench = bench.filter(i => i.element != player_to_enter.element) 99 sub_replacements.push([id, player_to_enter.element]) 100 } 101 } 102 } 103 } 104 return { 'team': team_picks, 'sub_replacement': sub_replacements, 'cap_replacement': cap_replacements }; 105} 106 107function prepare_fixture_data(data) { 108 109 data.forEach((game, index) => { 110 game.start_dt = new Date(game.kickoff_time);
111 game.end_dt = new Date(game.start_dt.getTime() + (105 * 60 * 1000)); 112 game.node_info = { start: (game.start_dt).getTime(), end: game.end_dt.getTime(), content: 'Game' } 113 }) 114 115 data.sort((a, b) => { return a.node_info.start - b.node_info.start }); 116 117 data.forEach((game, index) => { 118 game.duration = 105 * 60 * 1000; 119 game.team_h_name = teams_ordered[game.team_h - 1].name; 120 game.team_a_name = teams_ordered[game.team_a - 1].name; 121 game.label = teams_ordered[game.team_h - 1].name + " vs " + teams_ordered[game.team_a - 1].name; 122 let order = 0; 123 data.slice(0, index).forEach((game2) => { 124 if ((game.start_dt >= game2.start_dt && game.start_dt <= game2.end_dt) || 125 (game.end_dt >= game2.start_dt && game.end_dt <= game2.end_dt)) { 126 if (game2.order == order) { 127 order += 1; 128 } 129 } 130 }) 131 game.order = order; 132 }) 133 134 return data; 135} 136 137 138function get_provisional_bonus(gw_fixture) { 139 let bonus_players = {}; 140 141 gw_fixture.forEach((game) => { 142 let bps_provisional = {}; 143 144 if (needsProvisionalBonus(game)) { 145 try { 146 let bps_stats = game.stats.find(i => i.identifier == "bps") 147 let all_players = bps_stats.h.concat(bps_stats.a) 148 let sorted_groups = Object.entries(_.groupBy(all_players, i => i.value)).sort((a, b) => b[0] - a[0]).slice(0, 3) 149 sorted_groups.forEach((cat, i) => { 150 let bonus = 3 - i;
151 cat[1].forEach((p) => { 152 bonus_players[p.element] = bonus; 153 }); 154 }) 155 } catch (err) {} 156 } 157 }) 158 159 return bonus_players; 160} 161 162function rp_by_id_dict(fixture, rp_data) { 163 rp_data.forEach((p) => { 164 try { 165 p.games_finished = p.explain.map(i => { 166 let f = fixture.find(j => j.id == i.fixture) 167 if (f == undefined) { return true } 168 return f.finished_provisional 169 }).every(i => i); 170 if (p.games_finished && p.stats.minutes == 0) { 171 p.autosub = true; 172 } else { 173 p.autosub = false; 174 } 175 } catch (e) { 176 console.log("Player game_finished error", e) 177 } 178 }) 179 let rp_obj = Object.fromEntries(_.cloneDeep(rp_data.map(i => [i.id, i]))); 180 if (!_.isEmpty(this.provisional_bonus) && !_.isEmpty(rp_obj)) { 181 Object.entries(this.provisional_bonus).forEach(entry => { 182 const [key, value] = entry; 183 rp_obj[key].stats.total_points += value; 184 }) 185 } 186 return rp_obj; 187} 188 189function generate_autosub_dict(el_data, rp_by_id) { 190 let autosubs = []; 191 el_data.forEach((e) => { 192 autosubs.push([e.id, { element_type: e.element_type, autosub: rp_by_id[e.id] ? rp_by_id[e.id].autosub : false }]); 193 }) 194 let autosub_dict = Object.fromEntries(autosubs); 195 return autosub_dict; 196} 197 198function get_ownership_by_type(ownership_source, fpl_data, sample_data, autosubs) { 199 200 let teams = []; 201 if (sample_data == undefined) { 202 ownership_source = "Official FPL API"; 203 } else if (Object.keys(sample_data).length == 0) { 204 ownership_source = "Official FPL API"; 205 } 206 207 let tag = reverse_sample_name(ownership_source) 208 if (tag == "Official FPL API") { 209 return {data: fpl_data} 210 } 211 212 if (tag in sample_data) { 213 teams = sample_data[tag].filter(i => i.team != undefined) 214 } 215 else { 216 teams = sample_data['Overall'].filter(i => i.team != undefined) 217 } 218 219 220 let el_copy = _.cloneDeep(fpl_data); 221 let sub_replacements = []; 222 let cap_replacements = []; 223 224 teams = teams.filter(i => i.data != null) 225 226 if (!_.isEmpty(autosubs)) { 227 teams = _.cloneDeep(teams); 228 teams.forEach((team) => { 229 let edits = autosubbed_team(team.data.picks, autosubs); 230 team.data.picks = edits.team; 231 sub_replacements = sub_replacements.concat(edits.sub_replacement) 232 cap_replacements = cap_replacements.concat(edits.cap_replacement) 233 }) 234 } 235 236 let all_players = teams.map(i => i.data.picks).flat(); 237 let grouped_players = _.groupBy(all_players, (i) => i.element); 238 239 el_copy.forEach((e) => { 240 // let this_player_picks = all_players.filter(i => i.element == e.id); 241 let this_player_picks = grouped_players[e.id]; 242 if (this_player_picks !== undefined) { 243 let cnt = this_player_picks.length; 244 e.selected_by_percent = cnt / teams.length * 100; 245 let sum_of_multiplier = getSum(this_player_picks.map(i => i.multiplier)); 246 e.effective_ownership = sum_of_multiplier / teams.length * 100; 247 let captain_count = this_player_picks.filter(i => i.multiplier > 1.5).length; 248 e.captain_percentage = captain_count / teams.length * 100; 249 } else { 250 e.selected_by_percent = 0; 251 e.effective_ownership = 0; 252 e.captain_percentage = 0; 253 } 254 255 }); 256 return { data: el_copy, sub_replacement: sub_replacements, cap_replacement: cap_replacements }; 257} 258 259async function get_latest_sample_data(season, gw) { 260 return new Promise((resolve, reject) => { 261 get_sample_data(season, gw.slice(2)).then(data => { 262 if (data[0].status == 'rejected') { 263 get_sample_data(season, parseInt(gw.slice(2))-1).then((data) => { 264 if (data[0].status == 'rejected') { 265 reject("no data") 266 } 267 else { 268 let sample_data = data[0].value 269 if (data[1].status != 'rejected') { 270 sample_data['Prime'] = data[1].value 271 } 272 resolve({gw: parseInt(gw.slice(2))-1, data: sample_data}) 273 } 274 }) 275 } 276 else { 277 let sample_data = data[0].value 278 if (data[1].status != 'rejected') { 279 sample_data['Prime'] = data[1].value 280 } 281 resolve({gw: gw.slice(2), data: sample_data}) 282 } 283 }) 284 }) 285}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.