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