@rasifix/orienteering-utils 2.0.0 → 2.0.2
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/format.d.ts +6 -0
- package/lib/format.js +2 -0
- package/{src/formats/index.ts → lib/formats/index.d.ts} +1 -6
- package/lib/formats/index.js +9 -0
- package/lib/formats/kraemer.d.ts +14 -0
- package/lib/formats/kraemer.js +131 -0
- package/lib/formats/oware.d.ts +7 -0
- package/lib/formats/oware.js +129 -0
- package/lib/formats/solv.d.ts +14 -0
- package/lib/formats/solv.js +151 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -0
- package/{src/model/category.ts → lib/model/category.d.ts} +1 -2
- package/lib/model/category.js +2 -0
- package/{src/model/competition.ts → lib/model/competition.d.ts} +1 -2
- package/lib/model/competition.js +2 -0
- package/lib/model/ranking.d.ts +27 -0
- package/{src/model/ranking.ts → lib/model/ranking.js} +6 -37
- package/lib/model/runner.d.ts +21 -0
- package/lib/model/runner.js +8 -0
- package/{src/model/split.ts → lib/model/split.d.ts} +2 -2
- package/lib/model/split.js +2 -0
- package/lib/time.d.ts +10 -0
- package/{src/time.ts → lib/time.js} +22 -18
- package/lib/utils/anonymizer.d.ts +2 -0
- package/{src/utils/anonymizer.ts → lib/utils/anonymizer.js} +22 -28
- package/lib/utils/ranking.d.ts +71 -0
- package/lib/utils/ranking.js +383 -0
- package/package.json +9 -5
- package/lib/analyzis.js +0 -25
- package/src/format.ts +0 -11
- package/src/formats/kraemer.ts +0 -145
- package/src/formats/oware.ts +0 -143
- package/src/formats/solv.ts +0 -169
- package/src/index.ts +0 -5
- package/src/model/runner.ts +0 -23
- package/src/utils/ranking.ts +0 -535
- package/src/utils/reorganize.ts +0 -212
- package/test/butterfly-oware.csv +0 -120
- package/test/kraemer-test.ts +0 -78
- package/test/kraemer.csv +0 -130
- package/test/oware-test.ts +0 -79
- package/test/oware.csv +0 -101
- package/test/ranking-test.ts +0 -55
- package/test/solv-test.ts +0 -65
- package/test/solv.csv +0 -1833
- package/test/test.js +0 -14
- package/tsconfig.json +0 -11
package/lib/format.d.ts
ADDED
package/lib/format.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.solv = exports.oware = exports.kraemer = void 0;
|
|
4
|
+
var kraemer = require("./kraemer");
|
|
5
|
+
exports.kraemer = kraemer;
|
|
6
|
+
var oware = require("./oware");
|
|
7
|
+
exports.oware = oware;
|
|
8
|
+
var solv = require("./solv");
|
|
9
|
+
exports.solv = solv;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Format } from "../format";
|
|
2
|
+
import { Category } from "../model/category";
|
|
3
|
+
import { Competition } from "../model/competition";
|
|
4
|
+
export declare class KraemerFormater implements Format {
|
|
5
|
+
parse(text: string, options?: any): {
|
|
6
|
+
name: any;
|
|
7
|
+
map: any;
|
|
8
|
+
date: any;
|
|
9
|
+
startTime: any;
|
|
10
|
+
categories: Category[];
|
|
11
|
+
};
|
|
12
|
+
check(text: string): boolean;
|
|
13
|
+
serialize(competition: Competition): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KraemerFormater = void 0;
|
|
4
|
+
var time_1 = require("../time");
|
|
5
|
+
function strip(str) {
|
|
6
|
+
if (!str) {
|
|
7
|
+
return "";
|
|
8
|
+
}
|
|
9
|
+
else if (str.length > 0 && str[0] === '"') {
|
|
10
|
+
return str.substring(1, str.length - 1);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
return str;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
var KraemerFormater = /** @class */ (function () {
|
|
17
|
+
function KraemerFormater() {
|
|
18
|
+
}
|
|
19
|
+
// 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;
|
|
20
|
+
// 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)...
|
|
21
|
+
KraemerFormater.prototype.parse = function (text, options) {
|
|
22
|
+
if (options === void 0) { options = {}; }
|
|
23
|
+
// split text into lines
|
|
24
|
+
var lines = text.split(/\r?\n|\r|\n/g);
|
|
25
|
+
// extract header
|
|
26
|
+
var header = lines[0].split(";");
|
|
27
|
+
var firstTimeIdx;
|
|
28
|
+
// trying to get hold of correct column indices
|
|
29
|
+
var indices = {};
|
|
30
|
+
indices["Melde Id"] = header.indexOf("Melde Id");
|
|
31
|
+
indices["Nachname"] = header.indexOf("Nachname");
|
|
32
|
+
indices["Vorname"] = header.indexOf("Vorname");
|
|
33
|
+
indices["Jg"] = header.indexOf("Jg");
|
|
34
|
+
indices["G"] = header.indexOf("G");
|
|
35
|
+
indices["Datenbank Id"] = header.indexOf("Datenbank Id");
|
|
36
|
+
indices["Abk"] = header.indexOf("Abk");
|
|
37
|
+
indices["Club"] = header.indexOf("Ort");
|
|
38
|
+
indices["Ort"] = header.indexOf("Adr. Ort");
|
|
39
|
+
indices["Nat"] = header.indexOf("Nat");
|
|
40
|
+
indices["Start"] = header.indexOf("Start");
|
|
41
|
+
indices["Ziel"] = header.indexOf("Ziel");
|
|
42
|
+
indices["Zeit"] = header.indexOf("Zeit");
|
|
43
|
+
indices["Katnr"] = header.indexOf("Kurz");
|
|
44
|
+
indices["Rang"] = header.indexOf("Rang");
|
|
45
|
+
indices["Wertung"] = header.indexOf("Wertung");
|
|
46
|
+
indices["Posten"] = header.indexOf("Bahn Posten");
|
|
47
|
+
indices["km"] = header.indexOf("km");
|
|
48
|
+
indices["hm"] = header.indexOf("Hm");
|
|
49
|
+
firstTimeIdx = header.indexOf("Posten1");
|
|
50
|
+
if (header[0] === "OE0014") {
|
|
51
|
+
indices["Chip"] = header.indexOf("Chipnr");
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
indices["Chip"] = header.indexOf("Chip");
|
|
55
|
+
}
|
|
56
|
+
lines = lines.slice(1);
|
|
57
|
+
// the result object
|
|
58
|
+
var categories = {};
|
|
59
|
+
function objectify(cols) {
|
|
60
|
+
var result = {};
|
|
61
|
+
Object.keys(indices).forEach(function (key) {
|
|
62
|
+
result[key] = cols[indices[key]];
|
|
63
|
+
});
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
lines.forEach(function (line) {
|
|
67
|
+
var cols = line.split(";");
|
|
68
|
+
var lineObj = objectify(cols);
|
|
69
|
+
if (lineObj["Wertung"] !== "0") {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
var categoryName = strip(lineObj["Katnr"]);
|
|
73
|
+
var runnerName = strip(lineObj["Nachname"]);
|
|
74
|
+
var runnerFirstname = strip(lineObj["Vorname"]);
|
|
75
|
+
var runTime = (0, time_1.parseTime)(lineObj["Zeit"]);
|
|
76
|
+
var startTime = (0, time_1.parseTime)(lineObj["Start"]);
|
|
77
|
+
var runner = {
|
|
78
|
+
id: lineObj["Melde Id"],
|
|
79
|
+
category: categoryName,
|
|
80
|
+
firstName: runnerFirstname,
|
|
81
|
+
name: runnerName,
|
|
82
|
+
fullName: [runnerFirstname, runnerName].join(" "),
|
|
83
|
+
yearOfBirth: lineObj["Jg"],
|
|
84
|
+
club: (strip(lineObj["Abk"]) + " " + strip(lineObj["Club"])).trim(),
|
|
85
|
+
city: strip(lineObj["Ort"]),
|
|
86
|
+
nation: strip(lineObj["Nat"]),
|
|
87
|
+
time: (0, time_1.formatTime)(runTime) || "",
|
|
88
|
+
startTime: (0, time_1.formatTime)(startTime) || "",
|
|
89
|
+
splits: [],
|
|
90
|
+
};
|
|
91
|
+
var category = categories[categoryName];
|
|
92
|
+
if (typeof category === "undefined") {
|
|
93
|
+
category = {
|
|
94
|
+
name: strip(lineObj["Katnr"]),
|
|
95
|
+
distance: parseInt(strip(lineObj["km"]), 10) * 1000,
|
|
96
|
+
ascent: parseInt(strip(lineObj["hm"])),
|
|
97
|
+
controls: parseInt(strip(lineObj["Posten"])),
|
|
98
|
+
runners: [],
|
|
99
|
+
};
|
|
100
|
+
categories[category.name] = category;
|
|
101
|
+
}
|
|
102
|
+
var times = cols.slice(firstTimeIdx);
|
|
103
|
+
for (var idx = 0; idx < parseInt(lineObj["Posten"], 10) * 2; idx += 2) {
|
|
104
|
+
if (idx === times.length - 1) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
var parsedTime = (0, time_1.parseTime)(times[idx + 1]);
|
|
108
|
+
runner.splits.push({ code: times[idx], time: (0, time_1.formatTime)(parsedTime) });
|
|
109
|
+
}
|
|
110
|
+
category.runners.push(runner);
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
name: options.event || "Anonymous Event",
|
|
114
|
+
map: options.map || "Unknown Map",
|
|
115
|
+
date: options.date || "",
|
|
116
|
+
startTime: options.startTime || "",
|
|
117
|
+
categories: Object.keys(categories).map(function (category) {
|
|
118
|
+
return categories[category];
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
KraemerFormater.prototype.check = function (text) {
|
|
123
|
+
return (text.substring(0, 6) === "OE0014" ||
|
|
124
|
+
text.substring(0, 23) === "Stnr;Chip;Datenbank Id;");
|
|
125
|
+
};
|
|
126
|
+
KraemerFormater.prototype.serialize = function (competition) {
|
|
127
|
+
throw new Error("format does not implement serialization");
|
|
128
|
+
};
|
|
129
|
+
return KraemerFormater;
|
|
130
|
+
}());
|
|
131
|
+
exports.KraemerFormater = KraemerFormater;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OwareFormat = void 0;
|
|
4
|
+
function parseCategory(row) {
|
|
5
|
+
return {
|
|
6
|
+
name: row[0],
|
|
7
|
+
distance: parseInt(row[1], 10),
|
|
8
|
+
ascent: parseInt(row[2], 10),
|
|
9
|
+
controls: parseInt(row[3], 10),
|
|
10
|
+
runners: [],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function parseRunner(row, category, id) {
|
|
14
|
+
var headerLength = 15;
|
|
15
|
+
var i;
|
|
16
|
+
var splits = [];
|
|
17
|
+
for (i = headerLength; i < row.length; i += 2) {
|
|
18
|
+
splits.push({ code: row[i], time: row[i + 1] });
|
|
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
|
+
return {
|
|
29
|
+
id: id,
|
|
30
|
+
category: category,
|
|
31
|
+
rank: row[0] ? parseInt(row[0]) : undefined,
|
|
32
|
+
firstName: row[2],
|
|
33
|
+
name: row[1],
|
|
34
|
+
fullName: [row[2], row[1]].join(" "),
|
|
35
|
+
yearOfBirth: row[3],
|
|
36
|
+
club: row[8],
|
|
37
|
+
city: row[7],
|
|
38
|
+
nation: row[9],
|
|
39
|
+
time: row[12],
|
|
40
|
+
startTime: row[13],
|
|
41
|
+
splits: splits,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
var OwareFormat = /** @class */ (function () {
|
|
45
|
+
function OwareFormat() {
|
|
46
|
+
}
|
|
47
|
+
OwareFormat.prototype.parse = function (text) {
|
|
48
|
+
// split text into lines
|
|
49
|
+
var lines = text.trim().split(/[\r\n]+/);
|
|
50
|
+
// throw away first row containing headers
|
|
51
|
+
lines = lines.splice(1);
|
|
52
|
+
// second row contains information about the event
|
|
53
|
+
var header = lines[0].split(";");
|
|
54
|
+
var competition = {
|
|
55
|
+
// row starts with a double slash
|
|
56
|
+
name: header[0].substring(2, header[0].length),
|
|
57
|
+
map: header[1],
|
|
58
|
+
date: header[2],
|
|
59
|
+
startTime: header[3],
|
|
60
|
+
categories: [],
|
|
61
|
+
};
|
|
62
|
+
// throw a way the now parsed header
|
|
63
|
+
lines = lines.splice(1);
|
|
64
|
+
var category;
|
|
65
|
+
var idx = 0;
|
|
66
|
+
lines
|
|
67
|
+
.filter(function (line) { return line.trim().length > 0; })
|
|
68
|
+
.forEach(function (line) {
|
|
69
|
+
var cols = line.split(";");
|
|
70
|
+
if (cols.length === 4) {
|
|
71
|
+
category = parseCategory(cols);
|
|
72
|
+
competition.categories.push(category);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
category.runners.push(parseRunner(cols, category.name, ++idx));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return competition;
|
|
79
|
+
};
|
|
80
|
+
OwareFormat.prototype.serialize = function (event) {
|
|
81
|
+
var result = "//Format: Rank;Name;Firstname;YearOfBirth;SexMF;FedNr;Zip;Town;Club;NationIOF;StartNr;eCardNr;RunTime;StartTime;FinishTime;CtrlCode;SplitTime; ...\n";
|
|
82
|
+
result +=
|
|
83
|
+
"//" +
|
|
84
|
+
[event.name, event.map, event.date, event.startTime, ""].join(";") +
|
|
85
|
+
"\n";
|
|
86
|
+
event.categories.forEach(function (category) {
|
|
87
|
+
result +=
|
|
88
|
+
[
|
|
89
|
+
category.name,
|
|
90
|
+
category.distance,
|
|
91
|
+
category.ascent,
|
|
92
|
+
category.controls,
|
|
93
|
+
].join(";") + "\n";
|
|
94
|
+
category.runners.forEach(function (runner) {
|
|
95
|
+
result += [
|
|
96
|
+
runner.rank,
|
|
97
|
+
runner.fullName,
|
|
98
|
+
"",
|
|
99
|
+
runner.yearOfBirth,
|
|
100
|
+
"",
|
|
101
|
+
"",
|
|
102
|
+
"",
|
|
103
|
+
runner.city,
|
|
104
|
+
runner.club,
|
|
105
|
+
runner.nation,
|
|
106
|
+
"",
|
|
107
|
+
"", // ecard
|
|
108
|
+
runner.time,
|
|
109
|
+
runner.startTime,
|
|
110
|
+
"",
|
|
111
|
+
].join(";");
|
|
112
|
+
result +=
|
|
113
|
+
";" +
|
|
114
|
+
runner.splits
|
|
115
|
+
.map(function (split) {
|
|
116
|
+
return split.code + ";" + split.time;
|
|
117
|
+
})
|
|
118
|
+
.join(";") +
|
|
119
|
+
"\n";
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
return result;
|
|
123
|
+
};
|
|
124
|
+
OwareFormat.prototype.check = function (text) {
|
|
125
|
+
return text.substring(0, 8) === "//Format";
|
|
126
|
+
};
|
|
127
|
+
return OwareFormat;
|
|
128
|
+
}());
|
|
129
|
+
exports.OwareFormat = OwareFormat;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Format } from "../format";
|
|
2
|
+
import { Category } from "../model/category";
|
|
3
|
+
import { Competition } from "../model/competition";
|
|
4
|
+
export declare class SolvFormat implements Format {
|
|
5
|
+
parse(text: string, options?: any): {
|
|
6
|
+
name: any;
|
|
7
|
+
map: any;
|
|
8
|
+
date: any;
|
|
9
|
+
startTime: any;
|
|
10
|
+
categories: Category[];
|
|
11
|
+
};
|
|
12
|
+
serialize(competition: Competition): string;
|
|
13
|
+
check(text: string): boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SolvFormat = void 0;
|
|
4
|
+
var time_1 = require("../time");
|
|
5
|
+
function reformatTime(str) {
|
|
6
|
+
// "special" total times (like wrong or missing control)
|
|
7
|
+
if (str.indexOf(":") === -1) {
|
|
8
|
+
return str;
|
|
9
|
+
}
|
|
10
|
+
var parsed = (0, time_1.parseTime)(str);
|
|
11
|
+
return parsed ? (0, time_1.formatTime)(parsed) : undefined;
|
|
12
|
+
}
|
|
13
|
+
function reformatSplitTime(str) {
|
|
14
|
+
// normalize missing punch time
|
|
15
|
+
if (str === "-" || str === "-----") {
|
|
16
|
+
return "-";
|
|
17
|
+
}
|
|
18
|
+
// normalize not working control
|
|
19
|
+
if (str === "0.00") {
|
|
20
|
+
return "s";
|
|
21
|
+
}
|
|
22
|
+
var parsed = (0, time_1.parseTime)(str);
|
|
23
|
+
return parsed ? (0, time_1.formatTime)(parsed) : undefined;
|
|
24
|
+
}
|
|
25
|
+
// flat csv file format - every row contains full info including category
|
|
26
|
+
// Kategorie;Laenge;Steigung;PoAnz;Rang;Name;Jahrgang;Ort;Club;Zeit;Startzeit;Zielzeit;Zwischenzeiten
|
|
27
|
+
var SolvFormat = /** @class */ (function () {
|
|
28
|
+
function SolvFormat() {
|
|
29
|
+
}
|
|
30
|
+
SolvFormat.prototype.parse = function (text, options) {
|
|
31
|
+
if (options === void 0) { options = {}; }
|
|
32
|
+
var categories = {};
|
|
33
|
+
var lines = text.split("\n");
|
|
34
|
+
// drop header column
|
|
35
|
+
lines.splice(0, 1)[0].split(";");
|
|
36
|
+
lines.forEach(function (line, idx) {
|
|
37
|
+
var tokens = line.split(";");
|
|
38
|
+
if (tokens.length < 11) {
|
|
39
|
+
// invalid input? not enough data for runner
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
var categoryName = tokens[0];
|
|
43
|
+
var category = categories[categoryName];
|
|
44
|
+
if (!category) {
|
|
45
|
+
category = {
|
|
46
|
+
name: categoryName,
|
|
47
|
+
distance: Math.round(parseFloat(tokens[1]) * 1000),
|
|
48
|
+
ascent: parseInt(tokens[2]),
|
|
49
|
+
controls: parseInt(tokens[3]),
|
|
50
|
+
runners: [],
|
|
51
|
+
};
|
|
52
|
+
categories[categoryName] = category;
|
|
53
|
+
}
|
|
54
|
+
var name = tokens[5].split(" ");
|
|
55
|
+
var runner = {
|
|
56
|
+
id: idx,
|
|
57
|
+
category: categoryName,
|
|
58
|
+
rank: tokens[4] ? parseInt(tokens[4]) : undefined,
|
|
59
|
+
firstName: name[0],
|
|
60
|
+
name: name.slice(1).join(" "),
|
|
61
|
+
fullName: tokens[5],
|
|
62
|
+
yearOfBirth: tokens[6],
|
|
63
|
+
city: tokens[7],
|
|
64
|
+
club: tokens[8],
|
|
65
|
+
time: reformatTime(tokens[9]),
|
|
66
|
+
startTime: tokens[10],
|
|
67
|
+
splits: [],
|
|
68
|
+
};
|
|
69
|
+
if (tokens.length - 12 < category.controls * 2) {
|
|
70
|
+
// some crappy SOLV data...
|
|
71
|
+
console.log("fix crappy data from SOLV - not enough tokens on line for runner " +
|
|
72
|
+
runner.fullName);
|
|
73
|
+
for (var i = tokens.length; i < category.controls * 2 + 12; i++) {
|
|
74
|
+
if (i % 2 === 0) {
|
|
75
|
+
tokens[i] =
|
|
76
|
+
category.runners.length === 0
|
|
77
|
+
? "???"
|
|
78
|
+
: category.runners[0].splits[(i - 12) / 2].code;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
tokens[i] = "-";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (var i_1 = 12; i_1 < tokens.length - 1; i_1 += 2) {
|
|
86
|
+
var time = reformatSplitTime(tokens[i_1 + 1]);
|
|
87
|
+
if (runner.splits.length > 0 && time) {
|
|
88
|
+
var prev = runner.splits[runner.splits.length - 1].time;
|
|
89
|
+
var parsedTime = (0, time_1.parseTime)(tokens[i_1 + 1]);
|
|
90
|
+
if (time === prev ||
|
|
91
|
+
tokens[i_1 + 1] === "0.00" || (parsedTime && parsedTime > 180 * 60)) {
|
|
92
|
+
// normalize valid manual punches
|
|
93
|
+
time = "s";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
runner.splits.push({ code: tokens[i_1], time: time });
|
|
97
|
+
}
|
|
98
|
+
category.runners.push(runner);
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
name: options.event || "Anonymous Event",
|
|
102
|
+
map: options.map || "Unknown Map",
|
|
103
|
+
date: options.date || "",
|
|
104
|
+
startTime: options.startTime || "",
|
|
105
|
+
categories: Object.keys(categories).map(function (category) {
|
|
106
|
+
return categories[category];
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
SolvFormat.prototype.serialize = function (competition) {
|
|
111
|
+
var result = "Kategorie;Laenge;Steigung;PoAnz;Rang;Name;Jahrgang;Ort;Club;Zeit;Startzeit;Zielzeit;Zwischenzeiten\n";
|
|
112
|
+
competition.categories.forEach(function (category) {
|
|
113
|
+
category.runners.forEach(function (runner) {
|
|
114
|
+
var distance = category.distance
|
|
115
|
+
? category.distance
|
|
116
|
+
: null;
|
|
117
|
+
var runTime = (0, time_1.parseTime)(runner.time);
|
|
118
|
+
var startTime = (0, time_1.parseTime)(runner.startTime);
|
|
119
|
+
var finishTime = runTime && startTime ? (0, time_1.formatTime)(runTime + startTime) : '';
|
|
120
|
+
result += [
|
|
121
|
+
category.name,
|
|
122
|
+
distance,
|
|
123
|
+
category.ascent,
|
|
124
|
+
category.controls,
|
|
125
|
+
runner.rank,
|
|
126
|
+
runner.fullName,
|
|
127
|
+
runner.yearOfBirth,
|
|
128
|
+
runner.city,
|
|
129
|
+
runner.club,
|
|
130
|
+
runner.time,
|
|
131
|
+
runner.startTime,
|
|
132
|
+
finishTime,
|
|
133
|
+
].join(";");
|
|
134
|
+
result +=
|
|
135
|
+
";" +
|
|
136
|
+
runner.splits
|
|
137
|
+
.map(function (split) {
|
|
138
|
+
return split.code + ";" + split.time;
|
|
139
|
+
})
|
|
140
|
+
.join(";") +
|
|
141
|
+
"\n";
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
return result;
|
|
145
|
+
};
|
|
146
|
+
SolvFormat.prototype.check = function (text) {
|
|
147
|
+
return text.indexOf("Kategorie;Laenge;Steigung;PoAnz;Rang;") === 0;
|
|
148
|
+
};
|
|
149
|
+
return SolvFormat;
|
|
150
|
+
}());
|
|
151
|
+
exports.SolvFormat = SolvFormat;
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface Ranking {
|
|
2
|
+
runners: {
|
|
3
|
+
[key: string]: RunnerInfo;
|
|
4
|
+
};
|
|
5
|
+
legs: {
|
|
6
|
+
[key: string]: Leg;
|
|
7
|
+
};
|
|
8
|
+
ranking: RankingEntry[];
|
|
9
|
+
}
|
|
10
|
+
export interface Leg {
|
|
11
|
+
from: string;
|
|
12
|
+
to: string;
|
|
13
|
+
ranking: RankingEntry[];
|
|
14
|
+
}
|
|
15
|
+
export interface RankingEntry {
|
|
16
|
+
rank: number;
|
|
17
|
+
time: string;
|
|
18
|
+
runnerRef: string;
|
|
19
|
+
}
|
|
20
|
+
export interface RunnerInfo {
|
|
21
|
+
fullName: string;
|
|
22
|
+
club: string;
|
|
23
|
+
city: string;
|
|
24
|
+
category: string;
|
|
25
|
+
course: string[];
|
|
26
|
+
startTime: string;
|
|
27
|
+
}
|
|
@@ -1,37 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/* extracted information about all legs found */
|
|
6
|
-
legs: { [key:string]: Leg },
|
|
7
|
-
|
|
8
|
-
/* this is the overall ranking of the given runners */
|
|
9
|
-
ranking: RankingEntry[]
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface Leg {
|
|
13
|
-
from: string;
|
|
14
|
-
to: string;
|
|
15
|
-
ranking: RankingEntry[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface RankingEntry {
|
|
19
|
-
rank: number;
|
|
20
|
-
time: string;
|
|
21
|
-
runnerRef: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface RunnerInfo {
|
|
25
|
-
fullName: string;
|
|
26
|
-
club: string;
|
|
27
|
-
city: string;
|
|
28
|
-
category: string;
|
|
29
|
-
course: string[];
|
|
30
|
-
startTime: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const sample:Ranking = {
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var sample = {
|
|
35
4
|
runners: {
|
|
36
5
|
"22": {
|
|
37
6
|
fullName: "Hans Dobeli",
|
|
@@ -39,7 +8,7 @@ const sample:Ranking = {
|
|
|
39
8
|
city: "Witzwil",
|
|
40
9
|
category: "HB",
|
|
41
10
|
startTime: "01:33:00",
|
|
42
|
-
course: [
|
|
11
|
+
course: ["St", "31", "32", "33", "Zi"]
|
|
43
12
|
},
|
|
44
13
|
"23": {
|
|
45
14
|
fullName: "Fritz Berger",
|
|
@@ -47,7 +16,7 @@ const sample:Ranking = {
|
|
|
47
16
|
city: "Langnau",
|
|
48
17
|
category: "HB",
|
|
49
18
|
startTime: "00:55:00",
|
|
50
|
-
course: [
|
|
19
|
+
course: ["St", "31", "32", "33", "Zi"]
|
|
51
20
|
}
|
|
52
21
|
},
|
|
53
22
|
legs: {
|
|
@@ -80,4 +49,4 @@ const sample:Ranking = {
|
|
|
80
49
|
time: "46:44"
|
|
81
50
|
}
|
|
82
51
|
]
|
|
83
|
-
}
|
|
52
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Split } from "./split";
|
|
2
|
+
export interface Runner {
|
|
3
|
+
id: number;
|
|
4
|
+
category: string;
|
|
5
|
+
rank?: number;
|
|
6
|
+
name: string;
|
|
7
|
+
firstName: string;
|
|
8
|
+
fullName: string;
|
|
9
|
+
yearOfBirth?: string;
|
|
10
|
+
sex?: Sex;
|
|
11
|
+
city?: string;
|
|
12
|
+
nation?: string;
|
|
13
|
+
club?: string;
|
|
14
|
+
time?: string;
|
|
15
|
+
startTime: string;
|
|
16
|
+
splits: Split[];
|
|
17
|
+
}
|
|
18
|
+
export declare enum Sex {
|
|
19
|
+
male = "m",
|
|
20
|
+
female = "f"
|
|
21
|
+
}
|