File Coverage

blib/lib/Sport/Analytics/NHL/Report/BH.pm
Criterion Covered Total %
statement 317 412 76.9
branch 100 172 58.1
condition 34 80 42.5
subroutine 27 29 93.1
pod 19 19 100.0
total 497 712 69.8


line stmt bran cond sub pod time code
1             package Sport::Analytics::NHL::Report::BH;
2              
3 19     19   68404 use v5.10.1;
  19         66  
4 19     19   81 use strict;
  19         31  
  19         461  
5 19     19   72 use warnings FATAL => 'all';
  19         27  
  19         590  
6 19     19   93 use experimental qw(smartmatch);
  19         30  
  19         90  
7              
8 19     19   1145 use parent 'Sport::Analytics::NHL::Report';
  19         285  
  19         78  
9              
10 19     19   914 use Carp;
  19         30  
  19         918  
11              
12 19     19   92 use Sport::Analytics::NHL::Config;
  19         38  
  19         3043  
13 19     19   112 use Sport::Analytics::NHL::Errors;
  19         30  
  19         2694  
14 19     19   105 use Sport::Analytics::NHL::Util;
  19         28  
  19         1049  
15              
16             =head1 NAME
17              
18             Sport::Analytics::NHL::Report::BH - Class for the old Boxscore HTML report.
19             NOT IN USE - NOT IN USE.
20              
21             =head1 SYNOPSYS
22              
23             Class for the old Boxscore HTML report. At the moment it's not used, thus it's not documented.
24             Hack at your own risk.
25              
26             =head1 METHODS
27              
28             =over 2
29              
30             =item C
31              
32             =item C
33              
34             =item C
35              
36             =item C
37              
38             =item C
39              
40             =item C
41              
42             =item C
43              
44             =item C
45              
46             =item C
47              
48             =item C
49              
50             =item C
51              
52             =item C
53              
54             =item C
55              
56             =item C
57              
58             =item C
59              
60             =item C
61              
62             =item C
63              
64             =item C
65              
66             =item C
67              
68             =back
69              
70             =cut
71              
72 19     19   104 use Data::Dumper;
  19         30  
  19         71164  
