@rasifix/orienteering-utils 1.0.6 → 2.0.1
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/package.json +16 -4
- package/index.d.ts +0 -4
- package/index.js +0 -11
- package/lib/anonymizer.js +0 -72
- package/lib/butterfly.js +0 -59
- package/lib/kraemer.js +0 -125
- package/lib/oware.js +0 -105
- package/lib/ranking.js +0 -422
- package/lib/reorganize.js +0 -212
- package/lib/solv.js +0 -124
- package/lib/time.js +0 -45
- package/test/butterfly-oware.csv +0 -120
- package/test/oware-test.js +0 -82
- package/test/oware.csv +0 -101
- package/test/ranking-test.js +0 -102
- package/test/solv-test.js +0 -68
- package/test/solv.csv +0 -1833
- package/test/test.js +0 -11
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rasifix/orienteering-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "utility functions for orienteering result analyzis",
|
|
5
|
-
"main": "index",
|
|
6
|
-
"
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib/**/*.js",
|
|
9
|
+
"lib/**/*.d.ts"
|
|
10
|
+
],
|
|
7
11
|
"scripts": {
|
|
8
|
-
"test": "mocha test/test.js"
|
|
12
|
+
"test": "mocha test/test.js",
|
|
13
|
+
"build": "tsc"
|
|
9
14
|
},
|
|
10
15
|
"keywords": [
|
|
11
16
|
"orienteering"
|
|
@@ -19,5 +24,12 @@
|
|
|
19
24
|
"dependencies": {
|
|
20
25
|
"chai": "^4.3.6",
|
|
21
26
|
"mocha": "^9.2.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/chai": "^5.2.3",
|
|
30
|
+
"@types/mocha": "^10.0.10",
|
|
31
|
+
"@types/node": "^16.0.2",
|
|
32
|
+
"ts-node": "^10.9.2",
|
|
33
|
+
"typescript": "^4.5.5"
|
|
22
34
|
}
|
|
23
35
|
}
|
package/index.d.ts
DELETED
package/index.js
DELETED
package/lib/anonymizer.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
const names = [
|
|
2
|
-
'Gustavson', 'Hendrikson', 'Meyer', 'Marlovic', 'Torres', 'Huber',
|
|
3
|
-
'Wüst', 'Zürcher', 'Berner', 'Rufer', 'Gutmann', 'Hübscher',
|
|
4
|
-
'Schneller', 'Widemar', 'Rohrer', 'Kunz', 'Kinzle', 'Steinle',
|
|
5
|
-
'Allemann', 'Röhrig', 'Meyer', 'Uhlmann', 'Garaio', 'Regazoni',
|
|
6
|
-
'Maudet', 'Zoja'
|
|
7
|
-
];
|
|
8
|
-
|
|
9
|
-
const firstNames = {
|
|
10
|
-
f: [
|
|
11
|
-
'Anna', 'Alia', 'Ava', 'Berta', 'Benita', 'Carla', 'Cloe',
|
|
12
|
-
'Dina', 'Daria', 'Eva', 'Esther', 'Elin', 'Franca', 'Franziska',
|
|
13
|
-
'Gaby', 'Gerta', 'Gudrun', 'Hanna', 'Isabel', 'Ilda', 'Kim', 'Kathrin',
|
|
14
|
-
'Lia', 'Lisa', 'Lena', 'Liselotte', 'Lara', 'Mia', 'Marla', 'Nele', 'Olga',
|
|
15
|
-
'Pia', 'Rahel', 'Sara', 'Simona', 'Sina', 'Siri', 'Xenia', 'Zoé'
|
|
16
|
-
],
|
|
17
|
-
m: [
|
|
18
|
-
'Albert', 'Bruno', 'Chris', 'Dirk', 'David', 'Erwin', 'Francesco',
|
|
19
|
-
'Fritz', 'Gianni', 'Gustav', 'Hans', 'Ian', 'Jan', 'Karl', 'Lars',
|
|
20
|
-
'Martin', 'Marco', 'Markus', 'Nico', 'Nino', 'Otto', 'Olav',
|
|
21
|
-
'Patric', 'Pablo', 'Quentin', 'Ralf', 'Rudolf', 'Simon', 'Steve',
|
|
22
|
-
'Thomas', 'Tim', 'Urs', 'Udo'
|
|
23
|
-
]
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const cities = [
|
|
27
|
-
'Aarberg', 'Bern', 'Colombier', 'Diemerswil', 'Elm', 'Fribourg',
|
|
28
|
-
'Goldiwil', 'Heimiswil', 'Illiswil', 'Konolfingen', 'Lausanne',
|
|
29
|
-
'Lugano', 'Martigny', 'Neuchatel', 'Orbe', 'Zürich'
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const clubs = {
|
|
33
|
-
prefixes: [ 'OLG', 'OLV', 'OL', 'CA' ],
|
|
34
|
-
names: ['Bernstein', 'Erdmannlistein', 'Blanc', 'Piz Balü', 'Bartli und Most', 'Aare', 'Reuss' ]
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
function random(arr) {
|
|
38
|
-
if (arr.lenght === 0) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
const idx = Math.floor(Math.random() * (arr.length - 1));
|
|
42
|
-
return arr[idx];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function randInt(from, to) {
|
|
46
|
-
return from + Math.round(Math.random() * (to - from));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
module.exports.anonymize = function(event) {
|
|
50
|
-
event.categories.forEach(category => {
|
|
51
|
-
category.runners.forEach(runner => {
|
|
52
|
-
runner.name = random(names);
|
|
53
|
-
|
|
54
|
-
if (runner.sex === 'M' || runner.sex === 'm') {
|
|
55
|
-
runner.firstName = random(firstNames.m);
|
|
56
|
-
runner.sex = 'M';
|
|
57
|
-
} else {
|
|
58
|
-
runner.firstName = random(firstNames.f);
|
|
59
|
-
runner.sex = 'F';
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
runner.fullName = runner.firstName + ' ' + runner.name;
|
|
63
|
-
|
|
64
|
-
runner.city = random(cities);
|
|
65
|
-
runner.club = random(clubs.prefixes) + ' ' + random(clubs.names);
|
|
66
|
-
runner.yearOfBirth = randInt(1925, 2010);
|
|
67
|
-
runner.nation = 'SUI';
|
|
68
|
-
runner.ecard = Math.round(Math.random() * 1000000);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
return event;
|
|
72
|
-
};
|
package/lib/butterfly.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
function extractCourses(category) {
|
|
2
|
-
var courses = { };
|
|
3
|
-
category.runners.forEach(function(runner) {
|
|
4
|
-
const course = runner.splits.map(function(split, index, splits) {
|
|
5
|
-
return split.code;
|
|
6
|
-
});
|
|
7
|
-
const key = 'St-' + course.join('-');
|
|
8
|
-
if (!courses[key]) {
|
|
9
|
-
courses[key] = {
|
|
10
|
-
runners: [],
|
|
11
|
-
controls: course.map(function(c) {
|
|
12
|
-
return { code: c };
|
|
13
|
-
})
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
courses[key].runners.push(runner);
|
|
17
|
-
});
|
|
18
|
-
const coursesArray = Object.keys(courses).map(function(course) {
|
|
19
|
-
return courses[course];
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
for (var i = 0; i < coursesArray[0].controls.length; i++) {
|
|
23
|
-
const base = coursesArray[0].controls[i].code;
|
|
24
|
-
const shared = coursesArray.every(function(course) {
|
|
25
|
-
return course.controls[i].code === base;
|
|
26
|
-
});
|
|
27
|
-
coursesArray.forEach(function(course) {
|
|
28
|
-
course.controls[i].shared = shared;
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return coursesArray;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
module.exports.extractCourses = extractCourses;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* A category is classified as "fair" if all the runners have the exact same legs, although
|
|
39
|
-
* potentially in different order.
|
|
40
|
-
*/
|
|
41
|
-
module.exports.isFair = function(category) {
|
|
42
|
-
const courses = extractCourses(category);
|
|
43
|
-
const courseLegs = courses.map(function(course) {
|
|
44
|
-
const legs = [];
|
|
45
|
-
for (var i = 0; i < course.controls.length - 1; i++) {
|
|
46
|
-
const from = course.controls[i].code;
|
|
47
|
-
const to = course.controls[i + 1].code;
|
|
48
|
-
legs.push(from + '-' + to);
|
|
49
|
-
}
|
|
50
|
-
return legs.sort().join(':');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const grouped = { };
|
|
54
|
-
courseLegs.forEach(function(course) {
|
|
55
|
-
grouped[course] = true;
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return Object.keys(grouped).length === 1;
|
|
59
|
-
};
|
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
|
-
};
|