| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Sport::Analytics::NHL::Report::BS; |
|
2
|
|
|
|
|
|
|
|
|
3
|
41
|
|
|
41
|
|
74128
|
use v5.10.1; |
|
|
41
|
|
|
|
|
247
|
|
|
4
|
41
|
|
|
41
|
|
232
|
use strict; |
|
|
41
|
|
|
|
|
166
|
|
|
|
41
|
|
|
|
|
929
|
|
|
5
|
41
|
|
|
41
|
|
206
|
use warnings FATAL => 'all'; |
|
|
41
|
|
|
|
|
101
|
|
|
|
41
|
|
|
|
|
1398
|
|
|
6
|
41
|
|
|
41
|
|
20136
|
use utf8; |
|
|
41
|
|
|
|
|
514
|
|
|
|
41
|
|
|
|
|
235
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
41
|
|
|
41
|
|
1263
|
use experimental qw(smartmatch); |
|
|
41
|
|
|
|
|
92
|
|
|
|
41
|
|
|
|
|
358
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
41
|
|
|
41
|
|
10022
|
use Encode; |
|
|
41
|
|
|
|
|
135724
|
|
|
|
41
|
|
|
|
|
2703
|
|
|
11
|
41
|
|
|
41
|
|
1876
|
use Storable qw(dclone); |
|
|
41
|
|
|
|
|
7887
|
|
|
|
41
|
|
|
|
|
1621
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
41
|
|
|
41
|
|
1855
|
use JSON; |
|
|
41
|
|
|
|
|
29727
|
|
|
|
41
|
|
|
|
|
375
|
|
|
14
|
41
|
|
|
41
|
|
11458
|
use Try::Tiny; |
|
|
41
|
|
|
|
|
28139
|
|
|
|
41
|
|
|
|
|
2054
|
|
|
15
|
41
|
|
|
41
|
|
19066
|
use Text::Unidecode; |
|
|
41
|
|
|
|
|
51585
|
|
|
|
41
|
|
|
|
|
1986
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
41
|
|
|
41
|
|
632
|
use parent 'Sport::Analytics::NHL::Report'; |
|
|
41
|
|
|
|
|
330
|
|
|
|
41
|
|
|
|
|
313
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
41
|
|
|
41
|
|
2535
|
use Sport::Analytics::NHL::Config; |
|
|
41
|
|
|
|
|
145
|
|
|
|
41
|
|
|
|
|
7302
|
|
|
20
|
41
|
|
|
41
|
|
321
|
use Sport::Analytics::NHL::Errors; |
|
|
41
|
|
|
|
|
84
|
|
|
|
41
|
|
|
|
|
7396
|
|
|
21
|
41
|
|
|
41
|
|
479
|
use Sport::Analytics::NHL::Tools; |
|
|
41
|
|
|
|
|
96
|
|
|
|
41
|
|
|
|
|
6286
|
|
|
22
|
41
|
|
|
41
|
|
363
|
use Sport::Analytics::NHL::Util; |
|
|
41
|
|
|
|
|
104
|
|
|
|
41
|
|
|
|
|
2596
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
41
|
|
|
41
|
|
246
|
use Data::Dumper; |
|
|
41
|
|
|
|
|
92
|
|
|
|
41
|
|
|
|
|
150880
|
|
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 NAME |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
Sport::Analytics::NHL::Report::BS - Class for the Boxscore JSON report |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 SYNOPSYS |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
Class for the Boxscore JSON report. |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use Sport::Analytics::NHL::Report::BS; |
|
35
|
|
|
|
|
|
|
my $report = Sport::Analytics::NHL::Report::BS->new($json) |
|
36
|
|
|
|
|
|
|
$report->process(); |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 METHODS |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=over 2 |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=item C |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Create the Boxscore object with the JSON. |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=item C |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Process the Boxscore into the object compatible with further processing, etc. |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=item C |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
Assign specific event data |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Arguments: |
|
55
|
|
|
|
|
|
|
* the event hashref we're building |
|
56
|
|
|
|
|
|
|
* the original event from the JSON |
|
57
|
|
|
|
|
|
|
Returns: void. |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item C |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Assign specific goal event data |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Arguments: |
|
64
|
|
|
|
|
|
|
* the goal event hashref we're building |
|
65
|
|
|
|
|
|
|
* the original goal event from the JSON |
|
66
|
|
|
|
|
|
|
Returns: void. |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=item C |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
Assign specific penalty event data |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
Arguments: |
|
73
|
|
|
|
|
|
|
* the penalty event hashref we're building |
|
74
|
|
|
|
|
|
|
* the original penalty event from the JSON |
|
75
|
|
|
|
|
|
|
Returns: void. |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=item C |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Checks if the event is marked as 'BROKEN' and assigns default values to it. |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Arguments: |
|
82
|
|
|
|
|
|
|
* the event hashref we're building |
|
83
|
|
|
|
|
|
|
* the original event from the JSON |
|
84
|
|
|
|
|
|
|
Returns: void. |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
Note: should probably be replaced with fill_broken from the Tools package. |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=item C |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Fixes the goalie scored upon in the goal events of old boxscores (pre-1987). |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Arguments: the goal event |
|
93
|
|
|
|
|
|
|
Returns: void. |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=item C |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Fixes the served by data in a penalty event, when a bench or coach penalty is assigned in error to a player. |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Arguments: the event |
|
100
|
|
|
|
|
|
|
Returns: void. |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=item C |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Assigns the player1, player2 and servedby players in a variety of events |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
Arguments: |
|
107
|
|
|
|
|
|
|
* the event hashref we're building |
|
108
|
|
|
|
|
|
|
* the original event from the JSON |
|
109
|
|
|
|
|
|
|
Returns: void. |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=item C |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Marks a player entry in the boxscore as a broken one beyond repair |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
Arguments: the player hashref |
|
116
|
|
|
|
|
|
|
Returns: void. |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=item C |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
Converts the events as specified in the boxscore JSON into the $boxscore->{events} arrayref with adjusted fields. |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
Arguments: the JSON events |
|
123
|
|
|
|
|
|
|
Returns: void. |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item C |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Sets some extra header data not handled by any explicit methods: status, location, shootout data etc. |
|
128
|
|
|
|
|
|
|
Arguments: the boxscore JSON hashref |
|
129
|
|
|
|
|
|
|
Returns: void. |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item C |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Sets the game id data: the season, the stage, the season ID, and the overall 9-digit id. |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Arguments: the ID field of the boxscore JSON |
|
136
|
|
|
|
|
|
|
Returns: void. |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=item C |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
Sets the officials for the game. |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
Arguments: the officials' section in the boxscore JSON hashref |
|
143
|
|
|
|
|
|
|
Returns: void. |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=item C |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Set the game periods data from the boxscore JSON hashref |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Arguments: the boxscore JSON hashref |
|
150
|
|
|
|
|
|
|
Returns: void. |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item C |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Sets the player in a team roster from the boxscore JSON hashref in accordance with our data model. |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Arguments: the player live data entry from the boxscore JSON hashref |
|
157
|
|
|
|
|
|
|
Returns: void. |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item C |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Parses the game stars. Not in use. |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item C |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Sets the team data and the team rosters from the boxscore JSON hashref in accordance with our data model. |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Arguments: the boxscore JSON hashref |
|
168
|
|
|
|
|
|
|
Returns: void. |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=item C |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Sets the start, end and last updated timestamps for the game from the date strings in the JSON |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Argument: the boxscore JSON hashref |
|
175
|
|
|
|
|
|
|
Returns: void. |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=item C |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Builds a resolution cache for the roster, with keys as numbers of players pointing at their whole player record in the game. The players who are not numbered are stored as reference to their record in a special list [names]. |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Arguments: none |
|
182
|
|
|
|
|
|
|
Returns: void. Sets $self->{resolve_cache} |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Note: the caches are per team, and valid for one game only. |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=back |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=cut |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
our @JS_IGNORED_EVENT_TYPES = qw( |
|
191
|
|
|
|
|
|
|
PERIOD_READY GAME_SCHEDULED PERIOD_OFFICIAL GAME_OFFICIAL |
|
192
|
|
|
|
|
|
|
SHOOTOUT_COMPLETE EARLY_INT_END EARLY_INT_START EMERGENCY_GOALTENDER |
|
193
|
|
|
|
|
|
|
); |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
our %PLAYER_ID_MAP = ( |
|
196
|
|
|
|
|
|
|
Winner => 'player1', |
|
197
|
|
|
|
|
|
|
Loser => 'player2', |
|
198
|
|
|
|
|
|
|
Hitter => 'player1', |
|
199
|
|
|
|
|
|
|
Hittee => 'player2', |
|
200
|
|
|
|
|
|
|
Shooter => 'player1', |
|
201
|
|
|
|
|
|
|
Blocker => 'player2', |
|
202
|
|
|
|
|
|
|
PlayerID => 'player1', |
|
203
|
|
|
|
|
|
|
PenaltyOn => 'player1', |
|
204
|
|
|
|
|
|
|
DrewBy => 'player2', |
|
205
|
|
|
|
|
|
|
ServedBy => 'servedby', |
|
206
|
|
|
|
|
|
|
Scorer => 'player1', |
|
207
|
|
|
|
|
|
|
Assist => 'void', |
|
208
|
|
|
|
|
|
|
Goalie => 'player2', |
|
209
|
|
|
|
|
|
|
); |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub new ($$) { |
|
212
|
|
|
|
|
|
|
|
|
213
|
15
|
|
|
15
|
1
|
44
|
my $class = shift; |
|
214
|
15
|
|
|
|
|
58
|
my $json = shift; |
|
215
|
|
|
|
|
|
|
|
|
216
|
15
|
|
|
|
|
300
|
my $code = JSON->new(); |
|
217
|
15
|
|
|
|
|
182
|
$code->utf8(1); |
|
218
|
15
|
|
|
|
|
30
|
my $self; |
|
219
|
15
|
50
|
|
|
|
61
|
return undef unless $json; |
|
220
|
15
|
|
|
15
|
|
1172
|
try { $self = {json => $code->decode(decode "UTF-8", $json)} } |
|
221
|
15
|
|
|
7
|
|
214
|
catch { $self = {json => $code->decode($json)} }; |
|
|
7
|
|
|
|
|
20391
|
|
|
222
|
|
|
|
|
|
|
return undef unless |
|
223
|
|
|
|
|
|
|
$self->{json}{gameData}{status}{abstractGameState} |
|
224
|
15
|
50
|
33
|
|
|
55548
|
&& $self->{json}{gameData}{status}{abstractGameState} eq 'Final'; |
|
225
|
15
|
|
|
|
|
65
|
bless $self, $class; |
|
226
|
|
|
|
|
|
|
|
|
227
|
15
|
|
|
|
|
165
|
$self; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub set_id_data ($$) { |
|
231
|
|
|
|
|
|
|
|
|
232
|
7
|
|
|
7
|
1
|
1595
|
my $self = shift; |
|
233
|
7
|
|
|
|
|
19
|
my $id_data = shift; |
|
234
|
|
|
|
|
|
|
|
|
235
|
7
|
|
|
|
|
36
|
my $season_info = parse_nhl_game_id($id_data); |
|
236
|
7
|
|
|
|
|
28
|
$self->{season} = $season_info->{season}; |
|
237
|
7
|
|
|
|
|
22
|
$self->{stage} = $season_info->{stage}; |
|
238
|
7
|
|
|
|
|
15
|
$self->{season_id} = $season_info->{season_id}; |
|
239
|
7
|
|
|
|
|
46
|
$self->{_id} = $self->{season} * 100000 + $self->{stage} * 10000 + $self->{season_id}; |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub set_timestamps ($$) { |
|
243
|
|
|
|
|
|
|
|
|
244
|
6
|
|
|
6
|
1
|
16
|
my $self = shift; |
|
245
|
6
|
|
|
|
|
12
|
my $json = shift; |
|
246
|
|
|
|
|
|
|
|
|
247
|
6
|
|
|
|
|
15
|
my $ts = $json->{metaData}{timeStamp}; $ts =~ s/_/ /; |
|
|
6
|
|
|
|
|
37
|
|
|
248
|
6
|
|
|
|
|
33
|
$self->{last_updated} = str3time($ts); |
|
249
|
6
|
|
|
|
|
98
|
$self->{start_ts} = str3time($json->{gameData}{datetime}{dateTime}); |
|
250
|
|
|
|
|
|
|
$self->{stop_ts} = $json->{gameData}{datetime}{endDateTime} |
|
251
|
|
|
|
|
|
|
? str3time($json->{gameData}{datetime}{endDateTime}) |
|
252
|
6
|
100
|
|
|
|
51
|
: $self->{start_ts} + 9000; |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub set_extra_header_data ($$) { |
|
257
|
|
|
|
|
|
|
|
|
258
|
6
|
|
|
6
|
1
|
22
|
my $self = shift; |
|
259
|
6
|
|
|
|
|
14
|
my $json = shift; |
|
260
|
|
|
|
|
|
|
|
|
261
|
6
|
|
|
|
|
19
|
$self->{status} = 'FINAL'; |
|
262
|
6
|
|
|
|
|
18
|
$self->{location} = $json->{gameData}{venue}{name}; |
|
263
|
6
|
50
|
|
|
|
160
|
if ($json->{liveData}{linescore}{hasShootout}) { |
|
264
|
0
|
|
|
|
|
0
|
$self->{so} = 1; |
|
265
|
0
|
|
|
|
|
0
|
$self->{shootout} = dclone $json->{liveData}{linescore}{shootoutInfo}; |
|
266
|
0
|
|
|
|
|
0
|
delete $self->{shootout}{startTime}; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub set_officials ($$) { |
|
272
|
|
|
|
|
|
|
|
|
273
|
6
|
|
|
6
|
1
|
21
|
my $self = shift; |
|
274
|
6
|
|
|
|
|
14
|
my $officials = shift; |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$self->{officials} = { |
|
277
|
6
|
|
|
|
|
28
|
referees => [], |
|
278
|
|
|
|
|
|
|
linesmen => [], |
|
279
|
|
|
|
|
|
|
}; |
|
280
|
6
|
|
|
|
|
14
|
for my $official (@{$officials}) { |
|
|
6
|
|
|
|
|
18
|
|
|
281
|
|
|
|
|
|
|
my $o = { |
|
282
|
|
|
|
|
|
|
name => unidecode(uc $official->{official}{fullName}), |
|
283
|
22
|
|
100
|
|
|
85
|
official_id => $official->{official}{id} || 0, |
|
284
|
|
|
|
|
|
|
}; |
|
285
|
|
|
|
|
|
|
push( |
|
286
|
22
|
|
|
|
|
390
|
@{$self->{officials}{ |
|
287
|
22
|
100
|
|
|
|
88
|
$official->{officialType} eq 'Referee' ? 'referees' : 'linesmen' |
|
288
|
|
|
|
|
|
|
}}, $o |
|
289
|
|
|
|
|
|
|
); |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub set_broken_player ($$) { |
|
294
|
|
|
|
|
|
|
|
|
295
|
245
|
|
|
245
|
1
|
331
|
my $self = shift; |
|
296
|
245
|
|
|
|
|
284
|
my $player = shift; |
|
297
|
|
|
|
|
|
|
|
|
298
|
245
|
0
|
33
|
|
|
738
|
if ( |
|
|
|
|
0
|
|
|
|
|
|
299
|
|
|
|
|
|
|
$BROKEN_PLAYERS{BS}->{$self->{_id}} |
|
300
|
|
|
|
|
|
|
&& $BROKEN_PLAYERS{BS}->{$self->{_id}}->{$player} |
|
301
|
|
|
|
|
|
|
&& $BROKEN_PLAYERS{BS}->{$self->{_id}}->{$player} == -1 |
|
302
|
|
|
|
|
|
|
) { |
|
303
|
|
|
|
|
|
|
return { |
|
304
|
|
|
|
|
|
|
broken => 1, |
|
305
|
|
|
|
|
|
|
_id => $player, |
|
306
|
0
|
|
|
|
|
0
|
number => $self->{broken_number}++, |
|
307
|
|
|
|
|
|
|
}; |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub set_player ($$) { |
|
312
|
|
|
|
|
|
|
|
|
313
|
245
|
|
|
245
|
1
|
300
|
my $self = shift; |
|
314
|
245
|
|
|
|
|
279
|
my $ld_player = shift; |
|
315
|
|
|
|
|
|
|
|
|
316
|
245
|
100
|
100
|
|
|
476
|
unless ($ld_player->{stats}{skaterStats} || $ld_player->{stats}{goalieStats}) { |
|
317
|
|
|
|
|
|
|
$ld_player->{stats}{ |
|
318
|
25
|
50
|
|
|
|
87
|
$ld_player->{position}{code} eq 'G' ? 'goalieStats' : 'skaterStats' |
|
319
|
|
|
|
|
|
|
} = { broken => 1 }, |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
my $player = { |
|
322
|
|
|
|
|
|
|
_id => $ld_player->{person}{id}, |
|
323
|
|
|
|
|
|
|
name => uc unidecode($ld_player->{person}{fullName}), |
|
324
|
|
|
|
|
|
|
number => $ld_player->{jerseyNumber}, |
|
325
|
|
|
|
|
|
|
position => uc $ld_player->{position}{code}, |
|
326
|
|
|
|
|
|
|
$ld_player->{stats}{skaterStats} ? |
|
327
|
233
|
|
|
|
|
8639
|
%{dclone $ld_player->{stats}{skaterStats}} : |
|
328
|
245
|
100
|
50
|
|
|
544
|
%{dclone ($ld_player->{stats}{goalieStats} || {})}, |
|
|
12
|
|
|
|
|
559
|
|
|
329
|
|
|
|
|
|
|
}; |
|
330
|
245
|
0
|
33
|
|
|
1060
|
if ($BROKEN_PLAYERS{BS}->{$self->{_id}} |
|
|
|
|
33
|
|
|
|
|
|
331
|
|
|
|
|
|
|
&& $BROKEN_PLAYERS{BS}->{$self->{_id}}->{$ld_player->{person}{id}} |
|
332
|
|
|
|
|
|
|
&& ref $BROKEN_PLAYERS{BS}->{$self->{_id}}->{$ld_player->{person}{id}}) { |
|
333
|
0
|
|
|
|
|
0
|
for my $stat (keys %{$BROKEN_PLAYERS{BS}->{$self->{_id}}->{$ld_player->{person}{id}}}) { |
|
|
0
|
|
|
|
|
0
|
|
|
334
|
0
|
|
|
|
|
0
|
$player->{$stat} = $BROKEN_PLAYERS{BS}->{$self->{_id}}->{$ld_player->{person}{id}}{$stat}; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
} |
|
337
|
245
|
100
|
50
|
|
|
532
|
$player->{pim} ||= ($player->{penaltyMinutes} || 0) if $player->{position} eq 'G'; |
|
|
|
|
33
|
|
|
|
|
|
338
|
245
|
|
|
|
|
570
|
$player; |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub set_teams ($$) { |
|
342
|
|
|
|
|
|
|
|
|
343
|
6
|
|
|
6
|
1
|
21
|
my $self = shift; |
|
344
|
6
|
|
|
|
|
13
|
my $json = shift; |
|
345
|
|
|
|
|
|
|
|
|
346
|
6
|
|
|
|
|
14
|
$self->{teams} = []; |
|
347
|
|
|
|
|
|
|
$self->{_score} = [ |
|
348
|
|
|
|
|
|
|
$json->{liveData}{linescore}{teams}{away}{goals}, |
|
349
|
|
|
|
|
|
|
$json->{liveData}{linescore}{teams}{home}{goals}, |
|
350
|
6
|
|
|
|
|
45
|
]; |
|
351
|
6
|
|
|
|
|
15
|
my $t = 0; |
|
352
|
6
|
|
|
|
|
22
|
for my $team_key (qw(away home)) { |
|
353
|
12
|
|
|
|
|
33
|
$self->{_t} = $t; |
|
354
|
12
|
|
|
|
|
32
|
my $ldb_team = $json->{liveData}{boxscore}{teams}{$team_key}; |
|
355
|
12
|
|
|
|
|
24
|
my $ldl_team = $json->{liveData}{linescore}{teams}{$team_key}; |
|
356
|
|
|
|
|
|
|
my $team = { |
|
357
|
|
|
|
|
|
|
orig => $ldb_team->{team}{triCode} || $json->{gameData}{teams}{$team_key}{abbreviation}, |
|
358
|
|
|
|
|
|
|
stats => $ldb_team->{teamStats}{teamSkaterStats}, |
|
359
|
|
|
|
|
|
|
roster => [], |
|
360
|
|
|
|
|
|
|
scratches => $ldb_team->{scratches}, |
|
361
|
|
|
|
|
|
|
coach => $ldb_team->{coaches}[0]{person}{fullName} |
|
362
|
|
|
|
|
|
|
? uc $ldb_team->{coaches}[0]{person}{fullName} |
|
363
|
|
|
|
|
|
|
: 'UNKNOWN COACH', |
|
364
|
|
|
|
|
|
|
score => $ldl_team->{goals}, |
|
365
|
|
|
|
|
|
|
shots => $ldl_team->{shotsOnGoal}, |
|
366
|
|
|
|
|
|
|
pull => $ldl_team->{goaliePulled}, |
|
367
|
|
|
|
|
|
|
teamid => $ldl_team->{team}{id}, |
|
368
|
12
|
100
|
33
|
|
|
155
|
}; |
|
369
|
12
|
|
|
|
|
58
|
$team->{name} = resolve_team($team->{orig}); |
|
370
|
12
|
50
|
|
|
|
64
|
$team->{coach} = $BROKEN_COACHES{$team->{coach}} if $BROKEN_COACHES{$team->{coach}}; |
|
371
|
12
|
|
|
|
|
23
|
$self->{broken_number} = 101; |
|
372
|
12
|
|
|
|
|
23
|
for my $ld_player (values %{$ldb_team->{players}}) { |
|
|
12
|
|
|
|
|
55
|
|
|
373
|
|
|
|
|
|
|
my $player = |
|
374
|
245
|
|
33
|
|
|
504
|
$self->set_broken_player($ld_player->{person}{id}) || |
|
375
|
|
|
|
|
|
|
$self->set_player($ld_player); |
|
376
|
245
|
|
|
|
|
308
|
push(@{$team->{roster}}, $player); |
|
|
245
|
|
|
|
|
411
|
|
|
377
|
245
|
100
|
|
|
|
494
|
$team->{_decision} = $player->{decision} if ($player->{decision}); |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
push( |
|
380
|
0
|
|
|
|
|
0
|
@{$team->{roster}}, |
|
381
|
0
|
|
|
|
|
0
|
@{$MISSING_PLAYERS{$self->{_id}}->[$t]} |
|
382
|
|
|
|
|
|
|
) if ($MISSING_PLAYERS{$self->{_id}} |
|
383
|
12
|
50
|
33
|
|
|
67
|
&& @{$MISSING_PLAYERS{$self->{_id}}->[$t]}); |
|
|
0
|
|
|
|
|
0
|
|
|
384
|
12
|
50
|
|
|
|
33
|
$self->force_decision($team) unless $team->{_decision}; |
|
385
|
12
|
|
|
|
|
19
|
push(@{$self->{teams}}, $team); |
|
|
12
|
|
|
|
|
28
|
|
|
386
|
12
|
|
|
|
|
26
|
$t++; |
|
387
|
|
|
|
|
|
|
} |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub set_stars ($$) { |
|
392
|
|
|
|
|
|
|
|
|
393
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
394
|
0
|
|
|
|
|
0
|
my $json = shift; |
|
395
|
|
|
|
|
|
|
|
|
396
|
0
|
|
|
|
|
0
|
$self->{stars} = []; |
|
397
|
0
|
|
|
|
|
0
|
for my $star (qw(firstStar secondStar thirdStar)) { |
|
398
|
0
|
|
|
|
|
0
|
push(@{$self->{stars}}, $json->{liveData}{decisions}{$star}{id}) |
|
399
|
0
|
0
|
|
|
|
0
|
if $json->{liveData}{decisions}{$star}; |
|
400
|
|
|
|
|
|
|
} |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub set_periods ($$) { |
|
404
|
|
|
|
|
|
|
|
|
405
|
6
|
|
|
6
|
1
|
44
|
my $self = shift; |
|
406
|
6
|
|
|
|
|
13
|
my $json = shift; |
|
407
|
|
|
|
|
|
|
|
|
408
|
6
|
|
|
|
|
16
|
$self->{periods} = []; |
|
409
|
6
|
|
|
|
|
18
|
my $p = 1; |
|
410
|
6
|
|
|
|
|
11
|
for my $ld_period (@{$json->{liveData}{linescore}{periods}}) { |
|
|
6
|
|
|
|
|
31
|
|
|
411
|
|
|
|
|
|
|
my $period = { |
|
412
|
|
|
|
|
|
|
id => $p, |
|
413
|
|
|
|
|
|
|
start_ts => $ld_period->{startTime} |
|
414
|
|
|
|
|
|
|
? str3time($ld_period->{startTime}) |
|
415
|
|
|
|
|
|
|
: $self->{start_ts} + 2250*($p-1), |
|
416
|
|
|
|
|
|
|
stop_ts => $ld_period->{endTime} |
|
417
|
|
|
|
|
|
|
? str3time($ld_period->{endTime}) |
|
418
|
|
|
|
|
|
|
: $self->{start_ts} + 2250*$p-1, |
|
419
|
|
|
|
|
|
|
score => [ |
|
420
|
|
|
|
|
|
|
$ld_period->{away}{goals}, $ld_period->{away}{shotsOnGoal}, |
|
421
|
|
|
|
|
|
|
$ld_period->{home}{shotsOnGoal}, $ld_period->{home}{goals}, |
|
422
|
|
|
|
|
|
|
], |
|
423
|
|
|
|
|
|
|
type => $ld_period->{periodType}, |
|
424
|
18
|
100
|
|
|
|
71
|
}; |
|
|
|
100
|
|
|
|
|
|
|
425
|
18
|
|
|
|
|
33
|
push(@{$self->{periods}}, $period); |
|
|
18
|
|
|
|
|
42
|
|
|
426
|
18
|
50
|
33
|
|
|
116
|
$self->{ot} ||= $ld_period->{periodType} eq 'OVERTIME' ? 1 : 0; |
|
427
|
18
|
|
|
|
|
38
|
$p++; |
|
428
|
|
|
|
|
|
|
} |
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub place_players ($$) { |
|
432
|
|
|
|
|
|
|
|
|
433
|
756
|
|
|
756
|
1
|
927
|
my $event = shift; |
|
434
|
756
|
|
|
|
|
900
|
my $ld_event = shift; |
|
435
|
|
|
|
|
|
|
|
|
436
|
756
|
|
|
|
|
878
|
for my $player (@{$ld_event->{players}}) { |
|
|
756
|
|
|
|
|
1945
|
|
|
437
|
1537
|
|
|
|
|
6191
|
$event->{$PLAYER_ID_MAP{$player->{playerType}}} = $player->{player}{id}; |
|
438
|
|
|
|
|
|
|
} |
|
439
|
|
|
|
|
|
|
} |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub assign_specific_penalty_data ($$) { |
|
442
|
|
|
|
|
|
|
|
|
443
|
100
|
|
|
100
|
1
|
142
|
my $event = shift; |
|
444
|
100
|
|
|
|
|
165
|
my $ld_event = shift; |
|
445
|
|
|
|
|
|
|
|
|
446
|
100
|
|
|
|
|
206
|
place_players($event, $ld_event); |
|
447
|
100
|
|
|
|
|
209
|
$event->{penalty} = $ld_event->{result}{secondaryType}; |
|
448
|
100
|
|
100
|
|
|
306
|
$event->{severity} = uc($ld_event->{result}{penaltySeverity} || ''); |
|
449
|
100
|
|
|
|
|
187
|
$event->{length} = $ld_event->{result}{penaltyMinutes}; |
|
450
|
100
|
50
|
33
|
|
|
288
|
if ($event->{penalty} =~ /bench/i && $event->{penalty} !~ /leaving/i) { |
|
451
|
0
|
0
|
|
|
|
0
|
$event->{servedby} = $event->{player1} if $event->{player1}; |
|
452
|
0
|
|
|
|
|
0
|
$event->{player1} = $BENCH_PLAYER_ID; |
|
453
|
|
|
|
|
|
|
} |
|
454
|
100
|
100
|
66
|
|
|
703
|
if ($event->{penalty} =~ /too many/i || $event->{description} =~ /^\s+against/i) { |
|
|
|
50
|
|
|
|
|
|
|
455
|
5
|
50
|
33
|
|
|
51
|
$event->{servedby} ||= $event->{player1} if $event->{player1}; |
|
456
|
5
|
|
|
|
|
18
|
$event->{player1} = $BENCH_PLAYER_ID; |
|
457
|
5
|
|
|
|
|
26
|
$event->{pim_correction} += 2; |
|
458
|
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
elsif ($event->{penalty} =~ /(.*\w)\W*\bcoach$/i) { |
|
460
|
0
|
0
|
|
|
|
0
|
$event->{servedby} = $event->{player1} if $event->{player1}; |
|
461
|
0
|
|
|
|
|
0
|
$event->{player1} = $COACH_PLAYER_ID; |
|
462
|
0
|
|
|
|
|
0
|
$event->{penalty} = $1; |
|
463
|
|
|
|
|
|
|
} |
|
464
|
100
|
|
|
|
|
275
|
$event->{penalty} = normalize_penalty($event->{penalty}); |
|
465
|
|
|
|
|
|
|
} |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
sub assign_specific_goal_data ($$) { |
|
468
|
|
|
|
|
|
|
|
|
469
|
26
|
|
|
26
|
1
|
54
|
my $event = shift; |
|
470
|
26
|
|
|
|
|
45
|
my $ld_event = shift; |
|
471
|
|
|
|
|
|
|
|
|
472
|
26
|
|
|
|
|
74
|
place_players($event, $ld_event); |
|
473
|
|
|
|
|
|
|
$event->{assists} = [ map { |
|
474
|
102
|
100
|
|
|
|
245
|
$_->{playerType} eq 'Assist' ? $_->{player}{id} : (), |
|
475
|
26
|
|
|
|
|
46
|
} @{$ld_event->{players}} ]; |
|
|
26
|
|
|
|
|
64
|
|
|
476
|
26
|
|
100
|
|
|
128
|
$event->{shot_type} = vocabulary_lookup('shot_type', $ld_event->{result}{secondaryType} || ''); |
|
477
|
26
|
|
|
|
|
97
|
$event->{en} = $ld_event->{result}{emptyNet}; |
|
478
|
26
|
|
|
|
|
82
|
$event->{gwg} = $ld_event->{result}{gameWinningGoal}; |
|
479
|
|
|
|
|
|
|
} |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sub assign_specific_event_data ($$) { |
|
482
|
|
|
|
|
|
|
|
|
483
|
1616
|
|
|
1616
|
1
|
2097
|
my $event = shift; |
|
484
|
1616
|
|
|
|
|
1945
|
my $ld_event = shift; |
|
485
|
|
|
|
|
|
|
|
|
486
|
1616
|
|
|
|
|
2541
|
for ($event->{type}) { |
|
487
|
1616
|
|
|
|
|
3106
|
when ('FAC') { |
|
488
|
325
|
|
|
|
|
417
|
for my $player (@{$ld_event->{players}}) { |
|
|
325
|
|
|
|
|
721
|
|
|
489
|
650
|
|
|
|
|
2506
|
$event->{$PLAYER_ID_MAP{$player->{playerType}}} = $player->{player}{id}; |
|
490
|
|
|
|
|
|
|
} |
|
491
|
|
|
|
|
|
|
$event->{winning_team} = $ld_event->{team}{triCode}, |
|
492
|
325
|
|
|
|
|
871
|
} |
|
493
|
1291
|
|
|
|
|
1638
|
when ('GIVE') { $event->{player1} = $ld_event->{players}[0]{player}{id}; } |
|
|
50
|
|
|
|
|
264
|
|
|
494
|
1241
|
|
|
|
|
1583
|
when ('TAKE') { $event->{player1} = $ld_event->{players}[0]{player}{id}; } |
|
|
45
|
|
|
|
|
275
|
|
|
495
|
1196
|
|
|
|
|
1886
|
when ('MISS') { |
|
496
|
160
|
|
|
|
|
818
|
$event->{player1} = $ld_event->{players}[0]{player}{id}; |
|
497
|
160
|
|
|
|
|
579
|
$event->{description} =~ /\- (.*)/; |
|
498
|
160
|
|
50
|
|
|
661
|
$event->{miss} = vocabulary_lookup('miss', $1 || ''); |
|
499
|
|
|
|
|
|
|
} |
|
500
|
1036
|
|
|
|
|
1286
|
when ('STOP') { $event->{stopreason} = [ vocabulary_lookup('stopreason', $event->{description})] } |
|
|
245
|
|
|
|
|
524
|
|
|
501
|
791
|
|
|
|
|
1006
|
when ('HIT') { place_players($event, $ld_event); } |
|
|
160
|
|
|
|
|
354
|
|
|
502
|
631
|
|
|
|
|
815
|
when ('BLOCK') { |
|
503
|
155
|
|
|
|
|
395
|
place_players($event, $ld_event); |
|
504
|
155
|
|
|
|
|
230
|
my $x = $event->{player2}; |
|
505
|
155
|
|
|
|
|
220
|
$event->{player2} = $event->{player1}; |
|
506
|
155
|
|
|
|
|
279
|
$event->{player1} = $x; |
|
507
|
|
|
|
|
|
|
} |
|
508
|
476
|
|
|
|
|
643
|
when ('SHOT') { |
|
509
|
315
|
|
|
|
|
713
|
place_players($event, $ld_event); |
|
510
|
315
|
|
50
|
|
|
999
|
$event->{shot_type} = vocabulary_lookup('shot_type', $ld_event->{result}{secondaryType} || ''); |
|
511
|
|
|
|
|
|
|
} |
|
512
|
161
|
|
|
|
|
233
|
when ('PENL') { assign_specific_penalty_data($event, $ld_event); } |
|
|
100
|
|
|
|
|
239
|
|
|
513
|
61
|
|
|
|
|
99
|
when ('GOAL') { assign_specific_goal_data($event, $ld_event); } |
|
|
26
|
|
|
|
|
109
|
|
|
514
|
|
|
|
|
|
|
} |
|
515
|
1616
|
|
|
|
|
2568
|
delete $event->{void}; |
|
516
|
|
|
|
|
|
|
} |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub check_broken ($$) { |
|
519
|
|
|
|
|
|
|
|
|
520
|
1616
|
|
|
1616
|
1
|
1910
|
my $event = shift; |
|
521
|
1616
|
|
|
|
|
1876
|
my $ld_event = shift; |
|
522
|
|
|
|
|
|
|
|
|
523
|
1616
|
50
|
33
|
|
|
6389
|
if ( |
|
524
|
|
|
|
|
|
|
$BROKEN_EVENTS{BS}->{$event->{game_id}} && |
|
525
|
|
|
|
|
|
|
(my $evx = $BROKEN_EVENTS{BS}->{$event->{game_id}}->{$ld_event->{about}{eventIdx}}) |
|
526
|
|
|
|
|
|
|
) { |
|
527
|
0
|
|
|
|
|
0
|
for my $key (keys %{$evx}) { |
|
|
0
|
|
|
|
|
0
|
|
|
528
|
0
|
|
|
|
|
0
|
$event->{$key} = $evx->{$key}; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
sub fix_servedby ($) { |
|
534
|
|
|
|
|
|
|
|
|
535
|
1616
|
|
|
1616
|
1
|
1909
|
my $event = shift; |
|
536
|
|
|
|
|
|
|
|
|
537
|
1616
|
50
|
100
|
|
|
3328
|
if ($event->{type} eq 'PENL' |
|
|
|
|
66
|
|
|
|
|
|
538
|
|
|
|
|
|
|
&& $event->{description} =~ /served by/i |
|
539
|
|
|
|
|
|
|
&& ! $event->{servedby}) { |
|
540
|
0
|
|
|
|
|
0
|
$event->{_servedby} = 1; |
|
541
|
|
|
|
|
|
|
my @pl = ( |
|
542
|
|
|
|
|
|
|
3,2, |
|
543
|
|
|
|
|
|
|
($event->{description} =~ /\b(illegal|official|proceed|dress|refusal|objects|misconduct|ineligible|conduct|bench|coach|delay|abus|leaving)/i && $event->{description} !~ /leaves.*bench/i) |
|
544
|
|
|
|
|
|
|
|| $event->{severity} =~ /BENCH/ |
|
545
|
0
|
0
|
0
|
|
|
0
|
|| $event->{description} =~ /minor served by/i |
|
546
|
|
|
|
|
|
|
? 1 : () |
|
547
|
|
|
|
|
|
|
); |
|
548
|
0
|
|
|
|
|
0
|
for my $p (@pl) { |
|
549
|
0
|
|
|
|
|
0
|
my $field = "player$p"; |
|
550
|
0
|
0
|
|
|
|
0
|
if (defined $event->{$field}) { |
|
551
|
0
|
|
|
|
|
0
|
delete $event->{_servedby}; |
|
552
|
0
|
|
|
|
|
0
|
$event->{servedby} = delete $event->{$field}; |
|
553
|
0
|
0
|
|
|
|
0
|
if ($field eq 'player1') { |
|
554
|
0
|
0
|
|
|
|
0
|
$event->{$field} = $event->{description} =~ /coach/i ? |
|
555
|
|
|
|
|
|
|
$COACH_PLAYER_ID : $BENCH_PLAYER_ID; |
|
556
|
|
|
|
|
|
|
} |
|
557
|
0
|
|
|
|
|
0
|
return; |
|
558
|
|
|
|
|
|
|
} |
|
559
|
|
|
|
|
|
|
} |
|
560
|
|
|
|
|
|
|
} |
|
561
|
|
|
|
|
|
|
} |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
sub fix_old_goalie ($$) { |
|
564
|
|
|
|
|
|
|
|
|
565
|
1616
|
|
|
1616
|
1
|
2068
|
my $self = shift; |
|
566
|
1616
|
|
|
|
|
1924
|
my $event = shift; |
|
567
|
|
|
|
|
|
|
|
|
568
|
1616
|
50
|
66
|
|
|
3333
|
if ($event->{type} eq 'GOAL' |
|
|
|
|
66
|
|
|
|
|
|
569
|
|
|
|
|
|
|
&& ! $event->{en} |
|
570
|
|
|
|
|
|
|
&& ! $event->{player2} |
|
571
|
|
|
|
|
|
|
) { |
|
572
|
|
|
|
|
|
|
my $team = $self->{teams}[ |
|
573
|
0
|
0
|
|
|
|
0
|
$event->{team1} eq $self->{teams}[0]{name} ? 1 : 0, |
|
574
|
|
|
|
|
|
|
]; |
|
575
|
|
|
|
|
|
|
my @goalies = sort { |
|
576
|
|
|
|
|
|
|
get_seconds($a->{timeOnIce}) <=> get_seconds($b->{timeOnIce}) |
|
577
|
0
|
|
|
|
|
0
|
} grep { |
|
578
|
0
|
|
|
|
|
0
|
$_->{position} eq 'G' |
|
579
|
0
|
|
|
|
|
0
|
} @{$team->{roster}}; |
|
|
0
|
|
|
|
|
0
|
|
|
580
|
0
|
|
|
|
|
0
|
my $goalie = $goalies[0]; |
|
581
|
0
|
|
|
|
|
0
|
$event->{player2} = $goalie->{_id}; |
|
582
|
0
|
|
|
|
|
0
|
$event->{team2} = $team->{name}; |
|
583
|
|
|
|
|
|
|
} |
|
584
|
|
|
|
|
|
|
} |
|
585
|
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
sub set_events ($$) { |
|
587
|
|
|
|
|
|
|
|
|
588
|
6
|
|
|
6
|
1
|
22
|
my $self = shift; |
|
589
|
6
|
|
|
|
|
12
|
my $events = shift; |
|
590
|
|
|
|
|
|
|
|
|
591
|
6
|
|
|
|
|
17
|
$self->{events} = []; |
|
592
|
|
|
|
|
|
|
|
|
593
|
6
|
|
|
|
|
13
|
for my $ld_event (@{$events}) { |
|
|
6
|
|
|
|
|
22
|
|
|
594
|
|
|
|
|
|
|
next if $BROKEN_EVENTS{BS}->{$self->{_id}}->{$ld_event->{about}{eventIdx}} && |
|
595
|
1651
|
50
|
33
|
|
|
8380
|
$BROKEN_EVENTS{BS}->{$self->{_id}}->{$ld_event->{about}{eventIdx}} eq '-1'; |
|
596
|
1651
|
100
|
|
|
|
2573
|
next if grep { $_ eq $ld_event->{result}{eventTypeId} } @JS_IGNORED_EVENT_TYPES; |
|
|
13208
|
|
|
|
|
21390
|
|
|
597
|
|
|
|
|
|
|
my $event = { |
|
598
|
|
|
|
|
|
|
season => $self->{season}, |
|
599
|
|
|
|
|
|
|
stage => $self->{stage}, |
|
600
|
|
|
|
|
|
|
game_id => $self->{_id}, |
|
601
|
|
|
|
|
|
|
period => $ld_event->{about}{period}, |
|
602
|
|
|
|
|
|
|
time => $ld_event->{about}{periodTime}, |
|
603
|
|
|
|
|
|
|
coordinates => $ld_event->{coordinates}, |
|
604
|
|
|
|
|
|
|
type => vocabulary_lookup('events', $ld_event->{result}{eventTypeId}), |
|
605
|
|
|
|
|
|
|
description => uc $ld_event->{result}{description}, |
|
606
|
|
|
|
|
|
|
strength => vocabulary_lookup('strength', $ld_event->{result}{strength}{code} || ''), |
|
607
|
|
|
|
|
|
|
event_idx => $ld_event->{about}{eventIdx}, |
|
608
|
|
|
|
|
|
|
bsjs_id => $ld_event->{about}{eventId}, |
|
609
|
|
|
|
|
|
|
event_code => uc ($ld_event->{about}{eventCode} || ''), |
|
610
|
|
|
|
|
|
|
so => $ld_event->{about}{periodType} eq 'SHOOTOUT' ? 1 : 0, |
|
611
|
|
|
|
|
|
|
$BROKEN_EVENTS{BS}->{$self->{_id}}->{$ld_event->{about}{eventIdx}} ? |
|
612
|
0
|
|
|
|
|
0
|
%{$BROKEN_EVENTS{BS}->{$self->{_id}}->{$ld_event->{about}{eventIdx}}} : (), |
|
613
|
|
|
|
|
|
|
$ld_event->{team} ? ( |
|
614
|
|
|
|
|
|
|
team1 => resolve_team($ld_event->{team}{triCode} || $ld_event->{team}{name}), |
|
615
|
|
|
|
|
|
|
teamid => $ld_event->{team}{id}, |
|
616
|
1616
|
50
|
100
|
|
|
4915
|
) : (), |
|
|
|
50
|
50
|
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
617
|
|
|
|
|
|
|
}; |
|
618
|
1616
|
100
|
|
|
|
8614
|
$event->{time} = substr($event->{time}, 1) if $event->{time} =~ /^0/; |
|
619
|
|
|
|
|
|
|
$event->{special} = 1 |
|
620
|
1616
|
50
|
33
|
|
|
3828
|
if $SPECIAL_EVENTS{$self->{_id}} && $SPECIAL_EVENTS{$self->{_id}}->{$ld_event->{about}{eventIdx}}; |
|
621
|
1616
|
|
|
|
|
3556
|
assign_specific_event_data($event, $ld_event); |
|
622
|
1616
|
|
|
|
|
3653
|
$self->fix_old_goalie($event); |
|
623
|
1616
|
|
|
|
|
3305
|
check_broken($event, $ld_event); |
|
624
|
1616
|
|
|
|
|
3158
|
fix_servedby($event); |
|
625
|
1616
|
|
|
|
|
1890
|
push(@{$self->{events}}, $event); |
|
|
1616
|
|
|
|
|
3885
|
|
|
626
|
|
|
|
|
|
|
} |
|
627
|
|
|
|
|
|
|
} |
|
628
|
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
sub build_resolve_cache ($) { |
|
630
|
|
|
|
|
|
|
|
|
631
|
8
|
|
|
8
|
1
|
16743
|
my $self = shift; |
|
632
|
|
|
|
|
|
|
|
|
633
|
8
|
|
|
|
|
36
|
$self->{resolve_cache} = {}; |
|
634
|
8
|
|
|
|
|
29
|
for my $t (0,1) { |
|
635
|
16
|
|
|
|
|
29
|
my $unknown_number = 100; |
|
636
|
16
|
|
|
331
|
|
77
|
$self->{teams}[$t]{roster} = [ my_uniq { $_->{_id} } @{$self->{teams}[$t]{roster}} ]; |
|
|
331
|
|
|
|
|
947
|
|
|
|
16
|
|
|
|
|
103
|
|
|
637
|
16
|
|
|
|
|
70
|
for my $player (@{$self->{teams}[$t]{roster}}) { |
|
|
16
|
|
|
|
|
57
|
|
|
638
|
331
|
100
|
|
|
|
476
|
if (! $player->{broken}) { |
|
639
|
296
|
100
|
|
|
|
463
|
$player->{penaltyMinutes} = delete $player->{pim} if defined $player->{pim}; |
|
640
|
296
|
|
33
|
|
|
464
|
$player->{number} ||= $unknown_number++; |
|
641
|
296
|
|
|
|
|
580
|
while ($self->{resolve_cache}{$self->{teams}[$t]{name}}->{$player->{number}}) { |
|
642
|
0
|
|
|
|
|
0
|
$player->{number} += 100; |
|
643
|
|
|
|
|
|
|
} |
|
644
|
296
|
|
|
|
|
721
|
$self->{resolve_cache}{$self->{teams}[$t]{name}}->{$player->{number}} = \$player; |
|
645
|
|
|
|
|
|
|
} |
|
646
|
|
|
|
|
|
|
else { |
|
647
|
|
|
|
|
|
|
$self->{resolve_cache}{$self->{teams}[$t]{name}}->{names} |
|
648
|
35
|
|
100
|
|
|
127
|
||= []; |
|
649
|
35
|
|
|
|
|
45
|
push(@{$self->{resolve_cache}{$self->{teams}[$t]{name}}->{names}}, \$player); |
|
|
35
|
|
|
|
|
81
|
|
|
650
|
|
|
|
|
|
|
} |
|
651
|
|
|
|
|
|
|
} |
|
652
|
|
|
|
|
|
|
} |
|
653
|
|
|
|
|
|
|
} |
|
654
|
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
sub process ($) { |
|
656
|
|
|
|
|
|
|
|
|
657
|
5
|
|
|
5
|
1
|
692
|
my $self = shift; |
|
658
|
|
|
|
|
|
|
|
|
659
|
5
|
|
|
|
|
34
|
$self->set_id_data($self->{json}{gamePk}); |
|
660
|
5
|
|
|
|
|
23
|
$self->set_timestamps($self->{json}); |
|
661
|
5
|
|
|
|
|
33
|
$self->set_extra_header_data($self->{json}); |
|
662
|
5
|
|
|
|
|
71
|
$self->set_periods($self->{json}); |
|
663
|
5
|
|
|
|
|
50
|
$self->set_officials($self->{json}{liveData}{boxscore}{officials}); |
|
664
|
5
|
|
|
|
|
55
|
$self->set_teams($self->{json}); |
|
665
|
5
|
50
|
|
|
|
9
|
if (@{$self->{json}{liveData}{plays}{allPlays}}) { |
|
|
5
|
|
|
|
|
32
|
|
|
666
|
5
|
|
|
|
|
40
|
$self->set_events($self->{json}{liveData}{plays}{allPlays}); |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
else { |
|
669
|
0
|
|
|
|
|
0
|
$BROKEN_FILES{$self->{_id}}->{BS} = $NO_EVENTS; |
|
670
|
0
|
|
|
|
|
0
|
$self->{events} = []; |
|
671
|
|
|
|
|
|
|
} |
|
672
|
5
|
|
|
|
|
29
|
$self->{type} = 'BS'; |
|
673
|
5
|
|
|
|
|
5644
|
delete $self->{json}; |
|
674
|
5
|
|
|
|
|
105
|
1; |
|
675
|
|
|
|
|
|
|
} |
|
676
|
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
1; |
|
678
|
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=head1 AUTHOR |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
More Hockey Stats, C<< >> |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=head1 BUGS |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
|
686
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
|
687
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
|
688
|
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
=head1 SUPPORT |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
perldoc Sport::Analytics::NHL::Report::BS |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
You can also look for information at: |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
=over 4 |
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
|
701
|
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
L |
|
703
|
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
|
705
|
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
L |
|
707
|
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=item * CPAN Ratings |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
L |
|
711
|
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=item * Search CPAN |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
L |
|
715
|
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=back |