@rasifix/orienteering-utils 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/kraemer.js DELETED
@@ -1,125 +0,0 @@
1
- var { parseTime, formatTime } = require('./time');
2
-
3
- function strip(str) {
4
- if (!str) {
5
- return '';
6
- } else if (str.length > 0 && str[0] === '"') {
7
- return str.substring(1, str.length - 1);
8
- } else {
9
- return str;
10
- }
11
- }
12
-
13
- // OE0014;Stnr;XStnr;Chipnr;Datenbank Id;Nachname;Vorname;Jg;G;Block; AK; Start;Ziel; Zeit; Wertung;Gutschrift -;Zuschlag +;Kommentar;Club-Nr.;Abk; Ort; Nat; Sitz;Region;Katnr;Kurz; Lang; MeldeKat. Nr;MeldeKat. (kurz);MeldeKat. (lang);Rang;Ranglistenpunkte;Num1;Num2; Num3; Text1; Text2; Text3; Adr. Nachname;Adr. Vorname;Straße;Zeile2;PLZ; Adr. Ort;Tel; Mobil; Fax; EMail; Gemietet;Startgeld;Bezahlt;Mannschaft;Bahnnummer;Bahn; km; Hm; Bahn Posten;Platz; Startstempel;Zielstempel;Posten1;Stempel1;Posten2;Stempel2;Posten3; Stempel3;Posten4;Stempel4;Posten5;Stempel5;Posten6;Stempel6;Posten7;Stempel7;Posten8;Stempel8;Posten9;Stempel9;Posten10;Stempel10;Posten11;Stempel11;Posten12;Stempel12;Posten13;Stempel13;Posten14;Stempel14;Posten15;Stempel15;Posten16;Stempel16;Posten17;Stempel17;Posten18;Stempel18;Posten19;Stempel19;Posten20;Stempel20;Posten21;Stempel21;Posten22;Stempel22;Posten23;Stempel23;Posten24;Stempel24;Posten25;Stempel25;Posten26;Stempel26;Posten27;Stempel27;Posten28;Stempel28;Posten29;Stempel29;Posten30;Stempel30;Posten31;Stempel31;Posten32;Stempel32;Posten33;Stempel33;Posten34;Stempel34;Posten35;Stempel35;Posten36;Stempel36;Posten37;Stempel37;Posten38;Stempel38;Posten39;Stempel39;Posten40;Stempel40;Posten41;Stempel41;Posten42;Stempel42;Posten43;Stempel43;Posten44;Stempel44;Posten45;Stempel45;Posten46;Stempel46;Posten47;Stempel47;Posten48;Stempel48;Posten49;Stempel49;Posten50;Stempel50;Posten51;Stempel51;Posten52;Stempel52;Posten53;Stempel53;Posten54;Stempel54;Posten55;Stempel55;Posten56;Stempel56;Posten57;Stempel57;Posten58;Stempel58;Posten59;Stempel59;Posten60;Stempel60;Posten61;Stempel61;Posten62;Stempel62;Posten63;Stempel63;Posten64;Stempel64;
14
- // Stnr ;Chip;Datenbank Id;Nachname;Vorname;Jg;G;Block;AK;Start;Ziel;Zeit; Wertung;Club-Nr.;Abk; Ort; Nat; Katnr; Kurz; Lang;Num1;Num2;Num3;Text1; Text2;Text3;Adr. Name;Straße; Zeile2; PLZ; Ort; Tel; Fax; EMail;Id/Verein;Gemietet;Startgeld;Bezahlt;Bahnnummer; Bahn; km; Hm; Bahn Posten;Pl; Startstempel;Zielstempel;Posten1;Stempel1;Posten2; Stempel2; Posten3;Stempel3; Posten4; Stempel4;Posten5;Stempel5;Posten6; Stempel6;Posten7; Stempel7; Posten8;Stempel8;Posten9;Stempel9;Posten10;Stempel10;(und weitere)...
15
- module.exports.parse = function(text, options = {}) {
16
- // split text into lines
17
- var lines = text.split('[\r\n]+');
18
-
19
- // extract header
20
- var header = lines[0].split(";");
21
- var firstTimeIdx;
22
-
23
- // trying to get hold of correct column indices
24
- var indices = { };
25
- indices['Nachname'] = header.indexOf('Nachname');
26
- indices['Vorname'] = header.indexOf('Vorname');
27
- indices['Jg'] = header.indexOf('Jg');
28
- indices['G'] = header.indexOf('G');
29
- indices['Datenbank Id'] = header.indexOf('Datenbank Id');
30
- indices['Abk'] = header.indexOf('Abk');
31
- indices['Club'] = header.indexOf('Ort');
32
- indices['Ort'] = header.indexOf('Adr. Ort');
33
- indices['Nat'] = header.indexOf('Nat');
34
- indices['Start'] = header.indexOf('Start');
35
- indices['Ziel'] = header.indexOf('Ziel');
36
- indices['Zeit'] = header.indexOf('Zeit');
37
- indices['Katnr'] = header.indexOf('Kurz');
38
- indices['Wertung'] = header.indexOf('Wertung');
39
- indices['Posten'] = header.indexOf('Bahn Posten');
40
- indices['km'] = header.indexOf('km');
41
- indices['hm'] = header.indexOf('Hm');
42
- firstTimeIdx = header.indexOf('Posten1');
43
-
44
- if (header[0] === 'OE0014') {
45
- indices['Chip'] = header.indexOf('Chipnr');
46
- } else {
47
- indices['Chip'] = header.indexOf('Chip');
48
- }
49
-
50
- lines = lines.slice(1);
51
-
52
- // the result object
53
- var categories = { };
54
-
55
- function objectify(cols) {
56
- var result = { };
57
- Object.keys(indices).forEach(function(key) {
58
- result[key] = cols[indices[key]];
59
- });
60
- return result;
61
- }
62
-
63
- lines.forEach(function(line) {
64
- var cols = line.split(";");
65
- var lineObj = objectify(cols);
66
-
67
- if (lineObj['Wertung'] !== '0') {
68
- return;
69
- }
70
-
71
- let runnerName = strip(lineObj['Nachname']);
72
- let runnerFirstname = strip(lineObj['Vorname']);
73
- var runner = {
74
- name: runnerName,
75
- firstName: runnerFirstname,
76
- fullName: [runnerFirstname, runnerName].join(' '),
77
- yearOfBirth: lineObj['Jg'],
78
- sex: strip(lineObj['G']),
79
- club: (strip(lineObj['Abk']) + ' ' + strip(lineObj['Club'])).trim(),
80
- city: strip(lineObj['Ort']),
81
- nation: strip(lineObj['Nat']),
82
- time: formatTime(parseTime(lineObj['Zeit'])),
83
- startTime: formatTime(parseTime(lineObj['Start'])),
84
- ecard: strip(lineObj['Chip']),
85
- splits: []
86
- };
87
-
88
- var category = categories[strip(lineObj['Katnr'])];
89
- if (typeof category === 'undefined') {
90
- category = {
91
- name: strip(lineObj['Katnr']),
92
- distance: parseInt(strip(lineObj['km']), 10) * 1000,
93
- ascent: strip(lineObj['hm']),
94
- controls: strip(lineObj['Posten']),
95
- runners: []
96
- };
97
- categories[category.name] = category;
98
- }
99
-
100
- var times = cols.slice(firstTimeIdx);
101
- for (var idx = 0; idx < parseInt(lineObj['Posten'], 10) * 2; idx += 2) {
102
- if (idx === times.length - 1) {
103
- continue;
104
- }
105
- runner.splits.push([times[idx], formatTime(parseTime(times[idx + 1]))]);
106
- }
107
- runner.course = runner.splits.map(function(split) { return split[0]; }).join(',');
108
-
109
- category.runners.push(runner);
110
- });
111
-
112
- return {
113
- name: options.event || 'Anonymous Event',
114
- map: options.map || 'Unknown Map',
115
- date: date || '',
116
- startTime: startTime || '',
117
- categories: Object.keys(categories).map(function(category) {
118
- return categories[category];
119
- })
120
- };
121
- };
122
-
123
- module.exports.formatCheck = function(text) {
124
- return text.substring(0, 6) === 'OE0014' || text.substring(0, 23) === 'Stnr;Chip;Datenbank Id;';
125
- };
package/lib/oware.js DELETED
@@ -1,105 +0,0 @@
1
- function parseCategory(row) {
2
- return {
3
- name: row[0],
4
- distance: parseInt(row[1], 10),
5
- ascent: parseInt(row[2], 10),
6
- controls: parseInt(row[3], 10),
7
- runners: []
8
- };
9
- }
10
-
11
- function parseRunner(row, category, id) {
12
- var headerLength = 15;
13
- var i;
14
-
15
- var splits = [];
16
- for (i = headerLength; i < row.length; i += 2) {
17
- splits.push({ 'code': row[i], 'time': row[i + 1] });
18
- }
19
-
20
- // split cleanup - detect two following splits with identical time
21
- // --> control not working properly; set 's' as split time (substitute)
22
- // going from back to front to catch several not working controls
23
- for (i = splits.length - 1; i > 0; i--) {
24
- if (splits[i].time === splits[i - 1].time && splits[i].time !== '-') {
25
- splits[i].time = 's';
26
- }
27
- }
28
-
29
- return {
30
- id: id,
31
- category: category,
32
- rank: row[0] ? parseInt(row[0]) : null,
33
- name: row[1],
34
- firstName: row[2],
35
- fullName: [row[2], row[1]].join(' '),
36
- yearOfBirth: row[3],
37
- sex: row[4],
38
- club: row[8],
39
- city: row[7],
40
- nation: row[9],
41
- time: row[12],
42
- startTime: row[13],
43
- ecard: row[11],
44
- splits: splits
45
- };
46
- }
47
-
48
- module.exports.parse = function(text) {
49
- // split text into lines
50
- var lines = text.trim().split(/[\r\n]+/);
51
-
52
- // throw away first row containing headers
53
- lines = lines.splice(1);
54
-
55
- // second row contains information about the event
56
- var header = lines[0].split(';');
57
-
58
- var event = {
59
- // row starts with a double slash
60
- name: header[0].substring(2, header[0].length),
61
- map: header[1],
62
- date: header[2],
63
- startTime: header[3],
64
- categories: [ ]
65
- };
66
-
67
- // throw a way the now parsed header
68
- lines = lines.splice(1);
69
-
70
- var category = null;
71
-
72
- let idx = 0;
73
- lines.filter(line => line.trim().length > 0).forEach(function(line) {
74
- var cols = line.split(';');
75
- if (cols.length === 4) {
76
- category = parseCategory(cols);
77
- event.categories.push(category);
78
- } else {
79
- category.runners.push(parseRunner(cols, category.name, ++idx));
80
- }
81
- });
82
-
83
- return event;
84
- };
85
-
86
- module.exports.serialize = function(event) {
87
- var result = '//Format: Rank;Name;Firstname;YearOfBirth;SexMF;FedNr;Zip;Town;Club;NationIOF;StartNr;eCardNr;RunTime;StartTime;FinishTime;CtrlCode;SplitTime; ...\n';
88
- result += '//' + [event.name, event.map, event.date, event.startTime, ''].join(';') + '\n';
89
-
90
- event.categories.forEach(function(category) {
91
- result += [category.name, category.distance, category.ascent, category.controls].join(';') + '\n';
92
- category.runners.forEach(function(runner) {
93
- result += [runner.rank, runner.name, runner.firstName, runner.yearOfBirth, runner.sex, '', runner.zip, runner.city, runner.club, runner.nation, '', runner.ecard, runner.time, runner.startTime, ''].join(';');
94
- result += ';' + runner.splits.map(function(split) {
95
- return split.code + ';' + split.time;
96
- }).join(';') + '\n';
97
- });
98
- });
99
-
100
- return result;
101
- };
102
-
103
- module.exports.formatCheck = function(text) {
104
- return text.substring(0, 8) === '//Format';
105
- };
package/lib/ranking.js DELETED
@@ -1,422 +0,0 @@
1
- const { parseTime, formatTime } = require('./time');
2
- const { reorganize } = require('./reorganize');
3
-
4
-
5
- function invalidTime(time) {
6
- return !time || time < 0;
7
- }
8
-
9
- function validTime(time) {
10
- return !invalidTime(time);
11
- }
12
-
13
- function sum(a1, a2) {
14
- return a1 + a2;
15
- }
16
-
17
- function defineCourses(runners) {
18
- let courses = { };
19
- runners.forEach(runner => {
20
- let course = defineCourse(runner);
21
- if (!courses[course]) {
22
- courses[course] = {
23
- code: course,
24
- runners: [ runner.id ]
25
- };
26
- } else {
27
- courses[course].runners.push(runner.id);
28
- }
29
- });
30
- return Object.keys(courses).map(key => courses[key]);
31
- }
32
-
33
- function defineCourse(runner) {
34
- return 'St,' + runner.splits.map(split => split.code).join(',');
35
- }
36
-
37
- function defineLegs(runners) {
38
- let result = { };
39
-
40
- runners.filter(runner => runner.splits.length > 0).forEach(runner => {
41
- runner.splits.forEach((split, idx) => {
42
- if (validTime(split.split)) {
43
- let from = idx === 0 ? 'St' : runner.splits[idx - 1].code;
44
- let code = from + '-' + split.code;
45
- addRunnerToLeg(result, code, runner, split.split);
46
- }
47
- });
48
- });
49
-
50
- return result;
51
- }
52
-
53
- function addRunnerToLeg(legs, code, runner, split) {
54
- let leg = legs[code];
55
- if (!leg) {
56
- leg = legs[code] = createLeg(code);
57
- }
58
-
59
- leg.runners.push({
60
- id: runner.id,
61
- fullName: runner.fullName,
62
- split: split
63
- });
64
- }
65
-
66
- function createLeg(code) {
67
- return {
68
- code: code,
69
- runners: []
70
- };
71
- }
72
-
73
- function defineRunners(runners) {
74
- return runners.map(function(runner) {
75
- return {
76
- id: runner.id,
77
- fullName: runner.fullName,
78
- time: runner.time,
79
- yearOfBirth: runner.yearOfBirth,
80
- city: runner.city,
81
- club: runner.club,
82
- splits: runner.splits.map(function(split, idx) {
83
- var splitTime = null;
84
- if (split.time === '-') {
85
- splitTime = '-';
86
- } else if (idx === 0) {
87
- splitTime = parseTime(split.time);
88
- } else {
89
- if (parseTime(split.time) === null || parseTime(runner.splits[idx - 1].time) === null) {
90
- splitTime = '-';
91
- } else {
92
- splitTime = parseTime(split.time) - parseTime(runner.splits[idx - 1].time);
93
- }
94
- }
95
-
96
- return {
97
- code: split.code,
98
- time: split.time,
99
- split: splitTime
100
- };
101
- })
102
- };
103
- });
104
- }
105
-
106
- /**
107
- * Define properties of each leg. After this method the leg structure will be enhanced as follows:
108
- *
109
- * - runners are sorted per split time per leg
110
- * - each leg has a property 'idealSplit' (ideal split time of this leg)
111
- * - each leg has a property 'fastestSplit'
112
- * - each runner entry of a leg is enhanced with 'splitBehind' and 'splitRank'
113
- *
114
- * @param {*} legs leg data structre (only split is relevant)
115
- */
116
- function defineLegProperties(legs) {
117
- Object.keys(legs).forEach(code => {
118
- let leg = legs[code];
119
- leg.runners.sort(function(r1, r2) {
120
- return r1.split - r2.split;
121
- });
122
-
123
- // calculate the ideal time: take up to 5 fastest on that leg
124
- let selected = leg.runners.slice(0, Math.min(leg.runners.length, 5)).map(runner => runner.split);
125
-
126
- // only if there are valid splits for this leg
127
- if (selected.length > 0) {
128
- leg.idealSplit = Math.round(selected.reduce(sum) / selected.length);
129
- }
130
-
131
- // only if there are valid splits for this leg
132
- if (leg.runners.length > 0) {
133
- leg.fastestSplit = leg.runners[0].split;
134
- leg.runners[0].splitBehind = '0:00';
135
- leg.runners.slice(1).forEach(runner => {
136
- runner.splitBehind = runner.split - leg.fastestSplit;
137
- });
138
-
139
- leg.runners[0].splitRank = 1;
140
- leg.runners.forEach((runner, idx, arr) => {
141
- if (idx > 0) {
142
- if (runner.split === arr[idx - 1].split) {
143
- runner.splitRank = arr[idx - 1].splitRank;
144
- } else {
145
- runner.splitRank = idx + 1;
146
- }
147
- runner.performanceIndex = Math.round(1.0 * leg.idealSplit / runner.split * 100);
148
- }
149
- });
150
- }
151
- });
152
- }
153
-
154
- /**
155
- * Calculates the weight of each leg regarding the passed in idealTime.
156
- *
157
- * @param {*} legs
158
- * @param {*} idealTime
159
- */
160
- function defineLegWeight(legs, idealTime) {
161
- Object.keys(legs).forEach((code) => {
162
- let leg = legs[code];
163
- leg.weight = leg.idealSplit / idealTime;
164
- });
165
- }
166
-
167
- function legCode(splits, idx) {
168
- if (idx === 0) {
169
- return 'St-' + splits[0].code;
170
- } else {
171
- return splits[idx - 1].code + '-' + splits[idx].code;
172
- }
173
- }
174
-
175
- /**
176
- * Assigns the following property to every valid leg of a runner.
177
- *
178
- * - splitBehind: how much time behind the faster runner
179
- * - splitRank: rank on corresponding leg
180
- * - leg: code of leg
181
- *
182
- * @param {*} runners
183
- * @param {*} legs
184
- */
185
- function assignLegInfoToSplits(runners, legs) {
186
- runners.forEach(runner => {
187
- runner.splits.filter(s => validTime(s.split)).forEach((split, idx) => {
188
- let code = legCode(runner.splits, idx);
189
- let leg = legs[code];
190
-
191
- if (!leg) {
192
- throw 'leg with code ' + code + ' not defined!';
193
- }
194
-
195
- split.leg = leg.code;
196
-
197
- let legRunner = leg.runners.find(r => r.id === runner.id);
198
-
199
- split.idealBehind = legRunner ? legRunner.split - leg.idealSplit : '-';
200
- split.supermanBehind = legRunner ? legRunner.split - leg.fastestSplit : '-';
201
- split.splitBehind = legRunner ? legRunner.splitBehind : '-';
202
- split.splitRank = legRunner ? legRunner.splitRank : null;
203
- split.performanceIndex = legRunner ? legRunner.performanceIndex : null;
204
- split.weight = leg.weight;
205
- });
206
- });
207
- }
208
-
209
- function rank(runners) {
210
- runners.forEach((runner, idx) => {
211
- if (idx === 0) {
212
- runner.rank = 1;
213
- } else {
214
- let prev = runners[idx - 1];
215
- if (prev.time === runner.time) {
216
- runner.rank = prev.rank;
217
- } else if (parseTime(runner.time)) {
218
- runner.rank = idx + 1;
219
- }
220
- }
221
- });
222
- }
223
-
224
- class RankingBuilder {
225
-
226
- constructor(runners) {
227
- runners.forEach((runner, idx) => {
228
- for (let i = 0; i < runner.splits.length; i++) {
229
- let split = runner.splits[i];
230
- if (i === 0 && validTime(split.time)) {
231
- split.split = parseTime(split.time);
232
- } else if (i > 0) {
233
- let previousSplit = runner.splits[i - 1];
234
- if (validTime(split.time) && validTime(previousSplit.time)) {
235
- split.split = parseTime(split.time) - parseTime(previousSplit.time);
236
- }
237
- }
238
- }
239
- });
240
-
241
- this.courses = defineCourses(runners);
242
- this.legs = defineLegs(runners);
243
- this.runners = defineRunners(runners);
244
-
245
- defineLegProperties(this.legs);
246
-
247
- // calculate the ideal time [s]
248
- this.idealTime = Object.keys(this.legs).map(code => this.legs[code].idealSplit).reduce(sum);
249
-
250
- // each leg's weight is calculated regarding as a ratio of the ideal split time to the ideal time
251
- defineLegWeight(this.legs, this.idealTime);
252
-
253
- // now assing the leg information (such as idealTime, weight, ...) to the individual splits of the runners
254
- assignLegInfoToSplits(this.runners, this.legs);
255
-
256
-
257
- this.runners.forEach(runner => {
258
- let behind = 0;
259
- let supermanBehind = 0;
260
- let weightSum = 0;
261
- runner.splits.forEach(split => {
262
- behind += split.idealBehind;
263
- supermanBehind += split.supermanBehind;
264
- split.overallIdealBehind = behind;
265
- split.overallSupermanBehind = supermanBehind;
266
- split.position = weightSum;
267
-
268
- weightSum += split.weight;
269
- });
270
- });
271
-
272
- // function of function calculating the time at an arbitrary position for a given runner
273
- let timeFn = (runner) => (pos) => {
274
- if (pos === 0) {
275
- return 0;
276
- } else if (pos >= 1) {
277
- return parseTime(runner.time);
278
- }
279
-
280
- let idx = 0;
281
- let weightSum = 0;
282
- for (idx = 0; idx < runner.splits.length; idx++) {
283
- let split = runner.splits[idx];
284
- if (weightSum + split.weight > pos) {
285
- break;
286
- }
287
- weightSum += split.weight;
288
- }
289
-
290
- let prev = runner.splits[idx - 1];
291
- let next = runner.splits[idx];
292
-
293
- let prevTime = parseTime(prev.time);
294
- let nextTime = parseTime(next.time);
295
- return prevTime + (pos - prev.position) / (next.position - prev.position) * (nextTime - prevTime);
296
- };
297
-
298
- let timesAtPosition = (pos) => {
299
- return this.runners.map(runner => { return { id: runner.id, time: timeFn(runner)(pos) }; });
300
- };
301
-
302
- this.runners.forEach(runner => {
303
- runner.splits.forEach(split => {
304
- let times = timesAtPosition(split.position + split.weight).filter(entry => entry.time !== null && entry.time > 0);
305
- times.sort((t1, t2) => t1.time - t2.time);
306
-
307
- let rank = 1;
308
- let fastestTime = times[0].time;
309
-
310
- let lastTime = parseTime(times[0].time);
311
- for (let idx = 0; idx < times.length; idx++) {
312
- let entry = times[idx];
313
-
314
- if (lastTime < parseTime(entry.time)) {
315
- rank = idx;
316
- }
317
-
318
- if (runner.id === entry.id) {
319
- split.overallRank = rank;
320
- split.overallBehind = formatTime(entry.time - fastestTime);
321
- break;
322
- }
323
- }
324
- });
325
- });
326
-
327
- console.log(this.runners[1]);
328
-
329
- // calculate the overall rank
330
- rank(this.runners);
331
- }
332
-
333
- getCourses() {
334
- return this.courses;
335
- }
336
-
337
- getLeg(code) {
338
- return this.legs[code];
339
- }
340
-
341
- getLegs() {
342
- return Object.keys(this.legs).map(code => this.legs[code]);
343
- }
344
-
345
- getRanking() {
346
- let runners = this.runners.map(runner => { return { ...runner } });
347
-
348
-
349
- /*
350
-
351
- for each runner we need the following function
352
-
353
- f(pos) => timeBehindIdeal
354
-
355
- using this function it will be possible to calculate the following properties
356
-
357
- f(runner, split) => {
358
- overallRank // the rank the current position
359
- idealBehind // time behind ideal
360
- }
361
-
362
- the first function
363
-
364
- */
365
- }
366
- }
367
-
368
- module.exports.RankingBuilder = RankingBuilder;
369
-
370
-
371
- /*
372
- /* depends on ordered courses!
373
- Object.keys(results.legs).forEach((code, idx) => {
374
- let leg = result.legs[code];
375
- if (idx === 0) {
376
- leg.fastestTime = formatTime(leg.fastestSplit);
377
- leg.idealTime = formatTime(leg.idealSplit);
378
- } else {
379
- leg.fastestTime = formatTime(parseTime(result.legs[idx - 1].fastestTime) + leg.fastestSplit);
380
- leg.idealTime = formatTime(parseTime(result.legs[idx - 1].idealTime) + leg.idealSplit);
381
- }
382
- });
383
-
384
- result.runners.forEach(function(runner) {
385
- // calculate overall time behind leader
386
- runner.splits.forEach(function(split, splitIdx) {
387
- if (!invalidTime(split.time)) {
388
- let leader = result.runners.map(function(r) {
389
- return {
390
- time: r.splits[splitIdx].time,
391
- rank: r.splits[splitIdx].overallRank
392
- };
393
- }).find(function(split) {
394
- return split.rank === 1;
395
- });
396
-
397
- // no leader for this leg?!
398
- if (leader) {
399
- let leaderTime = leader.time;
400
- if (parseTime(split.time) !== null) {
401
- split.overallBehind = formatTime(parseTime(split.time) - parseTime(leaderTime));
402
- split.fastestBehind = formatTime(parseTime(split.time) - parseTime(result.legs[splitIdx].fastestTime));
403
- split.idealBehind = formatTime(parseTime(split.time) - parseTime(result.legs[splitIdx].idealTime));
404
- } else {
405
- split.overallBehind = '-';
406
- split.fastestBehind = '-';
407
- split.idealBehind = '-';
408
- }
409
- }
410
- }
411
- });
412
-
413
- // performance index for split
414
- runner.splits.filter(split => split.split != '-' && split.split != 's' && split.split != '0:00').forEach(split => {
415
- let leg = findLeg(legs, split.leg);
416
- split.perfidx = Math.round(1.0 * leg.idealSplit / parseTime(split.split) * 100);
417
- });
418
- });
419
-
420
- return result;
421
- }
422
- */