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 20     20   73745 use v5.10.1;
  20         80  
4 20     20   115 use strict;
  20         46  
  20         507  
5 20     20   107 use warnings FATAL => 'all';
  20         49  
  20         676  
6 20     20   97 use experimental qw(smartmatch);
  20         38  
  20         112  
7              
8 20     20   1294 use parent 'Sport::Analytics::NHL::Report';
  20         280  
  20         91  
9              
10 20     20   1184 use Carp;
  20         41  
  20         1250  
11              
12 20     20   122 use Sport::Analytics::NHL::Config;
  20         40  
  20         4121  
13 20     20   136 use Sport::Analytics::NHL::Errors;
  20         58  
  20         3662  
14 20     20   143 use Sport::Analytics::NHL::Util;
  20         37  
  20         1462  
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 20     20   117 use Data::Dumper;
  20         43  
  20         84081  
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 152 my $elem = shift;
102              
103 140         229 $elem->attr('href') =~ /id=(\d+)/;
104 140         1567 my $id = $1;
105 140 50       420 $BROKEN_PLAYER_IDS{$id} || $id;
106             }
107              
108             sub extract_name_from_href ($) {
109              
110 76     76 1 97 my $elem = shift;
111              
112 76         144 $elem->{_content}[0];
113             }
114              
115             sub read_header ($$) {
116              
117 2     2 1 5 my $self = shift;
118 2         3 my $main_div = shift;
119              
120 2         8 $self->{periods} = [ {}, {}, {} ];
121 2         5 $self->{teams} = [];
122 2         6 $self->{status} = 'FINAL';
123 2         5 $self->{type} = 'BH';
124             $self->{source} =~
125 2         166 m|title\>([A-Z].*)\s+at\s+([A-Z].*) - (\d{2}/\d{2}/\d{4}).*title|;
126 2         10 $self->{full_teams} = [ $1, $2 ];
127 2         8 $self->{date} = $3;
128 2         5 $self->{time} = '';
129 2         36 $self->{source} =~ m|gcGameId\D*(\d+)|;
130 2         6 $self->{_id} = $1;
131 2         11 $self->{stage} = int($self->{_id} / 10000) % 10;
132 2         7 $self->{season} = int($self->{_id} / 1000000);
133 2         7 substr($self->{_id}, 4, 1) = '';
134 2         9 $self->{season_id} = sprintf("%04d", $self->{_id} % 10000);
135 2         16 $self->convert_time_date(1);
136 2         16 $self->{source} =~ /game_string:.*\"(\S{3})\s*\@\s*(\S{3})\"/;
137 2         7 $self->{teams}[0]{name} = $1;
138 2         7 $self->{teams}[1]{name} = $2;
139 2         12 my $a_score = $self->get_sub_tree(0, [2,0,2,0,0,0], $main_div);
140 2         7 $self->{teams}[0]{score} = $a_score;
141 2         9 my $h_score = $self->get_sub_tree(0, [2,0,2,0,2,0], $main_div);
142 2         7 $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 9 my $self = shift;
150 6         8 my $row = shift;
151 6         7 my $cell = shift;
152 6         10 my $period = shift;
153              
154             my $event = {
155             type => 'GOAL',
156             strength => 'EV',
157 6         19 time => $cell->{_content}[0],
158             team1 => $self->get_sub_tree(0, [1,0], $row),
159             period => $period,
160             en => 0,
161             };
162 6         17 my $score = $self->get_sub_tree(0, [2,0], $row);
163 6 50       13 return undef unless $score;
164 6         7 my $offset = 0;
165 6 50 66     24 $event->{empty_net} = 1 if ! ref $score && $score =~ /\bEN\b/;
166            
167 6 100       13 if (! ref $score) {
168 2         7 $event->{player1} = extract_id_from_href(
169             $self->get_sub_tree(0, [2,1], $row)
170             );
171 2         5 $offset = 1;
172 2 50       13 if ($score =~ /(\w\w)G/) {
173 2         7 $event->{strength} = $1;
174             }
175 2 50       9 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         10 $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         13 $event->{assists} = [];
193 6 50       16 if ($asst =~ /ASST/) {
194 6         19 $asst1 = $self->get_sub_tree(0, [2,2+$offset], $row);
195 6 50       15 if ($asst1) {
196 6         11 $event->{assist1} = extract_id_from_href($asst1);
197 6         8 push(@{$event->{assists}}, $event->{assist1});
  6         13  
198 6         17 $asst2 = $self->get_sub_tree(0, [2,4+$offset], $row);
199 6 50       16 $event->{assist2} = extract_id_from_href($asst2) if $asst2;
200 6 50       14 push(@{$event->{assists}}, $event->{assist2}) if $asst2;
  6         10  
201             }
202             }
203 6         11 $event->{location} = 'UNK';
204 6         11 $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 29 my $self = shift;
212 24         27 my $row = shift;
213 24         24 my $cell = shift;
214 24         26 my $period = shift;
215              
216             my $event = {
217             type => 'PENL',
218             str => 'XX',
219 24         54 time => $cell->{_content}[0],
220             team1 => $self->get_sub_tree(0, [1,0], $row),
221             period => $period,
222             };
223 24 50       47 return () if $event->{time} eq 'NONE';
224 24         44 my $offender = $self->get_sub_tree(0, [2,0], $row);
225 24 50       39 if (ref $offender) {
226 24         35 $event->{player1} = extract_id_from_href($offender);
227 24         54 $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       67 my $against = $event->{penalty} =~ /\bagainst\b/ ? 1 : 0;
235 24 50       71 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         50 $event->{length} = 2;
248             }
249 24 100       36 if ($against) {
250 22         48 $event->{player2} = extract_id_from_href($self->get_sub_tree(0, [2,2], $row));
251 22         38 $event->{team2} = 'OTH';
252             }
253 24 50       50 $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     134 $event->{penalty} =~ /leaving .* bench/i;
      33        
      33        
      33        
259 24 50       44 $event->{length} = 0 if $event->{penalty} =~ /penalty shot/i;
260 24 100 33     79 if (
      66        
261             $event->{penalty} =~ /too many/i ||
262             $event->{penalty} =~ /\bbench\b/i && $event->{length} != 10
263             ) {
264 2 50 33     15 if ($event->{player1} && $event->{player1} =~ /^8\d{6}/) {
265 2         6 $event->{servedby} = $event->{player1};
266             }
267 2 50       8 $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     68 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         11 $event->{penalty} =~ s/\s*\-\s+bench//i;
276             }
277 24 50       68 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       42 if ($event->{penalty} =~ /aggressor/i) {
282 0         0 $event->{length} = 10;
283             }
284 24         26 $event->{penalty} =~ s/\s*\-\s+obstruction//i;
285 24         31 $event->{penalty} =~ s/(game)-(\S)/"$1 - $2"/ie;
  0         0  
286 24         41 $event->{penalty} =~ s/\s*against\s*//i;
287 24         32 $event->{location} = 'UNK';
288 24         37 $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 14 my $self = shift;
329 4         9 my $summary = shift;
330 4         6 my $type = shift;
331 4         6 my $events = shift;
332              
333 4         6 my $r = 0;
334 4         8 my $period = 0;
335 4         5 my $shootout_mode = 0;
336 4         11 while (my $row = $self->get_sub_tree(0, [$r], $summary)) {
337 42 50       58 unless (ref $row) {
338 0         0 $r++;
339 0         0 next;
340             }
341 42         57 my $cell = $row->{_content}[0];
342 42 100       74 if ($cell->tag eq 'th') {
    50          
343 12 50       69 unless ($shootout_mode) {
344 12         18 $period = $cell->{_content}[0];
345 12 50 33     41 $period += 3 if $cell->{_content}[2] && $cell->{_content}[2] =~ /OT period/i;
346 12 50       18 if ($period eq 'OT Period') {
347 0         0 $period = 4;
348             }
349 12 50       24 if ($period eq 'Shootout') {
350 0         0 $period = 5;
351 0         0 $shootout_mode = 1;
352             }
353 12 50       20 $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         14 $r++;
361 12         28 next;
362             }
363             elsif ($cell->tag eq 'td') {
364 30         256 my $method = "read_boxscore_${type}_event";
365 30         56 my $event = $self->$method($row, $cell, $period);
366 30 50       45 push(@{$events}, ref $event eq 'ARRAY' ? @{$event} : $event) if $event;
  30 50       65  
  0         0  
367             }
368             else {
369 0         0 print "strange cell ", $cell->tag, "\n";
370 0         0 exit;
371             }
372 30         79 $r++;
373             }
374             }
375              
376             sub parse_lineup_row ($$$) {
377              
378 84     84 1 110 my $self = shift;
379 84         90 my $row = shift;
380 84         90 my $headers = shift;
381              
382 84         143 my $player = {};
383 84         97 my $c = 0;
384 84         176 while (my $cell = $self->get_sub_tree(0, [$c], $row)) {
385 1364 50       1888 confess "no ref in lineup cell" unless ref $cell;
386 1364 100       2068 if ($cell->tag eq 'th') {
387 104         480 push(@{$headers}, $cell->{_content}[0]);
  104         166  
388 104         113 $c++;
389 104         221 next;
390             }
391 1260         6649 my $content;
392 1260 100       2041 if (ref $cell->{_content}[0]) {
393 76         90 my $c2 = $cell->{_content}[0];
394             $content = extract_id_from_href(
395 76 100       202 ref $c2->{_content}[0] ? $c2->{_content}[0] : $c2,
396             );
397             $player->{name} = extract_name_from_href(
398 76 100       170 ref $c2->{_content}[0] ? $c2->{_content}[0] : $c2,
399             );
400 76 50       132 if (ref $c2) {
401 76         114 $player->{wl} = $cell->{_content}[1];
402             }
403             }
404             else {
405 1184         1380 $content = $cell->{_content}[0];
406             }
407 1260         2132 $player->{$headers->[$c]} = $content;
408 1260         2688 $c++;
409             }
410 84         151 $player;
411             }
412              
413             sub parse_lineup_summary ($$$) {
414              
415 8     8 1 13 my $self = shift;
416 8         12 my $summary = shift;
417              
418 8         13 my $r = 0;
419 8         14 my @headers = ();
420 8         13 my @players = ();
421 8         19 while (my $row = $self->get_sub_tree(0, [$r], $summary)) {
422 84         149 my $player = $self->parse_lineup_row($row, \@headers);
423 84         97 $r++;
424 84 100       91 next unless keys %{$player};
  84         213  
425 76   100     180 $player->{position} = $player->{Pos} || 'G';
426 76 100       146 my $pos = $player->{position} eq 'G' ? 'G' : 'S';
427 76 100       117 if ($pos eq 'G') {
428 4         10 for my $stat (qw(EV SH PP), 'Saves - Shots') {
429 16         57 $player->{$stat} =~ /^(\d+)\s+\-\s+(\d+)$/;
430 16 100       45 if ($stat eq 'EV') {
    100          
    100          
431 4         14 $player->{evenSaves} = $1;
432 4         13 $player->{evenShotsAgainst} = $2;
433             }
434             elsif ($stat eq 'SH') {
435 4         11 $player->{powerPlaySaves} = $1;
436 4         14 $player->{powerPlayShotsAgainst} = $2;
437             }
438             elsif ($stat eq 'PP') {
439 4         11 $player->{shortHandedSaves} = $1;
440 4         12 $player->{shortHandedShotsAgainst} = $2;
441             }
442             else {
443 4         13 $player->{saves} = $1;
444 4         11 $player->{shots} = $2;
445             }
446             }
447             }
448 76         82 for my $key (keys %{$NORMAL_FIELDS{$pos}}) {
  76         296  
449             $player->{$NORMAL_FIELDS{$pos}->{$key}} = delete $player->{$key}
450 1396 100       2721 if exists $player->{$key};
451             }
452 76         148 for my $field (@{$LIVE_FIELDS{$pos}}) {
  76         124  
453 588   50     1178 $player->{$field} ||= -1;
454             }
455 76 100       148 $player->{decision} =~ s/\W//g if $player->{decision};
456 76   50     239 $player->{evenTimeOnIce} ||= '00:00';
457 76   50     211 $player->{status} ||= 'X';
458 76 50       154 $player->{start} = 2 unless defined $player->{start};
459 76         286 push(@players, $player);
460             }
461 8         36 @players;
462             }
463              
464             sub parse_event_summaries ($$) {
465              
466 2     2 1 4 my $self = shift;
467 2         6 my $summaries = shift;
468              
469 2 50       12 my $e = $self->get_sub_tree(0, [0,1,0,2,0,0], $summaries) ? 0 : 2;
470 2         4 my $events = [];
471              
472 2         7 for my $summary_type (qw(scoring penalty)) {
473 4         13 my $summary = $self->get_sub_tree(0, [0,1,$e,2,0,0], $summaries);
474 4         17 $self->parse_event_summary($summary, $summary_type, $events);
475 4 100       11 if ($summary_type eq 'scoring') {
476 2         9 my $shootout = $self->get_sub_tree(0, [0,1,$e,2,1,0], $summaries);
477 2 50       8 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         7 $self->{events} = $events;
486             }
487              
488             sub parse_lineup_summaries ($$) {
489              
490 2     2 1 4 my $self = shift;
491 2         3 my $summaries = shift;
492              
493 2 50       10 my $e = $self->get_sub_tree(0, [0,1,2,2,0,0], $summaries) ? 2 : 0;
494 2         9 my $x = $self->get_sub_tree(0, [0,1,2,2,0,0], $summaries);
495 2 50 33     14 if ($e == 2 && $x->tag eq 'tbody') {
496 0         0 $e += 2;
497             }
498 2         15 my $s = 1; my $t = 1;
  2         4  
499 2         5 for my $team (qw(away home)) {
500 4         7 for my $roster (qw(skaters goalie)) {
501 8         45 my $summary = $self->get_sub_tree(0, [0,1,$e,2,2*$s-$t,0], $summaries);
502 8         27 my @players = $self->parse_lineup_summary($summary);
503 8   100     145 $self->{teams}[1-$t]{roster} ||= [];
504 8         13 push(@{$self->{teams}[1-$t]{roster}}, @players);
  8         32  
505 8         64 $s++;
506             }
507 4         10 $t--;
508             }
509             }
510              
511             sub parse_officials_box ($$) {
512              
513 4     4 1 6 my $self = shift;
514 4         6 my $ei_box = shift;
515              
516 4         15 my $officials_box = $self->get_sub_tree(0, [2,0], $ei_box);
517              
518 4         13 my $referees = $self->get_sub_tree(0, [1,0], $officials_box);
519 4         7 my $officials = {};
520 4 100 66     20 if ($referees && !ref $referees) {
521 2 50       26 if ($referees =~ /:\s+(\S+.*\S+)\s*\,\s+(\S+.*\S+)\s*$/) {
522             $officials->{referees} = [
523 2         22 { 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         10 my $linesmen = $self->get_sub_tree(0, [2,0], $officials_box);
533 2 50       12 return {} unless $linesmen;
534 2 50       28 if ($linesmen =~ /:\s+(\S+.*\S+)\s*\,\s+(\S+.*\S+)\s*$/) {
535             $officials->{linesmen} = [
536 2         31 { 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         6 $officials = {};
548             }
549 4         16 $self->{officials} = $officials;
550             }
551              
552             sub parse_coaches ($$) {
553              
554 4     4 1 7 my $self = shift;
555 4         7 my $ei_box = shift;
556              
557 4         15 my $coach_box = $self->get_sub_tree(0, [2,1], $ei_box);
558 4 100       14 return unless $coach_box;
559              
560 2         6 for my $c (0,1) {
561 4         11 my $coach = $self->get_sub_tree(0, [$c+1,0], $coach_box);
562 4         20 $coach =~ s/^(.*)\:.*/$1/e;
  4         12  
563 4         16 $self->{teams}[$c]{coach} = $coach;
564             }
565             }
566              
567             sub parse_ei_box ($$$) {
568              
569 10     10 1 14 my $self = shift;
570 10         13 my $ei_box = shift;
571              
572 10   100     25 my $box_id = $ei_box->attr('id') || '';
573 10         110 for ($box_id) {
574 10         19 when ('gameReports') {
575 4         14 $self->parse_officials_box($ei_box);
576 4         15 $self->parse_coaches($ei_box);
577             }
578 6         9 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 5 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       10 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       11 if $BROKEN_ROSTERS{$self->{_id}};
633             }
634              
635             sub parse ($) {
636              
637 2     2 1 3 my $self = shift;
638              
639 2         4 my $flag = 1;
640              
641 2         8 for my $i (0..60) {
642 122         490 my $main_div = $self->get_sub_tree(0, [$i]);
643 122 100       216 next unless ref $main_div;
644             # print "I $i\n";
645 42 100 66     68 if ($main_div->attr('class') && $main_div->attr('class') eq 'chrome') {
646 4 100       78 if ($flag == $BOXSCORE_HEADER) {
    50          
647 2         9 $self->read_header($main_div);
648 2         5 $flag++;
649             }
650             elsif ($flag == $BOXSCORE_GAME) {
651 2         10 $self->parse_event_summaries($main_div);
652 2         8 $self->parse_lineup_summaries($main_div);
653 2         10 my $extra_info_box = $self->get_sub_tree(0, [0,2], $main_div);
654 2         5 my $x = 0;
655 2         6 while (my $ei_box = $self->get_sub_tree(0, [$x], $extra_info_box)) {
656 10         31 $self->parse_ei_box($ei_box);
657 10         26 $x++;
658             }
659 2         10 $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         10 $self->fill_missing_and_broken();
669             }
670              
671             sub fill_event_default_values ($$) {
672            
673 30     30 1 34 my $self = shift;
674 30         34 my $event = shift;
675              
676 30         36 $event->{file} = $self->{file};
677 30         57 $event->{stage} = $self->{stage};
678 30         47 $event->{season} = $self->{season};
679 30 50 66     87 $event->{strength} = delete $event->{str} if (!$event->{strength} && $event->{str});
680 30 50 33     58 $event->{strength} = 'EV' if $event->{strength} eq 'PS' && $event->{time} eq '0:00';
681 30 100       49 if ($event->{type} eq 'PENL') {
682 24         70 $event->{penalty} =~ s/^\s+//;
683 24         77 $event->{penalty} =~ s/\s+$//;
684 24         31 $event->{penalty} =~ s/\xC2\xA0//g;
685 24         38 $event->{penalty} = uc($event->{penalty});
686             }
687 30 50 33     60 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       83 $event->{time} = $1 if $event->{time} =~ /^0(\d.*)/;
701 30         91 $event->{on_ice} = [[],[]];
702             }
703              
704             sub normalize ($) {
705              
706 2     2 1 4 my $self = shift;
707              
708 2   50     27 $self->{location} ||= 'Unknown Location';
709 2   50     39 $self->{attendance} ||= 0;
710 2         7 for my $p (3..$LAST_PERIOD-1) {
711 0   0     0 $self->{periods}[$p] ||= {};
712             }
713 2         6 for my $e (1..@{$self->{events}}) {
  2         6  
714 30         53 my $event = $self->{events}[$e-1];
715 30         45 $event->{id} = $e;
716 30         49 $self->fill_event_default_values($event);
717             }
718             }
719              
720             1;