line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Sport::Analytics::NHL::Report::BS; |
2
|
|
|
|
|
|
|
|
3
|
41
|
|
|
41
|
|
62314
|
use v5.10.1; |
|
41
|
|
|
|
|
203
|
|
4
|
41
|
|
|
41
|
|
177
|
use strict; |
|
41
|
|
|
|
|
117
|
|
|
41
|
|
|
|
|
860
|
|
5
|
41
|
|
|
41
|
|
174
|
use warnings FATAL => 'all'; |
|
41
|
|
|
|
|
82
|
|
|
41
|
|
|
|
|
1210
|
|
6
|
41
|
|
|
41
|
|
18024
|
use utf8; |
|
41
|
|
|
|
|
491
|
|
|
41
|
|
|
|
|
186
|
|
7
|
|
|
|
|
|
|
|
8
|
41
|
|
|
41
|
|
1158
|
use experimental qw(smartmatch); |
|
41
|
|
|
|
|
79
|
|
|
41
|
|
|
|
|
274
|
|
9
|
|
|
|
|
|
|
|
10
|
41
|
|
|
41
|
|
8402
|
use Encode; |
|
41
|
|
|
|
|
115070
|
|
|
41
|
|
|
|
|
2369
|
|
11
|
41
|
|
|
41
|
|
1646
|
use Storable qw(dclone); |
|
41
|
|
|
|
|
6919
|
|
|
41
|
|
|
|
|
1440
|
|
12
|
|
|
|
|
|
|
|
13
|
41
|
|
|
41
|
|
1524
|
use JSON; |
|
41
|
|
|
|
|
26142
|
|
|
41
|
|
|
|
|
265
|
|
14
|
41
|
|
|
41
|
|
9608
|
use Try::Tiny; |
|
41
|
|
|
|
|
22797
|
|
|
41
|
|
|
|
|
1768
|
|
15
|
41
|
|
|
41
|
|
16715
|
use Text::Unidecode; |
|
41
|
|
|
|
|
44843
|
|
|
41
|
|
|
|
|
1735
|
|
16
|
|
|
|
|
|
|
|
17
|
41
|
|
|
41
|
|
603
|
use parent 'Sport::Analytics::NHL::Report'; |
|
41
|
|
|
|
|
272
|
|
|
41
|
|
|
|
|
261
|
|
18
|
|
|
|
|
|
|
|
19
|
41
|
|
|
41
|
|
2265
|
use Sport::Analytics::NHL::Config; |
|
41
|
|
|
|
|
129
|
|
|
41
|
|
|
|
|
6406
|
|
20
|
41
|
|
|
41
|
|
258
|
use Sport::Analytics::NHL::Errors; |
|
41
|
|
|
|
|
72
|
|
|
41
|
|
|
|
|
6283
|
|
21
|
41
|
|
|
41
|
|
362
|
use Sport::Analytics::NHL::Tools; |
|
41
|
|
|
|
|
89
|
|
|
41
|
|
|
|
|
5307
|
|
22
|
41
|
|
|
41
|
|
299
|
use Sport::Analytics::NHL::Util; |
|
41
|
|
|
|
|
83
|
|
|
41
|
|
|
|
|
2187
|
|
23
|
|
|
|
|
|
|
|
24
|
41
|
|
|
41
|
|
230
|
use Data::Dumper; |
|
41
|
|
|
|
|
86
|
|
|
41
|
|
|
|
|
131583
|
|
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
|
42
|
my $class = shift; |
214
|
15
|
|
|
|
|
47
|
my $json = shift; |
215
|
|
|
|
|
|
|
|
216
|
15
|
|
|
|
|
257
|
my $code = JSON->new(); |
217
|
15
|
|
|
|
|
127
|
$code->utf8(1); |
218
|
15
|
|
|
|
|
30
|
my $self; |
219
|
15
|
50
|
|
|
|
61
|
return undef unless $json; |
220
|
15
|
|
|
15
|
|
1009
|
try { $self = {json => $code->decode(decode "UTF-8", $json)} } |
221
|
15
|
|
|
7
|
|
188
|
catch { $self = {json => $code->decode($json)} }; |
|
7
|
|
|
|
|
20060
|
|
222
|
|
|
|
|
|
|
return undef unless |
223
|
|
|
|
|
|
|
$self->{json}{gameData}{status}{abstractGameState} |
224
|
15
|
50
|
33
|
|
|
46785
|
&& $self->{json}{gameData}{status}{abstractGameState} eq 'Final'; |
225
|
15
|
|
|
|
|
52
|
bless $self, $class; |
226
|
|
|
|
|
|
|
|
227
|
15
|
|
|
|
|
142
|
$self; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub set_id_data ($$) { |
231
|
|
|
|
|
|
|
|
232
|
7
|
|
|
7
|
1
|
1383
|
my $self = shift; |
233
|
7
|
|
|
|
|
21
|
my $id_data = shift; |
234
|
|
|
|
|
|
|
|
235
|
7
|
|
|
|
|
36
|
my $season_info = parse_nhl_game_id($id_data); |
236
|
7
|
|
|
|
|
22
|
$self->{season} = $season_info->{season}; |
237
|
7
|
|
|
|
|
18
|
$self->{stage} = $season_info->{stage}; |
238
|
7
|
|
|
|
|
15
|
$self->{season_id} = $season_info->{season_id}; |
239
|
7
|
|
|
|
|
42
|
$self->{_id} = $self->{season} * 100000 + $self->{stage} * 10000 + $self->{season_id}; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub set_timestamps ($$) { |
243
|
|
|
|
|
|
|
|
244
|
6
|
|
|
6
|
1
|
14
|
my $self = shift; |
245
|
6
|
|
|
|
|
14
|
my $json = shift; |
246
|
|
|
|
|
|
|
|
247
|
6
|
|
|
|
|
14
|
my $ts = $json->{metaData}{timeStamp}; $ts =~ s/_/ /; |
|
6
|
|
|
|
|
38
|
|
248
|
6
|
|
|
|
|
34
|
$self->{last_updated} = str3time($ts); |
249
|
6
|
|
|
|
|
118
|
$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
|
|
|
|
44
|
: $self->{start_ts} + 9000; |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub set_extra_header_data ($$) { |
257
|
|
|
|
|
|
|
|
258
|
6
|
|
|
6
|
1
|
20
|
my $self = shift; |
259
|
6
|
|
|
|
|
10
|
my $json = shift; |
260
|
|
|
|
|
|
|
|
261
|
6
|
|
|
|
|
16
|
$self->{status} = 'FINAL'; |
262
|
6
|
|
|
|
|
18
|
$self->{location} = $json->{gameData}{venue}{name}; |
263
|
6
|
50
|
|
|
|
140
|
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
|
17
|
my $self = shift; |
274
|
6
|
|
|
|
|
10
|
my $officials = shift; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$self->{officials} = { |
277
|
6
|
|
|
|
|
28
|
referees => [], |
278
|
|
|
|
|
|
|
linesmen => [], |
279
|
|
|
|
|
|
|
}; |
280
|
6
|
|
|
|
|
11
|
for my $official (@{$officials}) { |
|
6
|
|
|
|
|
14
|
|
281
|
|
|
|
|
|
|
my $o = { |
282
|
|
|
|
|
|
|
name => unidecode(uc $official->{official}{fullName}), |
283
|
22
|
|
100
|
|
|
87
|
official_id => $official->{official}{id} || 0, |
284
|
|
|
|
|
|
|
}; |
285
|
|
|
|
|
|
|
push( |
286
|
22
|
|
|
|
|
317
|
@{$self->{officials}{ |
287
|
22
|
100
|
|
|
|
69
|
$official->{officialType} eq 'Referee' ? 'referees' : 'linesmen' |
288
|
|
|
|
|
|
|
}}, $o |
289
|
|
|
|
|
|
|
); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub set_broken_player ($$) { |
294
|
|
|
|
|
|
|
|
295
|
245
|
|
|
245
|
1
|
266
|
my $self = shift; |
296
|
245
|
|
|
|
|
260
|
my $player = shift; |
297
|
|
|
|
|
|
|
|
298
|
245
|
0
|
33
|
|
|
640
|
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
|
268
|
my $self = shift; |
314
|
245
|
|
|
|
|
267
|
my $ld_player = shift; |
315
|
|
|
|
|
|
|
|
316
|
245
|
100
|
100
|
|
|
488
|
unless ($ld_player->{stats}{skaterStats} || $ld_player->{stats}{goalieStats}) { |
317
|
|
|
|
|
|
|
$ld_player->{stats}{ |
318
|
25
|
50
|
|
|
|
76
|
$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
|
|
|
|
|
7710
|
%{dclone $ld_player->{stats}{skaterStats}} : |
328
|
245
|
100
|
50
|
|
|
466
|
%{dclone ($ld_player->{stats}{goalieStats} || {})}, |
|
12
|
|
|
|
|
408
|
|
329
|
|
|
|
|
|
|
}; |
330
|
245
|
0
|
33
|
|
|
960
|
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
|
|
|
469
|
$player->{pim} ||= ($player->{penaltyMinutes} || 0) if $player->{position} eq 'G'; |
|
|
|
33
|
|
|
|
|
338
|
245
|
|
|
|
|
504
|
$player; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub set_teams ($$) { |
342
|
|
|
|
|
|
|
|
343
|
6
|
|
|
6
|
1
|
17
|
my $self = shift; |
344
|
6
|
|
|
|
|
23
|
my $json = shift; |
345
|
|
|
|
|
|
|
|
346
|
6
|
|
|
|
|
16
|
$self->{teams} = []; |
347
|
|
|
|
|
|
|
$self->{_score} = [ |
348
|
|
|
|
|
|
|
$json->{liveData}{linescore}{teams}{away}{goals}, |
349
|
|
|
|
|
|
|
$json->{liveData}{linescore}{teams}{home}{goals}, |
350
|
6
|
|
|
|
|
41
|
]; |
351
|
6
|
|
|
|
|
11
|
my $t = 0; |
352
|
6
|
|
|
|
|
30
|
for my $team_key (qw(away home)) { |
353
|
12
|
|
|
|
|
31
|
$self->{_t} = $t; |
354
|
12
|
|
|
|
|
26
|
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
|
|
|
120
|
}; |
369
|
12
|
|
|
|
|
46
|
$team->{name} = resolve_team($team->{orig}); |
370
|
12
|
50
|
|
|
|
82
|
$team->{coach} = $BROKEN_COACHES{$team->{coach}} if $BROKEN_COACHES{$team->{coach}}; |
371
|
12
|
|
|
|
|
25
|
$self->{broken_number} = 101; |
372
|
12
|
|
|
|
|
16
|
for my $ld_player (values %{$ldb_team->{players}}) { |
|
12
|
|
|
|
|
45
|
|
373
|
|
|
|
|
|
|
my $player = |
374
|
245
|
|
33
|
|
|
432
|
$self->set_broken_player($ld_player->{person}{id}) || |
375
|
|
|
|
|
|
|
$self->set_player($ld_player); |
376
|
245
|
|
|
|
|
269
|
push(@{$team->{roster}}, $player); |
|
245
|
|
|
|
|
345
|
|
377
|
245
|
100
|
|
|
|
453
|
$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
|
|
|
43
|
&& @{$MISSING_PLAYERS{$self->{_id}}->[$t]}); |
|
0
|
|
|
|
|
0
|
|
384
|
12
|
50
|
|
|
|
31
|
$self->force_decision($team) unless $team->{_decision}; |
385
|
12
|
|
|
|
|
16
|
push(@{$self->{teams}}, $team); |
|
12
|
|
|
|
|
24
|
|
386
|
12
|
|
|
|
|
22
|
$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
|
51
|
my $self = shift; |
406
|
6
|
|
|
|
|
9
|
my $json = shift; |
407
|
|
|
|
|
|
|
|
408
|
6
|
|
|
|
|
16
|
$self->{periods} = []; |
409
|
6
|
|
|
|
|
13
|
my $p = 1; |
410
|
6
|
|
|
|
|
11
|
for my $ld_period (@{$json->{liveData}{linescore}{periods}}) { |
|
6
|
|
|
|
|
24
|
|
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
|
|
|
|
66
|
}; |
|
|
100
|
|
|
|
|
|
425
|
18
|
|
|
|
|
32
|
push(@{$self->{periods}}, $period); |
|
18
|
|
|
|
|
35
|
|
426
|
18
|
50
|
33
|
|
|
101
|
$self->{ot} ||= $ld_period->{periodType} eq 'OVERTIME' ? 1 : 0; |
427
|
18
|
|
|
|
|
33
|
$p++; |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
sub place_players ($$) { |
432
|
|
|
|
|
|
|
|
433
|
756
|
|
|
756
|
1
|
844
|
my $event = shift; |
434
|
756
|
|
|
|
|
759
|
my $ld_event = shift; |
435
|
|
|
|
|
|
|
|
436
|
756
|
|
|
|
|
762
|
for my $player (@{$ld_event->{players}}) { |
|
756
|
|
|
|
|
1320
|
|
437
|
1537
|
|
|
|
|
4616
|
$event->{$PLAYER_ID_MAP{$player->{playerType}}} = $player->{player}{id}; |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub assign_specific_penalty_data ($$) { |
442
|
|
|
|
|
|
|
|
443
|
100
|
|
|
100
|
1
|
115
|
my $event = shift; |
444
|
100
|
|
|
|
|
111
|
my $ld_event = shift; |
445
|
|
|
|
|
|
|
|
446
|
100
|
|
|
|
|
183
|
place_players($event, $ld_event); |
447
|
100
|
|
|
|
|
188
|
$event->{penalty} = $ld_event->{result}{secondaryType}; |
448
|
100
|
|
100
|
|
|
282
|
$event->{severity} = uc($ld_event->{result}{penaltySeverity} || ''); |
449
|
100
|
|
|
|
|
154
|
$event->{length} = $ld_event->{result}{penaltyMinutes}; |
450
|
100
|
50
|
33
|
|
|
259
|
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
|
|
|
634
|
if ($event->{penalty} =~ /too many/i || $event->{description} =~ /^\s+against/i) { |
|
|
50
|
|
|
|
|
|
455
|
5
|
50
|
33
|
|
|
66
|
$event->{servedby} ||= $event->{player1} if $event->{player1}; |
456
|
5
|
|
|
|
|
11
|
$event->{player1} = $BENCH_PLAYER_ID; |
457
|
5
|
|
|
|
|
24
|
$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
|
|
|
|
|
241
|
$event->{penalty} = normalize_penalty($event->{penalty}); |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
sub assign_specific_goal_data ($$) { |
468
|
|
|
|
|
|
|
|
469
|
26
|
|
|
26
|
1
|
47
|
my $event = shift; |
470
|
26
|
|
|
|
|
36
|
my $ld_event = shift; |
471
|
|
|
|
|
|
|
|
472
|
26
|
|
|
|
|
62
|
place_players($event, $ld_event); |
473
|
|
|
|
|
|
|
$event->{assists} = [ map { |
474
|
102
|
100
|
|
|
|
197
|
$_->{playerType} eq 'Assist' ? $_->{player}{id} : (), |
475
|
26
|
|
|
|
|
37
|
} @{$ld_event->{players}} ]; |
|
26
|
|
|
|
|
49
|
|
476
|
26
|
|
100
|
|
|
99
|
$event->{shot_type} = vocabulary_lookup('shot_type', $ld_event->{result}{secondaryType} || ''); |
477
|
26
|
|
|
|
|
71
|
$event->{en} = $ld_event->{result}{emptyNet}; |
478
|
26
|
|
|
|
|
62
|
$event->{gwg} = $ld_event->{result}{gameWinningGoal}; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sub assign_specific_event_data ($$) { |
482
|
|
|
|
|
|
|
|
483
|
1616
|
|
|
1616
|
1
|
1792
|
my $event = shift; |
484
|
1616
|
|
|
|
|
1650
|
my $ld_event = shift; |
485
|
|
|
|
|
|
|
|
486
|
1616
|
|
|
|
|
2243
|
for ($event->{type}) { |
487
|
1616
|
|
|
|
|
2708
|
when ('FAC') { |
488
|
325
|
|
|
|
|
369
|
for my $player (@{$ld_event->{players}}) { |
|
325
|
|
|
|
|
556
|
|
489
|
650
|
|
|
|
|
1906
|
$event->{$PLAYER_ID_MAP{$player->{playerType}}} = $player->{player}{id}; |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
$event->{winning_team} = $ld_event->{team}{triCode}, |
492
|
325
|
|
|
|
|
771
|
} |
493
|
1291
|
|
|
|
|
1460
|
when ('GIVE') { $event->{player1} = $ld_event->{players}[0]{player}{id}; } |
|
50
|
|
|
|
|
188
|
|
494
|
1241
|
|
|
|
|
1320
|
when ('TAKE') { $event->{player1} = $ld_event->{players}[0]{player}{id}; } |
|
45
|
|
|
|
|
205
|
|
495
|
1196
|
|
|
|
|
1266
|
when ('MISS') { |
496
|
160
|
|
|
|
|
477
|
$event->{player1} = $ld_event->{players}[0]{player}{id}; |
497
|
160
|
|
|
|
|
496
|
$event->{description} =~ /\- (.*)/; |
498
|
160
|
|
50
|
|
|
558
|
$event->{miss} = vocabulary_lookup('miss', $1 || ''); |
499
|
|
|
|
|
|
|
} |
500
|
1036
|
|
|
|
|
1152
|
when ('STOP') { $event->{stopreason} = [ vocabulary_lookup('stopreason', $event->{description})] } |
|
245
|
|
|
|
|
435
|
|
501
|
791
|
|
|
|
|
839
|
when ('HIT') { place_players($event, $ld_event); } |
|
160
|
|
|
|
|
281
|
|
502
|
631
|
|
|
|
|
697
|
when ('BLOCK') { |
503
|
155
|
|
|
|
|
333
|
place_players($event, $ld_event); |
504
|
155
|
|
|
|
|
214
|
my $x = $event->{player2}; |
505
|
155
|
|
|
|
|
195
|
$event->{player2} = $event->{player1}; |
506
|
155
|
|
|
|
|
235
|
$event->{player1} = $x; |
507
|
|
|
|
|
|
|
} |
508
|
476
|
|
|
|
|
540
|
when ('SHOT') { |
509
|
315
|
|
|
|
|
596
|
place_players($event, $ld_event); |
510
|
315
|
|
50
|
|
|
866
|
$event->{shot_type} = vocabulary_lookup('shot_type', $ld_event->{result}{secondaryType} || ''); |
511
|
|
|
|
|
|
|
} |
512
|
161
|
|
|
|
|
191
|
when ('PENL') { assign_specific_penalty_data($event, $ld_event); } |
|
100
|
|
|
|
|
180
|
|
513
|
61
|
|
|
|
|
83
|
when ('GOAL') { assign_specific_goal_data($event, $ld_event); } |
|
26
|
|
|
|
|
72
|
|
514
|
|
|
|
|
|
|
} |
515
|
1616
|
|
|
|
|
2221
|
delete $event->{void}; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub check_broken ($$) { |
519
|
|
|
|
|
|
|
|
520
|
1616
|
|
|
1616
|
1
|
1663
|
my $event = shift; |
521
|
1616
|
|
|
|
|
1585
|
my $ld_event = shift; |
522
|
|
|
|
|
|
|
|
523
|
1616
|
50
|
33
|
|
|
5531
|
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
|
1727
|
my $event = shift; |
536
|
|
|
|
|
|
|
|
537
|
1616
|
50
|
100
|
|
|
2779
|
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
|
1734
|
my $self = shift; |
566
|
1616
|
|
|
|
|
1668
|
my $event = shift; |
567
|
|
|
|
|
|
|
|
568
|
1616
|
50
|
66
|
|
|
2919
|
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
|
|
|
|
|
11
|
my $events = shift; |
590
|
|
|
|
|
|
|
|
591
|
6
|
|
|
|
|
16
|
$self->{events} = []; |
592
|
|
|
|
|
|
|
|
593
|
6
|
|
|
|
|
14
|
for my $ld_event (@{$events}) { |
|
6
|
|
|
|
|
17
|
|
594
|
|
|
|
|
|
|
next if $BROKEN_EVENTS{BS}->{$self->{_id}}->{$ld_event->{about}{eventIdx}} && |
595
|
1651
|
50
|
33
|
|
|
5199
|
$BROKEN_EVENTS{BS}->{$self->{_id}}->{$ld_event->{about}{eventIdx}} eq '-1'; |
596
|
1651
|
100
|
|
|
|
2188
|
next if grep { $_ eq $ld_event->{result}{eventTypeId} } @JS_IGNORED_EVENT_TYPES; |
|
13208
|
|
|
|
|
18288
|
|
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
|
|
|
4289
|
) : (), |
|
|
50
|
50
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
617
|
|
|
|
|
|
|
}; |
618
|
1616
|
100
|
|
|
|
7680
|
$event->{time} = substr($event->{time}, 1) if $event->{time} =~ /^0/; |
619
|
|
|
|
|
|
|
$event->{special} = 1 |
620
|
1616
|
50
|
33
|
|
|
3310
|
if $SPECIAL_EVENTS{$self->{_id}} && $SPECIAL_EVENTS{$self->{_id}}->{$ld_event->{about}{eventIdx}}; |
621
|
1616
|
|
|
|
|
3036
|
assign_specific_event_data($event, $ld_event); |
622
|
1616
|
|
|
|
|
3223
|
$self->fix_old_goalie($event); |
623
|
1616
|
|
|
|
|
2864
|
check_broken($event, $ld_event); |
624
|
1616
|
|
|
|
|
2748
|
fix_servedby($event); |
625
|
1616
|
|
|
|
|
1610
|
push(@{$self->{events}}, $event); |
|
1616
|
|
|
|
|
3539
|
|
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
sub build_resolve_cache ($) { |
630
|
|
|
|
|
|
|
|
631
|
8
|
|
|
8
|
1
|
14899
|
my $self = shift; |
632
|
|
|
|
|
|
|
|
633
|
8
|
|
|
|
|
30
|
$self->{resolve_cache} = {}; |
634
|
8
|
|
|
|
|
25
|
for my $t (0,1) { |
635
|
16
|
|
|
|
|
26
|
my $unknown_number = 100; |
636
|
16
|
|
|
331
|
|
62
|
$self->{teams}[$t]{roster} = [ my_uniq { $_->{_id} } @{$self->{teams}[$t]{roster}} ]; |
|
331
|
|
|
|
|
853
|
|
|
16
|
|
|
|
|
86
|
|
637
|
16
|
|
|
|
|
65
|
for my $player (@{$self->{teams}[$t]{roster}}) { |
|
16
|
|
|
|
|
52
|
|
638
|
331
|
100
|
|
|
|
479
|
if (! $player->{broken}) { |
639
|
296
|
100
|
|
|
|
423
|
$player->{penaltyMinutes} = delete $player->{pim} if defined $player->{pim}; |
640
|
296
|
|
33
|
|
|
417
|
$player->{number} ||= $unknown_number++; |
641
|
296
|
|
|
|
|
540
|
while ($self->{resolve_cache}{$self->{teams}[$t]{name}}->{$player->{number}}) { |
642
|
0
|
|
|
|
|
0
|
$player->{number} += 100; |
643
|
|
|
|
|
|
|
} |
644
|
296
|
|
|
|
|
619
|
$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
|
|
|
154
|
||= []; |
649
|
35
|
|
|
|
|
42
|
push(@{$self->{resolve_cache}{$self->{teams}[$t]{name}}->{names}}, \$player); |
|
35
|
|
|
|
|
75
|
|
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
sub process ($) { |
656
|
|
|
|
|
|
|
|
657
|
5
|
|
|
5
|
1
|
643
|
my $self = shift; |
658
|
|
|
|
|
|
|
|
659
|
5
|
|
|
|
|
36
|
$self->set_id_data($self->{json}{gamePk}); |
660
|
5
|
|
|
|
|
22
|
$self->set_timestamps($self->{json}); |
661
|
5
|
|
|
|
|
27
|
$self->set_extra_header_data($self->{json}); |
662
|
5
|
|
|
|
|
66
|
$self->set_periods($self->{json}); |
663
|
5
|
|
|
|
|
27
|
$self->set_officials($self->{json}{liveData}{boxscore}{officials}); |
664
|
5
|
|
|
|
|
45
|
$self->set_teams($self->{json}); |
665
|
5
|
50
|
|
|
|
8
|
if (@{$self->{json}{liveData}{plays}{allPlays}}) { |
|
5
|
|
|
|
|
23
|
|
666
|
5
|
|
|
|
|
30
|
$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
|
|
|
|
|
22
|
$self->{type} = 'BS'; |
673
|
5
|
|
|
|
|
4798
|
delete $self->{json}; |
674
|
5
|
|
|
|
|
80
|
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 |