File Coverage

blib/lib/Sport/Analytics/NHL/Tools.pm
Criterion Covered Total %
statement 207 255 81.1
branch 44 68 64.7
condition 40 71 56.3
subroutine 40 45 88.8
pod 29 29 100.0
total 360 468 76.9


line stmt bran cond sub pod time code
1             package Sport::Analytics::NHL::Tools;
2              
3 53     53   207574 use v5.10.1;
  53         186  
4 53     53   234 use strict;
  53         93  
  53         1060  
5 53     53   220 use warnings FATAL => 'all';
  53         117  
  53         1453  
6              
7 53     53   266 use File::Find;
  53         96  
  53         3029  
8 53     53   278 use File::Path qw(make_path);
  53         89  
  53         2650  
9 53     53   12468 use POSIX qw(strftime);
  53         154305  
  53         283  
10              
11 53     53   55335 use Date::Parse;
  53         243093  
  53         5163  
12 53     53   10595 use JSON;
  53         180980  
  53         289  
13 53     53   11150 use List::MoreUtils qw(any);
  53         135841  
  53         358  
14              
15 53     53   35517 use Sport::Analytics::NHL::LocalConfig;
  53         92  
  53         5521  
16 53     53   301 use Sport::Analytics::NHL::Config;
  53         338  
  53         7397  
17 53     53   17060 use Sport::Analytics::NHL::DB;
  53         113  
  53         1488  
18 53     53   365 use Sport::Analytics::NHL::Util;
  53         91  
  53         2573  
19              
20 53     53   274 use parent 'Exporter';
  53         84  
  53         220  
