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   246349 use v5.10.1;
  53         204  
4 53     53   236 use strict;
  53         101  
  53         1159  
5 53     53   248 use warnings FATAL => 'all';
  53         131  
  53         1640  
6              
7 53     53   316 use File::Find;
  53         98  
  53         3497  
8 53     53   323 use File::Path qw(make_path);
  53         105  
  53         2859  
9 53     53   14990 use POSIX qw(strftime);
  53         181601  
  53         347  
10              
11 53     53   62390 use Date::Parse;
  53         271657  
  53         5526  
12 53     53   12871 use JSON;
  53         214852  
  53         335  
13 53     53   13038 use List::MoreUtils qw(any);
  53         163127  
  53         481  
14              
15 53     53   39771 use Sport::Analytics::NHL::LocalConfig;
  53         122  
  53         6252  
16 53     53   347 use Sport::Analytics::NHL::Config;
  53         335  
  53         8423  
17 53     53   19701 use Sport::Analytics::NHL::DB;
  53         139  
  53         1720  
18 53     53   414 use Sport::Analytics::NHL::Util;
  53         103  
  53         2962  
19              
20 53     53   317 use parent 'Exporter';
  53         88  
  53         249  
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 797 my $nhl_id = shift;
197              
198 10         63 $nhl_id =~ /^(\d{4})(\d{2})(\d{4})$/;
199             {
200 10         123 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 83 my $our_id = shift;
210              
211 26         216 $our_id =~ /^(\d{4})(\d{1})(\d{4})/;
212             {
213 26         434 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 23 my $date = shift;
223              
224 8         48 $date =~ /^(\d{4})(\d{2})(\d{2})/;
225 8 100       75 $2 > 8 ? $1 : $1 - 1;
226             }
227              
228             sub get_schedule_json_file ($;$) {
229              
230 18     18 1 4536 my $season = shift;
231 18   66     130 my $data_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
232              
233 18         126 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 45159 my $team = shift;
257 29236   100     70726 my $force_no_db = shift || 0;
258              
259 29236 50 66     77952 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     77380 return 'MTL' if ($team =~ /MONTR.*CAN/i || $team =~ /CAN.*MONTR/);
265 28889 100 66     68984 return 'NHL' if ($team eq 'League' || $team eq 'NHL');
266 28888         143219 for my $team_id (keys %TEAMS) {
267 619059 100       964532 return $team_id if $team_id eq $team;
268 594144         702467 for my $type (qw(short long full)) {
269 1780526 100       1879669 return $team_id if grep { uc($_) eq uc($team) } @{$TEAMS{$team_id}->{$type}};
  2621112         4547012  
  1780526         2613761  
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 18052 my $str = shift;
290              
291 10974         25662 my $time = str2time($str);
292 10974         1717943 my $year = substr($str, 0, 4);
293              
294 10974 100       26529 $time -= (31536000 + 3124224000) if $year < 1969;
295 10974         33340 $time;
296             }
297              
298             sub convert_new_schedule_game ($) {
299              
300 9446     9446 1 11845 my $schedule_game = shift;
301 9446         13576 my $game = {};
302 9446         29405 $game->{stage} = substr($schedule_game->{id},5,1)+0;
303 9446 100 100     22674 return undef if $game->{stage} ne $REGULAR && $game->{stage} ne $PLAYOFF;
304 9257         17630 $game->{season} = substr($schedule_game->{id},0,4)+0;
305 9257         15763 $game->{season_id} = $schedule_game->{id} % 10000+0;
306 9257         14959 $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         34462 )+0;
310 9257         19085 $game->{ts} = str3time(delete $schedule_game->{est})+0;
311 9257         296592 $game->{date} = strftime("%Y%m%d", localtime($game->{ts}))+0;
312 9257         35222 $game->{away} = resolve_team(delete $schedule_game->{a});
313 9257         25199 $game->{home} = resolve_team(delete $schedule_game->{h});
314 9257         23951 $game;
315             }
316              
317             sub arrange_new_schedule_by_date ($$) {
318              
319 4     4 1 35 my $schedule_by_date = shift;
320 4         11 my $schedule_json_data = shift;
321              
322              
323 4         11 for my $schedule_game (@{$schedule_json_data}) {
  4         15  
324 5392         9480 my $game = convert_new_schedule_game($schedule_game);
325 5392 100       10560 next unless $game;
326 5268   100     17959 $schedule_by_date->{$game->{date}} ||= [];
327 5268         6688 push(@{$schedule_by_date->{$game->{date}}}, $game);
  5268         13860  
328             }
329             }
330              
331             sub convert_old_schedule_game ($) {
332              
333 1671     1671 1 2306 my $schedule_game = shift;
334              
335 1671         4577 my $stage = substr($schedule_game->{gamePk},5,1);
336 1671 100 100     3720 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         8531 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         9259 )+0;
350 1670         58664 $game->{date} = strftime("%Y%m%d", localtime($game->{ts}))+0;
351 1670         5320 $game;
352             }
353              
354             sub arrange_old_schedule_by_date ($$) {
355              
356 5     5 1 13 my $schedule_by_date = shift;
357 5         15 my $schedule_json_data = shift;
358              
359 5         13 for my $schedule_date (@{$schedule_json_data->{dates}}) {
  5         22  
360 506         686 for my $schedule_game (@{$schedule_date->{games}}) {
  506         2539  
361 1435         2474 my $game = convert_old_schedule_game($schedule_game);
362 1435 100       3144 if ($game) {
363 1434   100     6792 $schedule_by_date->{$game->{date}} ||= [];
364 1434         1971 push(@{$schedule_by_date->{$game->{date}}}, $game);
  1434         4369  
365             }
366             }
367             }
368             }
369              
370             sub convert_schedule_game ($) {
371              
372 4290     4290 1 8946 my $game = shift;
373              
374             $game->{gamePk}
375 4290 100       10088 ? convert_old_schedule_game($game)
376             : convert_new_schedule_game($game);
377             }
378              
379             sub arrange_schedule_by_date ($$) {
380 9     9 1 150 my $schedule_by_date = shift;
381 9         18 my $schedule_json_data = shift;
382              
383 9 100       74 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 834 my @dates = @_;
391              
392 1         2 my %jsons = ();
393 1         2 my $schedule_by_date = {};
394 1         2 my @games = ();
395 1         4 for my $date (@dates) {
396 2         9 my $season = get_season_from_date($date);
397 2   33     21 my $schedule_file = sprintf("%s/%d/schedule.json", $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR, $season);
398 2 50       64 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       12 unless ($jsons{$season}) {
404 2         11 my $json = read_file($schedule_file);
405 2         5933 $jsons{$season} = decode_json($json);
406 2         11 arrange_schedule_by_date($schedule_by_date, $jsons{$season});
407             }
408 2 100       9 unless ($schedule_by_date->{$date}) {
409 1         66 print STDERR "No games scheduled for $date, skipping...\n";
410 1         6 next;
411             }
412 1         4 push(@games, @{$schedule_by_date->{$date}})
  1         10  
413             }
414 1         3635 @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 8 my $season = shift;
429              
430             (
431 3         28 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 29473 my $season = shift;
439 40         116 my $stage = shift;
440 40         109 my $season_id = shift;
441 40   33     287 my $base_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
442              
443 40         306 my $path = sprintf("%s/%04d/%04d/%04d", $base_dir, $season, $stage, $season_id);
444 40 100 66     1865 return $path if -d $path && -w $path;
445 9 50       4044 make_path($path) or die "Couldn't create path $path\n";
446              
447 9         73 $path;
448             }
449              
450             sub read_schedules ($) {
451              
452 2     2 1 882 my $opts = shift;
453              
454 2   33     23 my $start_season = $opts->{start_season} || $FIRST_SEASON;
455 2   33     9 my $stop_season = $opts->{stop_season} || $CURRENT_SEASON;
456 2         4 my $schedules = {};
457              
458 2         13 for my $season ($start_season .. $stop_season) {
459 4         22 my $json_file = get_schedule_json_file($season);
460 4         23 debug "Using schedule from file $json_file";
461 4 50       109 next unless -f $json_file;
462 4         20 my $json = read_file($json_file);
463 4         6445 $schedules->{$season} = decode_json($json);
464             }
465 2         13 $schedules;
466             }
467              
468             sub get_game_id_from_path ($) {
469              
470 3     3 1 4028 my $path = shift;
471              
472 3         97 $path =~ m|^$ENV{HOCKEYDB_DATA_DIR}/(\d{4})/(\d{4})/(\d{4})|;
473 3 50 33     127 $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 99 my $id = shift;
491 20   33     175 my $data_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
492              
493 20         116 my $game = parse_our_game_id($id);
494 20         123 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 1450 my $season = shift;
500              
501 4         11 my $game_ids = {};
502             find(
503             sub {
504 18 100 66 18   861 if ($_ eq $MAIN_GAME_FILE || $_ eq $SECONDARY_GAME_FILE) {
505 2         7 $game_ids->{get_game_id_from_path($File::Find::dir)} = 1;
506             }
507             },
508 4         402 "$ENV{HOCKEYDB_DATA_DIR}/$season",
509             );
510 4         39 $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 1887 my $game_id = shift;
530 3   33     44 my $data_dir = shift || $ENV{HOCKEYDB_DATA_DIR} || $DATA_DIR;
531              
532 3         22 my $path = get_game_path_from_id($game_id, $data_dir);
533 3         32 debug "Using path $path";
534 3         110 opendir(DIR, $path);
535 13         40 my @game_files = map { "$path/$_" } grep {
536 3 100 100     126 -f "$path/$_" && (/html$/ || /json$/)
  30         475  
537             } readdir(DIR);
538 3         41 closedir(DIR);
539              
540 3         23 @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 13491 my $vocabulary = shift;
564 5204         6726 my $string = shift;
565              
566 5204         6781 $string =~ tr/ / /;
567 5204         8873 $string =~ s/^\s+//;
568 5204         7590 $string =~ s/\s+$//;
569 5204         6933 $string = uc $string;
570 5204 100       14589 return $string if $VOCABULARY{$vocabulary}->{$string};
571 3140         3653 for my $word (keys %{$VOCABULARY{$vocabulary}}) {
  3140         8278  
572 14010         18040 my $alternatives = $VOCABULARY{$vocabulary}->{$word};
573 14010 100       25920 if (any {
574 11500     11500   23832 $string eq $_
575 14010         25535 } @{$alternatives}) {
576 3139         22604 return $word;
577             }
578             }
579 1         16 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 197 my $penalty = shift;
597              
598 132         190 $penalty =~ s/(\- double minor)//i;
599 132         166 $penalty =~ s/(\- obstruction)//i;
600 132         200 $penalty =~ s/(\-\s*bench\b)//i;
601 132         190 $penalty =~ s/(PS \- )//i;
602 132         240 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 106 my $boxscore = shift;
622 5         16 my $positions = {};
623              
624 5         30 for my $t (0,1) {
625 10         26 my $team = $boxscore->{teams}[$t];
626 10         25 for my $player (@{$team->{roster}}) {
  10         28  
627 165         473 $positions->{$player->{_id}} = $player->{position};
628             }
629             }
630 5         20 $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 7368151 my $event = shift;
729              
730             $event->{type} eq 'PEND' || $event->{type} eq 'PSTR'
731 7191 100 100     56702 || $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