73              
74             our $LAST_PERIOD = 979;
75              
76             our $BOXSCORE_HEADER = 1;
77             our $BOXSCORE_GAME = 2;
78              
79             my %NORMAL_FIELDS = (
80             S => {
81             A => 'assists', BkS => 'blocked', 'PP TOI' => 'powerPlayTimeOnIce', MS => 'misses',
82             'SH TOI' => 'shortHandedTimeOnIce', 'EV TOI' => 'evenTimeOnIce',
83             Hits => 'hits', G => 'goals', GvA => 'giveaways', TkA => 'takeaways',
84             PIM => 'penaltyMinutes', S => 'shots', 'FO%' => 'faceOffPercentage', P => 'points',
85             'No.' => 'number', 'Pos' => 'position', Player => '_id',
86             Pos => 'position', TOI => 'timeOnIce', '+/-' => 'plusMinus',
87             },
88             G => {
89             PIM => 'pim', Player => '_id', G => 'goals', S => 'saves', TOI => 'timeOnIce',
90             'No.' => 'number', 'wl' => 'decision',
91             },
92             );
93              
94             my %LIVE_FIELDS = (
95             S => [qw(shortHandedGoals shortHandedAssists powerPlayGoals powerPlayAssists evenStrengthGoals evenStrengthAssists faceoffTaken faceOffWins)],
96             G => [qw(pim goals assists)]
97             );
98              
99             sub extract_id_from_href ($) {
100              
101 140     140 1 164 my $elem = shift;
102              
103 140         274 $elem->attr('href') =~ /id=(\d+)/;
104 140         1657 my $id = $1;
105 140 50       442 $BROKEN_PLAYER_IDS{$id} || $id;
106             }
107              
108             sub extract_name_from_href ($) {
109              
110 76     76 1 106 my $elem = shift;
111              
112 76         142 $elem->{_content}[0];
113             }
114              
115             sub read_header ($$) {
116              
117 2     2 1 4 my $self = shift;
118 2         4 my $main_div = shift;
119              
120 2         8 $self->{periods} = [ {}, {}, {} ];
121 2         4 $self->{teams} = [];
122 2         162 $self->{status} = 'FINAL';
123 2         6 $self->{type} = 'BH';
124             $self->{source} =~
125 2         176 m|title\>([A-Z].*)\s+at\s+([A-Z].*) - (\d{2}/\d{2}/\d{4}).*title|;
126 2         58 $self->{full_teams} = [ $1, $2 ];
127 2         11 $self->{date} = $3;
128 2         4 $self->{time} = '';
129 2         39 $self->{source} =~ m|gcGameId\D*(\d+)|;
130 2         5 $self->{_id} = $1;
131 2         14 $self->{stage} = int($self->{_id} / 10000) % 10;
132 2         6 $self->{season} = int($self->{_id} / 1000000);
133 2         7 substr($self->{_id}, 4, 1) = '';
134 2         13 $self->{season_id} = sprintf("%04d", $self->{_id} % 10000);
135 2         20 $self->convert_time_date(1);
136 2         17 $self->{source} =~ /game_string:.*\"(\S{3})\s*\@\s*(\S{3})\"/;
137 2         7 $self->{teams}[0]{name} = $1;
138 2         5 $self->{teams}[1]{name} = $2;
139 2         9 my $a_score = $self->get_sub_tree(0, [2,0,2,0,0,0], $main_div);
140 2         6 $self->{teams}[0]{score} = $a_score;
141 2         7 my $h_score = $self->get_sub_tree(0, [2,0,2,0,2,0], $main_div);
142 2         5 $self->{teams}[1]{score} = $h_score;
143 2         4 $self->{old} = 1;
144 2         6 $LAST_PERIOD = 3;
145             }
146              
147             sub read_boxscore_scoring_event ($$$$) {
148              
149 6     6 1 8 my $self = shift;
150 6         8 my $row = shift;
151 6         8 my $cell = shift;
152 6         10 my $period = shift;
153              
154             my $event = {
155             type => 'GOAL',
156             strength => 'EV',
157 6         20 time => $cell->{_content}[0],
158             team1 => $self->get_sub_tree(0, [1,0], $row),
159             period => $period,
160             en => 0,
161             };
162 6         16 my $score = $self->get_sub_tree(0, [2,0], $row);
163 6 50       11 return undef unless $score;
164 6         8 my $offset = 0;
165 6 50 66     21 $event->{empty_net} = 1 if ! ref $score && $score =~ /\bEN\b/;
166            
167 6 100       11 if (! ref $score) {
168 2         8 $event->{player1} = extract_id_from_href(
169             $self->get_sub_tree(0, [2,1], $row)
170             );
171 2         4 $offset = 1;
172 2 50       14 if ($score =~ /(\w\w)G/) {
173 2         6 $event->{strength} = $1;
174             }
175 2 50       10 if ($score =~ /EN/) {
    50          
176 0         0 $event->{en} = 1;
177             }
178             elsif ($score =~ /PS/) {
179 0         0 $event->{str} = 'PS';
180 0         0 $event->{penaltyshot} = 1;
181 0         0 $event->{location} = 'OFF';
182 0         0 $event->{shot_type} = 'UNKNOWN';
183 0         0 $event->{distance} = 999;
184 0         0 return $event;
185             }
186             }
187             else {
188 4         9 $event->{player1} = extract_id_from_href($score);
189             }
190 6         17 my $asst = $self->get_sub_tree(0, [2,1+$offset], $row);
191 6         11 my $asst1; my $asst2;
192 6         12 $event->{assists} = [];
193 6 50       16 if ($asst =~ /ASST/) {
194 6         15 $asst1 = $self->get_sub_tree(0, [2,2+$offset], $row);
195 6 50       13 if ($asst1) {
196 6         8 $event->{assist1} = extract_id_from_href($asst1);
197 6         8 push(@{$event->{assists}}, $event->{assist1});
  6         14  
198 6         14 $asst2 = $self->get_sub_tree(0, [2,4+$offset], $row);
199 6 50       15 $event->{assist2} = extract_id_from_href($asst2) if $asst2;
200 6 50       13 push(@{$event->{assists}}, $event->{assist2}) if $asst2;
  6         10  
201             }
202             }
203 6         10 $event->{location} = 'UNK';
204 6         8 $event->{shot_type} = 'UNKNOWN';
205 6         7 $event->{distance} = 999;
206 6         11 $event;
207             }
208              
209             sub read_boxscore_penalty_event ($$$$) {
210              
211 24     24 1 28 my $self = shift;
212 24         28 my $row = shift;
213 24         25 my $cell = shift;
214 24         26 my $period = shift;
215              
216             my $event = {
217             type => 'PENL',
218             str => 'XX',
219 24         69 time => $cell->{_content}[0],
220             team1 => $self->get_sub_tree(0, [1,0], $row),
221             period => $period,
222             };
223 24 50       51 return () if $event->{time} eq 'NONE';
224 24         51 my $offender = $self->get_sub_tree(0, [2,0], $row);
225 24 50       41 if (ref $offender) {
226 24         32 $event->{player1} = extract_id_from_href($offender);
227 24         53 $event->{penalty} = $self->get_sub_tree(0, [2,1], $row);
228             }
229             else {
230 0         0 $event->{penalty} = $offender;
231 0         0 $event->{player1} = $BENCH_PLAYER_ID;
232 0         0 $event->{length} = 2;
233             }
234 24 100       78 my $against = $event->{penalty} =~ /\bagainst\b/ ? 1 : 0;
235 24 50       67 if ($event->{penalty} =~ /(.*\S)\s*\(maj\)/) {
    50          
    50          
236 0         0 $event->{length} = 5;
237 0         0 $event->{penalty} = $1;
238             }
239             elsif ($event->{penalty} =~ /(.*\S)\s*\(10.*min\)/) {
240 0         0 $event->{length} = 10;
241 0         0 $event->{penalty} = $1;
242             }
243             elsif ($event->{penalty} =~ /double minor/i) {
244 0         0 $event->{length} = 4;
245             }
246             else {
247 24         53 $event->{length} = 2;
248             }
249 24 100       39 if ($against) {
250 22         43 $event->{player2} = extract_id_from_href($self->get_sub_tree(0, [2,2], $row));
251 22         40 $event->{team2} = 'OTH';
252             }
253 24 50       54 $event->{misconduct} = 1 if $event->{penalty} =~ /conduct/i;
254             $event->{length} = 10 if
255             $event->{penalty} =~ /misconduct/i ||
256             $event->{penalty} =~ /Match/ ||
257             $event->{penalty} =~ /abuse.*official/i && $self->{season} > 1997 ||
258 24 50 33     133 $event->{penalty} =~ /leaving .* bench/i;
      33        
      33        
      33        
259 24 50       45 $event->{length} = 0 if $event->{penalty} =~ /penalty shot/i;
260 24 100 33     85 if (
      66        
261             $event->{penalty} =~ /too many/i ||
262             $event->{penalty} =~ /\bbench\b/i && $event->{length} != 10
263             ) {
264 2 50 33     13 if ($event->{player1} && $event->{player1} =~ /^8\d{6}/) {
265 2         4 $event->{servedby} = $event->{player1};
266             }
267 2 50       9 $event->{player1} = $event->{penalty} =~ /coach/ ? $COACH_PLAYER_ID : $BENCH_PLAYER_ID;
268             }
269 24         68 $event->{penalty} =~ s/\s+against\s+//i;
270 24 100 66     69 if ($event->{penalty} =~ /\bbench\b/i && $event->{penalty} !~ /leaving/i) {
271 2 0 33     5 if (! $event->{servedby} && $event->{player1} && $event->{player1} != $BENCH_PLAYER_ID) {
      0        
272 0         0 $event->{servedby} = $event->{player1};
273             }
274 2         5 $event->{player1} = $BENCH_PLAYER_ID;
275 2         9 $event->{penalty} =~ s/\s*\-\s+bench//i;
276             }
277 24 50       75 if ($event->{penalty} =~ /(.*\w)\W*\bcoach\b/i) {
278 0         0 $event->{player1} = $COACH_PLAYER_ID;
279 0         0 $event->{penalty} = $1;
280             }
281 24 50       38 if ($event->{penalty} =~ /aggressor/i) {
282 0         0 $event->{length} = 10;
283             }
284 24         31 $event->{penalty} =~ s/\s*\-\s+obstruction//i;
285 24         29 $event->{penalty} =~ s/(game)-(\S)/"$1 - $2"/ie;
  0         0  
286 24         39 $event->{penalty} =~ s/\s*against\s*//i;
287 24         36 $event->{location} = 'UNK';
288 24         33 $event;
289             }
290              
291             sub read_boxscore_shootout_event ($$$$) {
292              
293 0     0 1 0 my $self = shift;
294 0         0 my $row = shift;
295 0         0 my $cell = shift;
296 0         0 my $period = shift;
297              
298 0         0 my $events;
299 0         0 for my $t (1,3) {
300 0         0 my $href = $self->get_sub_tree(0, [$t, 0], $row);
301 0 0       0 next unless $href;
302 0         0 my $event = {
303             penaltyshot => 1,
304             period => 5,
305             time => '00:00',
306             str => 'EV',
307             shot_type => 'UNKNOWN',
308             location => 'OFF',
309             distance => 999,
310             so => 1,
311             };
312 0 0       0 if ($href->attr('class') =~ /shootoutgoal/i) {
313 0         0 $event->{type} = 'GOAL';
314             }
315             else {
316 0         0 $event->{type} = 'MISS';
317 0         0 $event->{miss} = 'Unknown';
318             }
319 0         0 $event->{player1} = extract_id_from_href($href);
320 0         0 $event->{team1} = $self->{teams}[$self->{so_teams}[($t-1)/2]]{name};
321 0         0 push(@{$events}, $event);
  0         0  
322             }
323 0         0 $events;
324             }
325              
326             sub parse_event_summary ($$$$;$) {
327              
328 4     4 1 7 my $self = shift;
329 4         5 my $summary = shift;
330 4         6 my $type = shift;
331 4         4 my $events = shift;
332              
333 4         6 my $r = 0;
334 4         5 my $period = 0;
335 4         6 my $shootout_mode = 0;
336 4         8 while (my $row = $self->get_sub_tree(0, [$r], $summary)) {
337 42 50       59 unless (ref $row) {
338 0         0 $r++;
339 0         0 next;
340             }
341 42         56 my $cell = $row->{_content}[0];
342 42 100       77 if ($cell->tag eq 'th') {
    50          
343 12 50       67 unless ($shootout_mode) {
344 12         17 $period = $cell->{_content}[0];
345 12 50 33     35 $period += 3 if $cell->{_content}[2] && $cell->{_content}[2] =~ /OT period/i;
346 12 50       21 if ($period eq 'OT Period') {
347 0         0 $period = 4;
348             }
349 12 50       21 if ($period eq 'Shootout') {
350 0         0 $period = 5;
351 0         0 $shootout_mode = 1;
352             }
353 12 50       23 $LAST_PERIOD = $period if $period > $LAST_PERIOD;
354             }
355             else {
356             $self->{so_teams} = [ map {
357 0 0       0 $self->{full_teams}[0] eq $_ ? 0 : 1,
358 0         0 } ( $row->{_content}[1]{_content}[0], $row->{_content}[2]{_content}[0]) ];
359             }
360 12         12 $r++;
361 12         34 next;
362             }
363             elsif ($cell->tag eq 'td') {
364 30         281 my $method = "read_boxscore_${type}_event";
365 30         56 my $event = $self->$method($row, $cell, $period);
366 30 50       49 push(@{$events}, ref $event eq 'ARRAY' ? @{$event} : $event) if $event;
  30 50       69  
  0         0  
367             }
368             else {
369 0         0 print "strange cell ", $cell->tag, "\n";
370 0         0 exit;
371             }
372 30         80 $r++;
373             }
374             }
375              
376             sub parse_lineup_row ($$$) {
377              
378 84     84 1 99 my $self = shift;
379 84         111 my $row = shift;
380 84         88 my $headers = shift;
381              
382 84         116 my $player = {};
383 84         104 my $c = 0;
384 84         180 while (my $cell = $self->get_sub_tree(0, [$c], $row)) {
385 1364 50       1947 confess "no ref in lineup cell" unless ref $cell;
386 1364 100       2180 if ($cell->tag eq 'th') {
387 104         525 push(@{$headers}, $cell->{_content}[0]);
  104         189  
388 104         133 $c++;
389 104         251 next;
390             }
391 1260         6866 my $content;
392 1260 100       2068 if (ref $cell->{_content}[0]) {
393 76         112 my $c2 = $cell->{_content}[0];
394             $content = extract_id_from_href(
395 76 100       190 ref $c2->{_content}[0] ? $c2->{_content}[0] : $c2,
396             );
397             $player->{name} = extract_name_from_href(
398 76 100       177 ref $c2->{_content}[0] ? $c2->{_content}[0] : $c2,
399             );
400 76 50       165 if (ref $c2) {
401 76         137 $player->{wl} = $cell->{_content}[1];
402             }
403             }
404             else {
405 1184         1495 $content = $cell->{_content}[0];
406             }
407 1260         2377 $player->{$headers->[$c]} = $content;
408 1260         3003 $c++;
409             }
410 84         170 $player;
411             }
412              
413             sub parse_lineup_summary ($$$) {
414              
415 8     8 1 11 my $self = shift;
416 8         14 my $summary = shift;
417              
418 8         11 my $r = 0;
419 8         15 my @headers = ();
420 8         12 my @players = ();
421 8         19 while (my $row = $self->get_sub_tree(0, [$r], $summary)) {
422 84         154 my $player = $self->parse_lineup_row($row, \@headers);
423 84         110 $r++;
424 84 100       87 next unless keys %{$player};
  84         218  
425 76   100     199 $player->{position} = $player->{Pos} || 'G';
426 76 100       141 my $pos = $player->{position} eq 'G' ? 'G' : 'S';
427 76 100       118 if ($pos eq 'G') {
428 4         9 for my $stat (qw(EV SH PP), 'Saves - Shots') {
429 16         55 $player->{$stat} =~ /^(\d+)\s+\-\s+(\d+)$/;
430 16 100       63 if ($stat eq 'EV') {
    100          
    100          
431 4         15 $player->{evenSaves} = $1;
432 4         13 $player->{evenShotsAgainst} = $2;
433             }
434             elsif ($stat eq 'SH') {
435 4         11 $player->{powerPlaySaves} = $1;
436 4         19 $player->{powerPlayShotsAgainst} = $2;
437             }
438             elsif ($stat eq 'PP') {
439 4         10 $player->{shortHandedSaves} = $1;
440 4         9 $player->{shortHandedShotsAgainst} = $2;
441             }
442             else {
443 4         14 $player->{saves} = $1;
444 4         11 $player->{shots} = $2;
445             }
446             }
447             }
448 76         83 for my $key (keys %{$NORMAL_FIELDS{$pos}}) {
  76         336  
449             $player->{$NORMAL_FIELDS{$pos}->{$key}} = delete $player->{$key}
450 1396 100       2863 if exists $player->{$key};
451             }
452 76         134 for my $field (@{$LIVE_FIELDS{$pos}}) {
  76         136  
453 588   50     1288 $player->{$field} ||= -1;
454             }
455 76 100       150 $player->{decision} =~ s/\W//g if $player->{decision};
456 76   50     252 $player->{evenTimeOnIce} ||= '00:00';
457 76   50     237 $player->{status} ||= 'X';
458 76 50       160 $player->{start} = 2 unless defined $player->{start};
459 76         267 push(@players, $player);
460             }
461 8         39 @players;
462             }
463              
464             sub parse_event_summaries ($$) {
465              
466 2     2 1 5 my $self = shift;
467 2         4 my $summaries = shift;
468              
469 2 50       9 my $e = $self->get_sub_tree(0, [0,1,0,2,0,0], $summaries) ? 0 : 2;
470 2         5 my $events = [];
471              
472 2         5 for my $summary_type (qw(scoring penalty)) {
473 4         24 my $summary = $self->get_sub_tree(0, [0,1,$e,2,0,0], $summaries);
474 4         32 $self->parse_event_summary($summary, $summary_type, $events);
475 4 100       11 if ($summary_type eq 'scoring') {
476 2         7 my $shootout = $self->get_sub_tree(0, [0,1,$e,2,1,0], $summaries);
477 2 50       7 if ($shootout) {
478 0         0 $self->{so} = 1;
479 0   0     0 $self->{periods}[4] ||= {};
480 0         0 $self->parse_event_summary($shootout, 'shootout', $events);
481             }
482             }
483 4         7 $e++;
484             }
485 2         5 $self->{events} = $events;
486             }
487              
488             sub parse_lineup_summaries ($$) {
489              
490 2     2 1 5 my $self = shift;
491 2         3 my $summaries = shift;
492              
493 2 50       18 my $e = $self->get_sub_tree(0, [0,1,2,2,0,0], $summaries) ? 2 : 0;
494 2         16 my $x = $self->get_sub_tree(0, [0,1,2,2,0,0], $summaries);
495 2 50 33     15 if ($e == 2 && $x->tag eq 'tbody') {
496 0         0 $e += 2;
497             }
498 2         18 my $s = 1; my $t = 1;
  2         4  
499 2         6 for my $team (qw(away home)) {
500 4         20 for my $roster (qw(skaters goalie)) {
501 8         31 my $summary = $self->get_sub_tree(0, [0,1,$e,2,2*$s-$t,0], $summaries);
502 8         29 my @players = $self->parse_lineup_summary($summary);
503 8   100     61 $self->{teams}[1-$t]{roster} ||= [];
504 8         12 push(@{$self->{teams}[1-$t]{roster}}, @players);
  8         40  
505 8         17 $s++;
506             }
507 4         9 $t--;
508             }
509             }
510              
511             sub parse_officials_box ($$) {
512              
513 4     4 1 6 my $self = shift;
514 4         5 my $ei_box = shift;
515              
516 4         16 my $officials_box = $self->get_sub_tree(0, [2,0], $ei_box);
517              
518 4         11 my $referees = $self->get_sub_tree(0, [1,0], $officials_box);
519 4         8 my $officials = {};
520 4 100 66     16 if ($referees && !ref $referees) {
521 2 50       38 if ($referees =~ /:\s+(\S+.*\S+)\s*\,\s+(\S+.*\S+)\s*$/) {
522             $officials->{referees} = [
523 2         15 { name => $1, number => 0 }, { name => $2, number => 0 },
524             ];
525             }
526             else {
527 0         0 $referees =~ /:\s+(\S+.*\S+)/;
528             $officials->{referees} = [
529 0         0 { name => $1, number => 0 }
530             ];
531             }
532 2         18 my $linesmen = $self->get_sub_tree(0, [2,0], $officials_box);
533 2 50       6 return {} unless $linesmen;
534 2 50       28 if ($linesmen =~ /:\s+(\S+.*\S+)\s*\,\s+(\S+.*\S+)\s*$/) {
535             $officials->{linesmen} = [
536 2         14 { name => $1, number => 0 }, { name => $2, number => 0 },
537             ];
538             }
539             else {
540 0         0 $linesmen =~ /:\s+(\S+.*\S+)/;
541             $officials->{linesmen} = [
542 0         0 { name => $1, number => 0 },
543             ];
544             }
545             }
546             else {
547 2         4 $officials = {};
548             }
549 4         9 $self->{officials} = $officials;
550             }
551              
552             sub parse_coaches ($$) {
553              
554 4     4 1 8 my $self = shift;
555 4         5 my $ei_box = shift;
556              
557 4         10 my $coach_box = $self->get_sub_tree(0, [2,1], $ei_box);
558 4 100       13 return unless $coach_box;
559              
560 2         9 for my $c (0,1) {
561 4         17 my $coach = $self->get_sub_tree(0, [$c+1,0], $coach_box);
562 4         23 $coach =~ s/^(.*)\:.*/$1/e;
  4         11  
563 4         20 $self->{teams}[$c]{coach} = $coach;
564             }
565             }
566              
567             sub parse_ei_box ($$$) {
568              
569 10     10 1 13 my $self = shift;
570 10         12 my $ei_box = shift;
571              
572 10   100     18 my $box_id = $ei_box->attr('id') || '';
573 10         96 for ($box_id) {
574 10         20 when ('gameReports') {
575 4         20 $self->parse_officials_box($ei_box);
576 4         9 $self->parse_coaches($ei_box);
577             }
578 6         11 when ('threeStars') {
579 0         0 $self->{stars} = [];
580 0         0 for my $s (0..2) {
581 0         0 my $star = $self->get_sub_tree(0, [2,$s,0,0], $ei_box);
582 0 0       0 push(@{$self->{stars}}, extract_id_from_href($star)) if $star;
  0         0  
583             }
584             }
585             }
586             }
587              
588             sub fill_broken_rosters ($$) {
589              
590 0     0 1 0 my $self = shift;
591 0         0 my $broken_rosters = shift;
592              
593 0         0 my $r = 0;
594 0         0 for my $broken_roster (@{$broken_rosters}) {
  0         0  
595 0         0 for my $broken_player (@{$broken_roster}) {
  0         0  
596 0         0 for my $player (@{$self->{teams}[$r]{roster}}) {
  0         0  
597 0 0       0 if ($player->{number} == $broken_player->{'No.'}) {
598 0         0 for my $field (keys %{$broken_player}) {
  0         0  
599 0 0       0 next if $field eq 'No.';
600 0 0       0 unless (exists $player->{$field}) {
601 0 0 0     0 if ($field eq 'number' || $field eq 'error') {
602 0         0 $player->{number} = $broken_player->{$field};
603             }
604             else {
605 0         0 die "Invalid field $field specified";
606             }
607             }
608 0         0 $player->{$field} = $broken_player->{$field};
609             }
610             }
611             }
612             }
613 0         0 $r++;
614             }
615             }
616              
617             sub fill_missing_and_broken ($) {
618              
619 2     2 1 4 my $self = shift;
620              
621 2 50       10 if ($MISSING_EVENTS{$self->{_id}}) {
622 0         0 for my $event (@{$MISSING_EVENTS{$self->{_id}}}) {
  0         0  
623 0         0 push(@{$self->{events}}, $event)
624 0 0 0     0 unless $event->{type} eq 'PEND' || $event->{type} eq 'GEND';
625             }
626             }
627 2 50       8 if ($MISSING_COACHES{$self->{_id}}) {
628 0         0 $self->{teams}[0]{coach} = $MISSING_COACHES{$self->{_id}}->[0];
629 0         0 $self->{teams}[1]{coach} = $MISSING_COACHES{$self->{_id}}->[1];
630             }
631             $self->fill_broken_rosters($self, $BROKEN_ROSTERS{$self->{_id}})
632 2 50       9 if $BROKEN_ROSTERS{$self->{_id}};
633             }
634              
635             sub parse ($) {
636              
637 2     2 1 3 my $self = shift;
638              
639 2         5 my $flag = 1;
640              
641 2         12 for my $i (0..60) {
642 122         495 my $main_div = $self->get_sub_tree(0, [$i]);
643 122 100       188 next unless ref $main_div;
644             # print "I $i\n";
645 42 100 66     70 if ($main_div->attr('class') && $main_div->attr('class') eq 'chrome') {
646 4 100       92 if ($flag == $BOXSCORE_HEADER) {
    50          
647 2         11 $self->read_header($main_div);
648 2         3 $flag++;
649             }
650             elsif ($flag == $BOXSCORE_GAME) {
651 2         9 $self->parse_event_summaries($main_div);
652 2         8 $self->parse_lineup_summaries($main_div);
653 2         9 my $extra_info_box = $self->get_sub_tree(0, [0,2], $main_div);
654 2         5 my $x = 0;
655 2         8 while (my $ei_box = $self->get_sub_tree(0, [$x], $extra_info_box)) {
656 10         23 $self->parse_ei_box($ei_box);
657 10         22 $x++;
658             }
659 2         8 $flag++;
660             }
661             else {
662 0         0 print "Got strange box\n";
663 0         0 print $main_div->dump;
664 0         0 exit;
665             }
666             }
667             }
668 2         9 $self->fill_missing_and_broken();
669             }
670              
671             sub fill_event_default_values ($$) {
672            
673 30     30 1 102 my $self = shift;
674 30         27 my $event = shift;
675              
676 30         34 $event->{file} = $self->{file};
677 30         100 $event->{stage} = $self->{stage};
678 30         34 $event->{season} = $self->{season};
679 30 50 66     85 $event->{strength} = delete $event->{str} if (!$event->{strength} && $event->{str});
680 30 50 33     49 $event->{strength} = 'EV' if $event->{strength} eq 'PS' && $event->{time} eq '0:00';
681 30 100       38 if ($event->{type} eq 'PENL') {
682 24         55 $event->{penalty} =~ s/^\s+//;
683 24         50 $event->{penalty} =~ s/\s+$//;
684 24         38 $event->{penalty} =~ s/\xC2\xA0//g;
685 24         47 $event->{penalty} = uc($event->{penalty});
686             }
687 30 50 33     50 if ($BROKEN_EVENTS{BH}->{$self->{_id}}
688             && (my $evx = $BROKEN_EVENTS{BH}->{$self->{_id}}{$event->{id}})) {
689 0 0       0 if ($evx->{broken}) {
690 0         0 $event->{broken} = 1;
691             }
692             else {
693 0         0 for my $error (keys %{$evx}) {
  0         0  
694             defined $evx->{$error}
695             ? $event->{$error} = $evx->{$error}
696 0 0       0 : delete $event->{$error};
697             }
698             }
699             }
700 30 100       70 $event->{time} = $1 if $event->{time} =~ /^0(\d.*)/;
701 30         84 $event->{on_ice} = [[],[]];
702             }
703              
704             sub normalize ($) {
705              
706 2     2 1 3 my $self = shift;
707              
708 2   50     19 $self->{location} ||= 'Unknown Location';
709 2   50     12 $self->{attendance} ||= 0;
710 2         9 for my $p (3..$LAST_PERIOD-1) {
711 0   0     0 $self->{periods}[$p] ||= {};
712             }
713 2         5 for my $e (1..@{$self->{events}}) {
  2         6  
714 30         45 my $event = $self->{events}[$e-1];
715 30         43 $event->{id} = $e;
716 30         47 $self->fill_event_default_values($event);
717             }
718             }
719              
720             1;