21              
22             =head1 NAME
23              
24             Sport::Analytics::NHL::Tools - Commonly used routines that are system-dependent
25              
26             =head1 SYNOPSIS
27              
28             Commonly used routines that are specific to the Sport::Analytics::NHL ecosystem. For the independent stuff see Sport::Analytics::NHL::Util .
29              
30             use Sport::Analytics::NHL::Tools;
31             my $game = parse_nhl_game_id(2011020001);
32             my $season = get_season_from_date(20110202); # returns 2010
33             my $team = resolve('NY Rangers'); # returns NYR
34             #and so on
35              
36             Provides global variable $DB that can be used to store the MongoDB handle.
37              
38             =head1 FUNCTIONS
39              
40             =over 2
41              
42             =item C
43              
44             Parses the SSSSTTNNNN nhl id
45             Arguments: the nhl game id
46             Returns: hashref with season, stage, season id and our SSSSTNNNN id
47              
48             =item C
49              
50             Parses the SSSSTNNNN our id
51             Arguments: our game id
52             Returns: hashref with season, stage, season id and our SSSSTNNNN id
53              
54             =item C
55              
56             Figures out the NHL season (start year) the given YYYYMMDD date refers to
57             Arguments: the YYYYMMDD date
58             Returns: the YYYY or YYYY-1 season
59              
60             =item C
61              
62             Returns the path to the schedule file in the filesystem
63             Arguments: the season and the root of the data (optional)
64             Returns: the path to the schedule file
65              
66             =item C
67              
68             Attempts to resolve the name of a team to the normalized 3-letter id
69             Arguments: the name of a team, optional no-db force flag
70             Returns: the 3-letter normalized id
71              
72             =item C
73              
74             Converts a game record obtained from the 'live' interface to a normalized form
75              
76             Arguments: the game record
77             Returns: the normalized game
78              
79             =item C
80              
81             Arranges the schedule obtained from the 'live' interface by dates
82              
83             Arguments: the schedule
84             Returns: hashref with keys of dates,
85             values of lists of normalized game records
86              
87             =item C
88              
89             Converts a game record obtained from the API interface to a normalized form
90              
91             Arguments: the game record
92             Returns: the normalized game
93              
94             =item C
95              
96             Arranges the schedule obtained from the API interface by dates
97              
98             Arguments: the schedule
99             Returns: hashref with keys of dates,
100             values of lists of normalized game records
101              
102             =item C
103              
104             Converts a game record obtained scraping the schedules to a normalized form
105              
106             Arguments: the game record
107             Returns: the normalized game
108              
109             =item C
110              
111             Arranges the schedule obtained by the scraper by dates
112              
113             Arguments: the schedule
114             Returns: hashref with keys of dates,
115             values of lists of normalized game records
116              
117             =item C
118              
119             Gets the list of the games scheduled for given dates using the file storage
120              
121             Arguments: the list of dates
122             Returns: the list of normalized game records
123              
124             =item C
125              
126             Gets the list of the games scheduled for given dates using the database
127              
128             Arguments: the list of dates
129             Returns: the list of normalized game records
130              
131             =item C
132              
133             Gets the list of the games scheduled for given dates
134              
135             Arguments: the list of dates
136             Returns: the list of normalized game records
137              
138             =item C
139              
140             Gets the earliest possible start and latest possible end for a season in format YYYY-MM-DD
141              
142             Arguments: the season
143             Returns: (YYYY-09-02,YYYY+1-09-01)
144              
145             =item C
146              
147             Creates and/or returns the game path for a given season, stage, season_id
148              
149             Arguments: season, stage, season_id, root storage dir (optional)
150             Returns: the storage path (created if necessary)
151              
152             =item C
153              
154             Reads the existing schedules for the given range of seasons
155              
156             Arguments: the hashref with first and last season of the range
157             Returns: the schedule data, hashref by season
158              
159             =item C
160              
161             Given the game path, produces our SSSSTNNNN game id
162              
163             Arguments: the game path
164             Returns the SSSSTNNNN id, or undef if the matching of the path failed
165              
166             =item C
167              
168             Find games already scraped into the filesystem and returns the game ids of them.
169              
170             Arguments: the season to look for
171             Returns: hashref of game ids as keys and 1s as values
172              
173             =back
174              
175             =cut
176              
177             our @EXPORT = qw(
178             $DB
179             parse_nhl_game_id parse_our_game_id
180             resolve_team get_games_for_dates
181             get_season_from_date get_start_stop_date str3time
182             get_schedule_json_file make_game_path get_game_id_from_path
183             get_game_files_by_id
184             arrange_schedule_by_date convert_schedule_game read_schedules
185             read_existing_game_ids get_game_path_from_id
186             vocabulary_lookup normalize_penalty
187             is_noplay_event
188             set_roster_positions set_player_stat fix_playergoals
189             print_events
190             );
191              
192             our $DB;
193              
194             sub parse_nhl_game_id ($) {
195              
196 10     10 1 670 my $nhl_id = shift;
197              
198 10         59 $nhl_id =~ /^(\d{4})(\d{2})(\d{4})$/;
199             {
200 10         114 season => $1,
201             stage => $2 + 0,
202             season_id => $3,
203             game_id => $1*100000 + $2*10000 + $3
204             };
205             }
206              
207             sub parse_our_game_id ($) {
208              
209 26     26 1 61 my $our_id = shift;
210              
211 26         168 $our_id =~ /^(\d{4})(\d{1})(\d{4})/;
212             {
213 26         327 season => $1,
214             stage => $2 + 0,
215             season_id => $3,
216             game_id => $our_id,
217             };
218             }
219              
220             sub get_season_from_date ($) {
221              
222 8     8 1 16 my $date = shift;
223              
224 8         40 $date =~ /^(\d{4})(\d{2})(\d{2})/;
225 8 100       60 $2 > 8 ? $1 : $1 - 1;
226             }
227              
228             sub get_schedule_json_file ($;$) {
229              
230 18     18 1 3581 my $season = shift;
231 18   66     114 my $data_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
232              
233 18         111 sprintf("%s/%s/schedule.json", $data_dir, $season);
234             }
235              
236             sub get_games_for_dates_from_db (@) {
237              
238 0     0 1 0 my @dates = @_;
239              
240 0   0     0 $DB ||= Sport::Analytics::NHL::DB->new();
241 0         0 my @games = $DB->{dbh}->get_collection('schedule')->find(
242             { date => {
243             '$in' => [map($_+0, @dates)],
244             }},
245             {_id => 0, season => 1, stage => 1, season_id => 1}
246             )->all();
247 0 0       0 if (! @games) {
248 0         0 print STDERR "No matching games found in the database, trying files\n";
249 0         0 @games = get_games_for_dates_from_fs(@dates);
250             }
251 0         0 @games;
252             }
253              
254             sub resolve_team ($;$) {
255              
256 29236     29236 1 41745 my $team = shift;
257 29236   100     67048 my $force_no_db = shift || 0;
258              
259 29236 50 66     75260 if (! $force_no_db && $ENV{MONGO_DB}) {
260 0   0     0 $DB ||= Sport::Analytics::NHL::DB->new();
261 0         0 my $team_id = $DB->resolve_team_db($team);
262 0 0       0 return $team_id if $team_id;
263             }
264 29236 100 66     71207 return 'MTL' if ($team =~ /MONTR.*CAN/i || $team =~ /CAN.*MONTR/);
265 28889 100 66     64682 return 'NHL' if ($team eq 'League' || $team eq 'NHL');
266 28888         131046 for my $team_id (keys %TEAMS) {
267 638203 100       940217 return $team_id if $team_id eq $team;
268 613288         686840 for my $type (qw(short long full)) {
269 1837958 100       1813718 return $team_id if grep { uc($_) eq uc($team) } @{$TEAMS{$team_id}->{$type}};
  2824638         4585093  
  1837958         2537934  
270             }
271             }
272 0         0 die "Couldn't resolve team $team";
273             }
274              
275             =over 2
276              
277             =item C
278              
279             Wraps around str2time to fix its parsing the pre-1969 dates to the same timestamp as their 100 years laters.
280             Arguments: the str2time argument string
281             Returns: the correct timestamp (negative for pre-1969)
282              
283             =back
284              
285             =cut
286              
287             sub str3time ($) {
288              
289 10974     10974 1 14402 my $str = shift;
290              
291 10974         25874 my $time = str2time($str);
292 10974         1598533 my $year = substr($str, 0, 4);
293              
294 10974 100       24310 $time -= (31536000 + 3124224000) if $year < 1969;
295 10974         28503 $time;
296             }
297              
298             sub convert_new_schedule_game ($) {
299              
300 9446     9446 1 10938 my $schedule_game = shift;
301 9446         13281 my $game = {};
302 9446         25582 $game->{stage} = substr($schedule_game->{id},5,1)+0;
303 9446 100 100     21466 return undef if $game->{stage} ne $REGULAR && $game->{stage} ne $PLAYOFF;
304 9257         17220 $game->{season} = substr($schedule_game->{id},0,4)+0;
305 9257         15744 $game->{season_id} = $schedule_game->{id} % 10000+0;
306 9257         13384 $game->{_id} = (delete $schedule_game->{id})+0;
307             $game->{game_id} = sprintf(
308             "%04d%d%04d",$game->{season},$game->{stage},$game->{season_id}
309 9257         32998 )+0;
310 9257         17415 $game->{ts} = str3time(delete $schedule_game->{est})+0;
311 9257         273955 $game->{date} = strftime("%Y%m%d", localtime($game->{ts}))+0;
312 9257         32272 $game->{away} = resolve_team(delete $schedule_game->{a});
313 9257         23628 $game->{home} = resolve_team(delete $schedule_game->{h});
314 9257         24340 $game;
315             }
316              
317             sub arrange_new_schedule_by_date ($$) {
318              
319 4     4 1 31 my $schedule_by_date = shift;
320 4         7 my $schedule_json_data = shift;
321              
322              
323 4         10 for my $schedule_game (@{$schedule_json_data}) {
  4         14  
324 5392         8328 my $game = convert_new_schedule_game($schedule_game);
325 5392 100       8800 next unless $game;
326 5268   100     14788 $schedule_by_date->{$game->{date}} ||= [];
327 5268         5810 push(@{$schedule_by_date->{$game->{date}}}, $game);
  5268         11491  
328             }
329             }
330              
331             sub convert_old_schedule_game ($) {
332              
333 1671     1671 1 1933 my $schedule_game = shift;
334              
335 1671         3327 my $stage = substr($schedule_game->{gamePk},5,1);
336 1671 100 100     3410 return undef if $stage != $REGULAR && $stage != $PLAYOFF;
337             my $game = {
338             away => resolve_team($schedule_game->{teams}{away}{team}{name}),
339             home => resolve_team($schedule_game->{teams}{home}{team}{name}),
340             _id => $schedule_game->{gamePk} + 0,
341             stage => $stage + 0,
342             season => substr($schedule_game->{gamePk}, 0, 4) + 0,
343             season_id => $schedule_game->{gamePk} % 10000 + 0,
344             ts => str3time($schedule_game->{gameDate}),
345 1670         4793 year => substr($schedule_game->{gameDate}, 0, 4) + 0,
346             };
347             $game->{game_id} = sprintf(
348             "%04d%d%04d",$game->{season},$game->{stage},$game->{season_id}
349 1670         7856 )+0;
350 1670         50543 $game->{date} = strftime("%Y%m%d", localtime($game->{ts}))+0;
351 1670         4947 $game;
352             }
353              
354             sub arrange_old_schedule_by_date ($$) {
355              
356 5     5 1 11 my $schedule_by_date = shift;
357 5         13 my $schedule_json_data = shift;
358              
359 5         13 for my $schedule_date (@{$schedule_json_data->{dates}}) {
  5         17  
360 506         568 for my $schedule_game (@{$schedule_date->{games}}) {
  506         1241  
361 1435         2210 my $game = convert_old_schedule_game($schedule_game);
362 1435 100       2753 if ($game) {
363 1434   100     4691 $schedule_by_date->{$game->{date}} ||= [];
364 1434         1599 push(@{$schedule_by_date->{$game->{date}}}, $game);
  1434         3564  
365             }
366             }
367             }
368             }
369              
370             sub convert_schedule_game ($) {
371              
372 4290     4290 1 8702 my $game = shift;
373              
374             $game->{gamePk}
375 4290 100       9190 ? convert_old_schedule_game($game)
376             : convert_new_schedule_game($game);
377             }
378              
379             sub arrange_schedule_by_date ($$) {
380 9     9 1 141 my $schedule_by_date = shift;
381 9         14 my $schedule_json_data = shift;
382              
383 9 100       59 ref $schedule_json_data eq 'ARRAY' ?
384             arrange_new_schedule_by_date($schedule_by_date, $schedule_json_data) :
385             arrange_old_schedule_by_date($schedule_by_date, $schedule_json_data);
386             }
387              
388             sub get_games_for_dates_from_fs(@) {
389              
390 1     1 1 738 my @dates = @_;
391              
392 1         2 my %jsons = ();
393 1         2 my $schedule_by_date = {};
394 1         3 my @games = ();
395 1         2 for my $date (@dates) {
396 2         8 my $season = get_season_from_date($date);
397 2   33     17 my $schedule_file = sprintf("%s/%d/schedule.json", $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR, $season);
398 2 50       53 if (! -f $schedule_file) {
399 0         0 print STDERR
400             "[ERROR] No schedule crawl specified, and no schedule file $schedule_file present for $date\n";
401 0         0 next;
402             }
403 2 50       10 unless ($jsons{$season}) {
404 2         9 my $json = read_file($schedule_file);
405 2         4888 $jsons{$season} = decode_json($json);
406 2         12 arrange_schedule_by_date($schedule_by_date, $jsons{$season});
407             }
408 2 100       9 unless ($schedule_by_date->{$date}) {
409 1         50 print STDERR "No games scheduled for $date, skipping...\n";
410 1         6 next;
411             }
412 1         2 push(@games, @{$schedule_by_date->{$date}})
  1         6  
413             }
414 1         2805 @games;
415             }
416              
417             sub get_games_for_dates (@) {
418              
419 0     0 1 0 my @dates = @_;
420              
421             $ENV{MONGO_DB} ?
422 0 0       0 get_games_for_dates_from_db(@dates) :
423             get_games_for_dates_from_fs(@dates);
424             }
425              
426             sub get_start_stop_date ($) {
427              
428 3     3 1 6 my $season = shift;
429              
430             (
431 3         27 sprintf("%04d-%02d-%02d", $season+0, 9, 2),
432             sprintf("%04d-%02d-%02d", $season+1, 9, 1),
433             );
434             }
435              
436             sub make_game_path ($$$;$) {
437              
438 40     40 1 16858 my $season = shift;
439 40         92 my $stage = shift;
440 40         85 my $season_id = shift;
441 40   33     230 my $base_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
442              
443 40         270 my $path = sprintf("%s/%04d/%04d/%04d", $base_dir, $season, $stage, $season_id);
444 40 100 66     1563 return $path if -d $path && -w $path;
445 9 50       2862 make_path($path) or die "Couldn't create path $path\n";
446              
447 9         42 $path;
448             }
449              
450             sub read_schedules ($) {
451              
452 2     2 1 670 my $opts = shift;
453              
454 2   33     8 my $start_season = $opts->{start_season} || $FIRST_SEASON;
455 2   33     8 my $stop_season = $opts->{stop_season} || $CURRENT_SEASON;
456 2         4 my $schedules = {};
457              
458 2         10 for my $season ($start_season .. $stop_season) {
459 4         14 my $json_file = get_schedule_json_file($season);
460 4         23 debug "Using schedule from file $json_file";
461 4 50       84 next unless -f $json_file;
462 4         17 my $json = read_file($json_file);
463 4         5259 $schedules->{$season} = decode_json($json);
464             }
465 2         9 $schedules;
466             }
467              
468             sub get_game_id_from_path ($) {
469              
470 3     3 1 2936 my $path = shift;
471              
472 3         81 $path =~ m|^$ENV{HOCKEYDB_DATA_DIR}/(\d{4})/(\d{4})/(\d{4})|;
473 3 50 33     102 $1 && $2 && $3 ? $1*100000 + $2*10000 + $3 : undef;
474             }
475              
476             =over 2
477              
478             =item C
479              
480             Gets the expected SSSS/TTTT/NNNN path for our 9-digit game id.
481             Arguments: our 9-digit game id
482             Returns: the path (creates it if necessary)
483              
484             =back
485              
486             =cut
487              
488             sub get_game_path_from_id ($;$) {
489              
490 20     20 1 57 my $id = shift;
491 20   33     148 my $data_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
492              
493 20         102 my $game = parse_our_game_id($id);
494 20         108 make_game_path($game->{season}, $game->{stage}, $game->{season_id}, $data_dir);
495             }
496              
497             sub read_existing_game_ids ($) {
498              
499 4     4 1 1248 my $season = shift;
500              
501 4         9 my $game_ids = {};
502             find(
503             sub {
504 18 100 66 18   821 if ($_ eq $MAIN_GAME_FILE || $_ eq $SECONDARY_GAME_FILE) {
505 2         6 $game_ids->{get_game_id_from_path($File::Find::dir)} = 1;
506             }
507             },
508 4         360 "$ENV{HOCKEYDB_DATA_DIR}/$season",
509             );
510 4         30 $game_ids;
511             }
512              
513             =over 2
514              
515             =item C
516              
517             Gets existing game files for the given game Id. Assumes SSSS/TTTT/NNNN file tree structure under the root data directory.
518             Arguments:
519             * our 9-digit game id
520             * (optional) root data directory
521             Returns: The list of html/json reports from the game directory
522              
523             =back
524              
525             =cut
526              
527             sub get_game_files_by_id ($;$) {
528              
529 3     3 1 1583 my $game_id = shift;
530 3   33     40 my $data_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
531              
532 3         16 my $path = get_game_path_from_id($game_id, $data_dir);
533 3         30 debug "Using path $path";
534 3         85 opendir(DIR, $path);
535 13         39 my @game_files = map { "$path/$_" } grep {
536 3 100 100     101 -f "$path/$_" && (/html$/ || /json$/)
  30         421  
537             } readdir(DIR);
538 3         39 closedir(DIR);
539              
540 3         20 @game_files;
541             }
542              
543             =over 2
544              
545             =item C
546              
547             Normalizes one of the following event properties from different variants:
548             * penalty
549             * shot_type
550             * miss
551             * strength
552             * stoppage reason
553              
554             Arguments: the property name and the original string
555             Returns: the normalized, vocabulary-matched string
556              
557             =back
558              
559             =cut
560              
561             sub vocabulary_lookup ($$) {
562              
563 5204     5204 1 11699 my $vocabulary = shift;
564 5204         5751 my $string = shift;
565              
566 5204         6185 $string =~ tr/ / /;
567 5204         7909 $string =~ s/^\s+//;
568 5204         6704 $string =~ s/\s+$//;
569 5204         6058 $string = uc $string;
570 5204 100       12825 return $string if $VOCABULARY{$vocabulary}->{$string};
571 3140         3128 for my $word (keys %{$VOCABULARY{$vocabulary}}) {
  3140         6878  
572 14705         17149 my $alternatives = $VOCABULARY{$vocabulary}->{$word};
573 14705 100       24025 if (any {
574 11542     11542   20720 $string eq $_
575 14705         24458 } @{$alternatives}) {
576 3139         18377 return $word;
577             }
578             }
579 1         13 die "Unknown word $string for vocabulary $vocabulary";
580             }
581              
582             =over 2
583              
584             =item C
585              
586             Normalizes an NHL Report penalty string including a vocabulary lookup
587             Arguments: the original string
588             Returns: the normalized, vocabulary-matched string
589              
590             =back
591              
592             =cut
593              
594             sub normalize_penalty ($) {
595              
596 132     132 1 174 my $penalty = shift;
597              
598 132         176 $penalty =~ s/(\- double minor)//i;
599 132         150 $penalty =~ s/(\- obstruction)//i;
600 132         184 $penalty =~ s/(\-\s*bench\b)//i;
601 132         189 $penalty =~ s/(PS \- )//i;
602 132         197 vocabulary_lookup('penalty', $penalty);
603              
604             }
605              
606             =over 2
607              
608             =item C
609              
610             Prepares a hash with positions of each player id in the boxscore for future caching and resolving purposes.
611              
612             Arguments: the boxscore
613             Returns: the positions hash.
614              
615             =back
616              
617             =cut
618              
619             sub set_roster_positions ($) {
620              
621 5     5 1 90 my $boxscore = shift;
622 5         13 my $positions = {};
623              
624 5         15 for my $t (0,1) {
625 10         20 my $team = $boxscore->{teams}[$t];
626 10         15 for my $player (@{$team->{roster}}) {
  10         21  
627 165         368 $positions->{$player->{_id}} = $player->{position};
628             }
629             }
630 5         17 $positions;
631             }
632              
633             =over 2
634              
635             =item C
636              
637             A testing helper that sets the player stats the way they seem to appear in the event summary rather than in the boxscore, or finds a way to arbitrate the discrepancies.
638              
639             Arguments:
640             * The boxscore
641             * The NHL id of the player being fixed
642             * The stat to fix
643             * The value of the stat in the event summary
644             * The possible arbitration delta
645              
646             Returns: void. The boxscore is updated.
647              
648             =back
649              
650             =cut
651              
652             sub set_player_stat ($$$$;$) {
653              
654 0     0 1 0 my $boxscore = shift;
655 0         0 my $player_id = shift;
656 0         0 my $stat = shift;
657 0         0 my $value = shift;
658 0   0     0 my $delta = shift || 0;
659              
660 0         0 for my $t (0,1) {
661 0         0 for my $player (@{$boxscore->{teams}[$t]{roster}}) {
  0         0  
662 0 0       0 if ($player->{_id} == $player_id) {
663 0 0 0     0 if ($stat eq 'goalsAgainst' && defined $player->{saves}) {
    0          
    0          
664 0         0 $player->{saves} = $player->{shots} - $value;
665 0         0 debug "Setting $player->{_id} $stat to $value";
666 0         0 $player->{$stat} = $value;
667             }
668             elsif ($stat eq 'penaltyMinutes') {
669 0 0       0 if($delta) {
670 0         0 debug "Setting $player->{_id} $stat to $value+$delta";
671 0         0 $player->{$stat} = $delta;
672             }
673             }
674             elsif (defined $player->{$stat}) {
675 0         0 debug "Setting $player->{_id} $stat to $value";
676 0         0 $player->{$stat} = $value;
677             }
678 0         0 return;
679             }
680             }
681             }
682 0         0 die "Couldn't find $player_id / $stat\n";
683 0         0 1;
684             }
685              
686             =over 2
687              
688             =item C
689              
690             Fixes the number of goals and assists for players in the boxscore as shown by the summary.
691              
692             Arguments:
693             * The boxscore
694             * The index of the team of the player (0 - away, 1 - home)
695             * The event summary
696              
697             Returns: void. Boxscore is modified.
698              
699             =back
700              
701             =cut
702              
703             sub fix_playergoals ($$$) {
704              
705 0     0 1 0 my $boxscore = shift;
706 0         0 my $t = shift;
707 0         0 my $event_summary = shift;
708              
709 0         0 for my $player (@{$boxscore->{teams}[$t]{roster}}) {
  0         0  
710 0 0       0 if (my $es = $event_summary->{$player->{_id}}) {
711 0         0 $player->{goals} = $es->{goals};
712 0         0 $player->{assists} = $es->{assists};
713             }
714             }
715             }
716              
717             =over 2
718              
719             =item C
720              
721             Check if the event is not a played one (PEND, GEND, PSTR, STOP)
722              
723             =back
724              
725             =cut
726              
727             sub is_noplay_event ($) {
728 7191     7191 1 7387124 my $event = shift;
729              
730             $event->{type} eq 'PEND' || $event->{type} eq 'PSTR'
731 7191 100 100     50867 || $event->{type} eq 'GEND' || $event->{type} eq 'STOP';
      100        
732             }
733              
734              
735              
736             =over 2
737              
738             =item C
739              
740             Prints the list of parsed events in a compact for. Work in progress. Do not use.
741              
742             =back
743              
744             =cut
745              
746             sub print_events ($) {
747              
748 0     0 1   my $events = shift;
749              
750 0           for (@{$events}) {
  0            
751 0           print "$_->{period}\t$_->{t}\t$_->{ts}\t$_->{type}\n";
752             }
753             }
754              
755             1;
756              
757             =head1 AUTHOR
758              
759             More Hockey Stats, C<< >>
760              
761             =head1 BUGS
762              
763             Please report any bugs or feature requests to C, or through
764             the web interface at L. I will be notified, and then you'll
765             automatically be notified of progress on your bug as I make changes.
766              
767              
768             =head1 SUPPORT
769              
770             You can find documentation for this module with the perldoc command.
771              
772             perldoc Sport::Analytics::NHL::Tools
773              
774             You can also look for information at:
775              
776             =over 4
777              
778             =item * RT: CPAN's request tracker (report bugs here)
779              
780             L
781              
782             =item * AnnoCPAN: Annotated CPAN documentation
783              
784             L
785              
786             =item * CPAN Ratings
787              
788             L
789              
790             =item * Search CPAN
791              
792             L
793              
794             =back