sokolov-sbs-flowserver/flow/get_departures.js

614 lines
37 KiB
JavaScript
Raw Normal View History

2025-08-07 21:49:01 +02:00
exports.id = 'getdepartures';
exports.title = 'Get departures';
exports.group = 'Worksys';
exports.color = '#5D9CEC';
exports.version = '0.0.1';
exports.output = 2;
exports.input = true;
exports.icon = 'cloud-upload';
const { promisifyBuilder } = require('./helper/db_helper');
exports.install = function(instance) {
const URL = "https://bezpecne.sokolov.cz/zast/jedn_drogerie.csv";
//const URL = "https://bezpecne.sokolov.cz/zast/sidl_michal.csv";
const CHECK_DEPARTURES_INTERVAL = 1 * 60 * 60000; //raz za hodinu
const NUMBER_OF_REQUESTS_BEFORE_LOAD_DEPARTURES_FROM_FILE = 15;
const CHECK_NEW_DAY_DEPARTURES_AT = 1 // at 1 at night we check new departures
let departuresFromFile = null;
let departuresDB = null;
let httpBody = null;
let attempts = 0;
let server_responded = false;
async function loadDepartures() {
departuresDB = TABLE("departures");
departuresFromFile = await promisifyBuilder(departuresDB.find());
departuresFromFile = departuresFromFile[0].departures;
//console.log("cccc", departuresFromFile);
}
loadDepartures();
instance.on('close', function() {
clearInterval(interval1);
})
let interval1 = setInterval(getDepartures, CHECK_DEPARTURES_INTERVAL);
function getDepartures() {
//console.log('getDep called');
let d = new Date();
let hour = d.getHours();
if (hour === CHECK_NEW_DAY_DEPARTURES_AT) server_responded = false;
if (d.getHours() === CHECK_NEW_DAY_DEPARTURES_AT || !server_responded) {
attempts++;
//console.log('attempts: ', attempts);
const opt = {
url: URL
};
opt.callback = function(err, response) {
if (err || response.body.includes('Rejected') || response.status === 404) {
console.log('errr', err, response.body);
//NOTE: if error, we try to refetch departures
if (attempts < NUMBER_OF_REQUESTS_BEFORE_LOAD_DEPARTURES_FROM_FILE) {
setTimeout(getDepartures, 20000);
} else if (attempts === NUMBER_OF_REQUESTS_BEFORE_LOAD_DEPARTURES_FROM_FILE) {
const { departures } = processBusData(departuresFromFile);
console.log('odchody nacitane zo suboru');
instance.send(0, departures);
}
return;
}
attempts = 0;
server_responded = true;
console.log(response);
httpBody = response.body;
departuresDB.modify({ departures: httpBody }).callback(function(err, response) {
if (err) console.log("Get_departures: error writing to departure.table", err)
console.log("Departures written to db for day: ", new Date());
});
const { departures } = processBusData(httpBody);
console.log(JSON.stringify(departures));
instance.send(0, departures);
}
REQUEST(opt);
}
}
setTimeout(getDepartures, 5000);
/**
* Filters a departure array based on date masks and a specific day index.
*
* @param {Array<Array<any>>} rawDepartures - The unfiltered departure array.
* @param {Object} dateMasks - An object containing date masks (e.g., {X01: "111..."}).
* @param {number | null} dayIndex - The 0-based index representing the current day in the mask.
* @param {boolean} isInsideDateRange - True if today's date is inside of the overall date range.
* @returns {Array<Array<any>>} The filtered departure array.
*/
const filterDeparturesByDate = (rawDepartures, dateMasks, dayIndex, isInsideDateRange) => {
// If today's date is not inside of the overall date range, no departures should be shown.
if (!isInsideDateRange) {
return [];
}
// If dayIndex is invalid or no date masks are provided, return the unfiltered array.
// You might adjust this default behavior based on specific requirements.
if (dayIndex === null || dayIndex < 0 || Object.keys(dateMasks).length === 0) {
console.warn("Filtering conditions not fully met (e.g., current day not calculated or no masks). Returning unfiltered departures.");
return rawDepartures;
}
const filtered = rawDepartures.filter(departureItem => {
const kodMasky = departureItem[3]; // 'Kód datumové masky' is at index 3
const dateMask = dateMasks[kodMasky]; // Get the mask string (e.g., "111001...")
// Check if the mask exists and if the dayIndex is within the mask's length
if (dateMask && dayIndex < dateMask.length) {
const characterForToday = dateMask[dayIndex];
return characterForToday === '1'; // Keep if the character at the current day's index is '1'
}
// If mask not found or dayIndex is out of bounds for a specific departure's mask,
// it means this departure doesn't have valid mask data for today.
// Decide default behavior: return false (discard) or true (keep).
// Discarding is safer if valid mask data is required.
console.warn(`Departure with mask '${kodMasky}' has invalid or missing mask data for day index ${dayIndex}. Discarding.`);
return false;
});
return filtered;
};
/**
* Processes the raw HTTP body to extract departure data, date range analysis, and date masks.
*
* @param {string} httpBody - The raw HTTP request body string.
* @param {string | null} todayOverride - Optional. A date string (e.g., 'YYYY-MM-DD') to use as "today" for analysis.
* If null, the current system date will be used.
* @returns {Object} An object containing:
* - departure: Filtered array of departure times.
* - dateAnalysis: Analysis of the date range (start, end, days passed, etc.).
* - dateMasks: An object mapping mask codes to their binary strings.
*/
const processBusData = (httpBody, todayOverride = null) => {
// 1. Initial cleanup and splitting of the raw body
const cleanedString = httpBody.startsWith('\ufeff') ? httpBody.substring(1) : httpBody;
const lines = cleanedString.split('\r\n');
//console.log("*************lines", lines, lines.length, typeof lines);
// --- Data structures to be populated ---
const rawDepartures = []; // Collects all departures before filtering
const dateMasks = {};
let dateAnalysis = {
startDate: null,
endDate: null,
today: null,
daysPassed: null,
isInsideDateRange: null
};
// --- Flags and counters for parsing different sections ---
let captureDateMasksMode = false;
let departureSectionStartIndex = -1;
let foundObdobi = false;
// Define "today" for calculation.
const todayCalc = todayOverride ? new Date(todayOverride) : new Date();
todayCalc.setUTCHours(0, 0, 0, 0);
let linka_ = null;
let cas_odjezdu = null;
let cilova_obec_spoje = null;
let kod_datumovej_masky = null;
// --- Iterate through lines to parse all sections ---
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const trimmedLine = line.trim();
// --- 1. Parse 'Období' (Date Range Analysis) ---
if (!foundObdobi && trimmedLine.startsWith('Období;')) {
const parts = trimmedLine.split(';');
if (parts.length >= 3) {
const startDateStr = parts[1].trim();
const endDateStr = parts[2].trim();
const parseDateString = (dateStr) => {
const [day, month, year] = dateStr.split('.');
return `${year}-${month}-${day}`;
};
const parsedStartDate = new Date(parseDateString(startDateStr));
const parsedEndDate = new Date(parseDateString(endDateStr));
if (!isNaN(parsedStartDate.getTime()) && !isNaN(parsedEndDate.getTime())) {
parsedStartDate.setUTCHours(0, 0, 0, 0);
parsedEndDate.setUTCHours(0, 0, 0, 0);
const millisecondsPerDay = 1000 * 60 * 60 * 24;
const timeDifference = todayCalc.getTime() - parsedStartDate.getTime();
const daysPassed = Math.floor(timeDifference / millisecondsPerDay);
const isInsideDateRange = todayCalc <= parsedEndDate && todayCalc >= parsedStartDate;
console.log("is in date range? ", isInsideDateRange);
dateAnalysis = {
startDate: parsedStartDate.toLocaleDateString('en-GB'),
endDate: parsedEndDate.toLocaleDateString('en-GB'),
today: todayCalc.toLocaleDateString('en-GB'),
daysPassed: daysPassed >= 0 ? daysPassed : 0,
isInsideDateRange: isInsideDateRange
};
foundObdobi = true;
} else {
console.error("Warning: Could not parse valid start and/or end dates from 'Období' field.");
}
}
}
// --- 2. Parse Date Masks ---
if (trimmedLine.includes("Kód datumové masky;Datumová maska")) {
captureDateMasksMode = true;
continue;
}
if (captureDateMasksMode && !trimmedLine) {
captureDateMasksMode = false;
continue;
}
if (captureDateMasksMode) {
const columns = trimmedLine.split(';');
if (columns.length >= 2) {
const code = columns[0].trim();
const mask = columns[1].trim();
if (code && mask) {
dateMasks[code] = mask;
}
}
}
// --- 3. Find Start of Departure Data ---
if (trimmedLine.includes("Linka") && trimmedLine.includes("Čas odjezdu") && trimmedLine.includes('Cílová obec spoje') && trimmedLine.includes('Kód datumové masky')) {
let structure = trimmedLine.split(";");
linka_ = structure.indexOf("Linka");
cas_odjezdu = structure.indexOf("Čas odjezdu");
cilova_obec_spoje = structure.indexOf("Cílová obec spoje");
kod_datumovej_masky = structure.indexOf("Kód datumové masky");
if (linka_ == -1 || cas_odjezdu == -1 || cilova_obec_spoje == -1 || kod_datumovej_masky == -1) {
console.log("subor odchodov neobsahuje pozadovane udaje");
linka_ = 0;
cas_odjezdu = 2;
cilova_obec_spoje = 4;
kod_datumovej_masky = 5;
}
departureSectionStartIndex = i + 1;
continue;
}
// --- 4. Parse Raw Departure Data ---
if (departureSectionStartIndex !== -1 && i >= departureSectionStartIndex) {
if (!trimmedLine) {
continue;
}
const columns = trimmedLine.split(';');
if (columns.length >= 6 && columns[0].trim() !== '') {
//const linka = parseInt(columns[0].trim(), 10);
//let casOdjezdu = columns[2].trim();
//if (casOdjezdu.length === 4) casOdjezdu = "0" + casOdjezdu;
//let cilovaObecSpoje = columns[4].trim();
//const kodDatumoveMasky = columns[5].trim();
//cilovaObecSpoje = cilovaObecSpoje.replace(/,,/g, ', ');
const linka = parseInt(columns[linka_].trim(), 10);
let casOdjezdu = columns[cas_odjezdu].trim();
if (casOdjezdu.length === 4) casOdjezdu = "0" + casOdjezdu;
let cilovaObecSpoje = columns[cilova_obec_spoje].trim();
const kodDatumoveMasky = columns[kod_datumovej_masky].trim();
cilovaObecSpoje = cilovaObecSpoje.replace(/,,/g, ', ');
if (!isNaN(linka)) {
rawDepartures.push([
linka,
casOdjezdu,
cilovaObecSpoje,
kodDatumoveMasky
]);
}
}
}
}
// --- Final Step: Filter the departures using the new function ---
const finalDepartures = filterDeparturesByDate(
rawDepartures,
dateMasks,
dateAnalysis.daysPassed,
dateAnalysis.isInsideDateRange
);
// console.log('aaaaaaa', JSON.stringify(rawDepartures));
// console.log('aaaFINALaaaa', JSON.stringify(finalDepartures));
return {
departures: finalDepartures, // Now 'departures' holds the filtered array
rawDepartures: rawDepartures,
dateAnalysis: dateAnalysis,
dateMasks: dateMasks
};
};
//184 total
let allDepartures = [[3, "4:09", "Sokolov, Závodu míru", "X01"], [3, "4:24", "Sokolov, Závodu míru", "X02"], [1, "4:50", "Březová, aut.st.", "X02"], [3, "4:52", "Sokolov, Závodu míru", "X02"], [3, "4:56", "Sokolov, Závodu míru", "X03"], [3, "5:02", "Sokolov, Závodu míru", "X02"], [4, "5:05", "Sokolov, Závodu míru", "X02"], [6, "5:07", "Sokolov, sídl.Michal škola", "X04"], [6, "5:07", "Sokolov, Závodu míru", "X05"], [3, "5:09", "Sokolov, Závodu míru", "X04"], [3, "5:22", "Sokolov, Závodu míru", "X02"], [1, "5:23", "Březová, aut.st.", "X02"], [3, "5:31", "Sokolov, sídl.Michal škola", "X04"], [6, "5:34", "Sokolov, sídl.Michal škola", "X04"], [4, "5:37", "Sokolov,Stará ovčárna", "X02"], [3, "5:40", "Sokolov, sídl.Michal", "X05"], [1, "5:47", "Březová, aut.st.", "X03"], [1, "5:51", "Březová, aut.st.", "X02"], [3, "5:57", "Sokolov, Závodu míru", "X03"], [6, "5:59", "Sokolov, sídl.Michal škola", "X04"], [3, "6:00", "Sokolov, Závodu míru", "X02"], [1, "6:13", "Březová, aut.st.", "X02"], [3, "6:16", "Sokolov, Závodu míru", "X04"], [3, "6:19", "Sokolov, Závodu míru", "X05"], [3, "6:24", "Sokolov, sídl.Michal", "X02"], [3, "6:24", "Sokolov, Závodu míru", "X03"], [6, "6:27", "Sokolov, sídl.Michal škola", "X05"], [6, "6:29", "Sokolov, sídl.Michal škola", "X04"], [4, "6:31", "Sokolov, Závodu míru", "X04"], [3, "6:39", "Sokolov, Závodu míru", "X02"], [1, "6:46", "Březová, aut.st.", "X02"], [33, "6:49", "Sokolov, sídl.Michal škola", "X04"], [3, "6:56", "Sokolov,Hrušková", "X04"], [3, "6:56", "Sokolov, Závodu míru", "X06"], [3, "6:59", "Sokolov, Závodu míru", "X02"], [1, "7:01", "Březová, aut.st.", "X03"], [1, "7:05", "Březová, aut.st.", "X02"], [3, "7:19", "Sokolov, Závodu míru", "X01"], [6, "7:23", "Sokolov, sídl.Michal škola", "X04"], [3, "7:27", "Sokolov, sídl.Michal", "X05"], [2, "7:31", "Sokolov, sídl.Michal", "X04"], [3, "7:34", "Sokolov, Závodu míru", "X04"], [4, "7:34", "Sokolov, Závodu míru", "X02"], [1, "7:35", "Březová, aut.st.", "X02"], [3, "7:45", "Sokolov, sídl.Michal", "X02"], [3, "7:51", "Sokolov, Závodu míru", "X03"], [1, "7:55", "Březová, aut.st.", "X02"], [1, "7:57", "Březová, aut.st.", "X03"], [3, "7:58", "Sokolov, Závodu míru", "X04"], [33, "8:01", "Sokolov, sídl.Michal škola", "X04"], [3, "8:13", "Sokolov, Závodu míru", "X05"], [3, "8:15", "Sokolov, Závodu míru", "X07"], [1, "8:18", "Březová, aut.st.", "X02"], [33, "8:29", "Sokolov, sídl.Michal škola", "X02"], [3, "8:34", "Sokolov, Závodu míru", "X02"], [3, "8:50", "Sokolov,Stará ovčárna", "X02"], [3, "8:51", "Sokolov, Závodu míru", "X03"], [33, "8:54", "Sokolov, sídl.Michal škola", "X02"], [1, "8:57", "Březová, aut.st.", "X03"], [3, "9:04", "Sokolov, Závodu míru", "X02"], [1, "9:09", "Březová, aut.st.", "X02"], [3, "9:20", "Sokolov, Závodu míru", "X03"], [3, "9:24", "Sokolov, Závodu míru", "X02"], [33, "9:34", "Sokolov, sídl.Michal škola", "X02"], [4, "9:41", "Sokolov, sídl.Michal", "X02"], [1, "9:44", "Březová, aut.st.", "X03"], [3, "9:45", "Sokolov, Závodu míru", "X02"], [3, "9:51", "Sokolov, Závodu míru", "X03"], [1, "9:58", "Březová, aut.st.", "X02"], [3, "9:59", "Sokolov, Závodu míru", "X02"], [7, "10:14", "Březová, aut.st.", "X02"], [3, "10:19", "Sokolov, Závodu míru", "X03"], [33, "10:24", "Sokolov, sídl.Michal škola", "X02"], [3, "10:40", "Sokolov, Závodu míru", "X02"], [1, "10:55", "Březová, aut.st.", "X02"], [3, "10:55", "Sokolov, Závodu míru", "X02"], [1, "10:57", "Březová, aut.st.", "X03"], [3, "11:02", "Sokolov, Závodu míru", "X03"], [3, "11:17", "Sokolov, Závodu míru", "X02"], [3, "11:29", "Sokolov, Závodu míru", "X03"], [33, "11:29", "Sokolov, sídl.Michal škola", "X02"], [3, "11:44", "Sokolov, Závodu míru", "X02"], [1, "11:46", "Březová, aut.st.", "X02"], [1, "11:49", "Březová, aut.st.", "X03"], [3, "11:51", "Sokolov, Závodu míru", "X03"], [33, "11:56", "Sokolov, sídl.Michal škola", "X02"], [3, "12:07", "Sokolov, Závodu míru", "X02"], [3, "12:19", "Sokolov, Závodu míru", "X03
let httpBody1 = {
body: 'Sloupec1;Sloupec2;Sloupec3;Sloupec4;Sloupec5;Sloupec7\r\n' +
'Export odjezdů ze dne;22.04.2025;08:32;;;\r\n' +
'Zastávka;Sokolov,,ul.Jednoty drogerie;;;;\r\n' +
'Období;24.03.2025;31.05.2025;;;\r\n' +
';;;;;\r\n' +
'Kód datumové masky;Datumová maska;;;;\r\n' +
'X01;111111111111111111111111111111111111111111111111111111111111111111111;;;;\r\n' +
'X02;111110011111001111100111100001111001110100111010011111001111100111110;;;;\r\n' +
'X03;000001100000110000011000011110000110001011000101100000110000011000001;;;;\r\n' +
'X04;111110011111001111100111000001111001110100111010011111001111100111110;;;;\r\n' +
'X05;000000000000000000000000100000000000000000000000000000000000000000000;;;;\r\n' +
'X06;000001100000110000011000111110000110001011000101100000110000011000001;;;;\r\n' +
'X07;111111111111111111111111011111111111111111111111111111111111111111111;;;;\r\n' +
';;;;;\r\n' +
'Linka;Spoj;Čas odjezdu;Nástupiště;Cílová obec spoje;Kód datumové masky\r\n' +
'3;;4:09;;Sokolov,,Závodu míru;X01\r\n' +
'3;;4:24;;Sokolov,,Závodu míru;X02\r\n' +
'1;;4:50;;Březová,,aut.st.;X02\r\n' +
'3;;4:52;;Sokolov,,Závodu míru;X02\r\n' +
'3;;4:56;;Sokolov,,Závodu míru;X03\r\n' +
'3;;5:02;;Sokolov,,Závodu míru;X02\r\n' +
'4;;5:05;;Sokolov,,Závodu míru;X02\r\n' +
'6;;5:07;;Sokolov,,sídl.Michal škola;X04\r\n' +
'6;;5:07;;Sokolov,,Závodu míru;X05\r\n' +
'3;;5:09;;Sokolov,,Závodu míru;X04\r\n' +
'3;;5:22;;Sokolov,,Závodu míru;X02\r\n' +
'1;;5:23;;Březová,,aut.st.;X02\r\n' +
'3;;5:31;;Sokolov,,sídl.Michal škola;X04\r\n' +
'6;;5:34;;Sokolov,,sídl.Michal škola;X04\r\n' +
'4;;5:37;;Sokolov,Stará ovčárna;X02\r\n' +
'3;;5:40;;Sokolov,,sídl.Michal;X05\r\n' +
'1;;5:47;;Březová,,aut.st.;X03\r\n' +
'1;;5:51;;Březová,,aut.st.;X02\r\n' +
'3;;5:57;;Sokolov,,Závodu míru;X03\r\n' +
'6;;5:59;;Sokolov,,sídl.Michal škola;X04\r\n' +
'3;;6:00;;Sokolov,,Závodu míru;X02\r\n' +
'1;;6:13;;Březová,,aut.st.;X02\r\n' +
'3;;6:16;;Sokolov,,Závodu míru;X04\r\n' +
'3;;6:19;;Sokolov,,Závodu míru;X05\r\n' +
'3;;6:24;;Sokolov,,sídl.Michal;X02\r\n' +
'3;;6:24;;Sokolov,,Závodu míru;X03\r\n' +
'6;;6:27;;Sokolov,,sídl.Michal škola;X05\r\n' +
'6;;6:29;;Sokolov,,sídl.Michal škola;X04\r\n' +
'4;;6:31;;Sokolov,,Závodu míru;X04\r\n' +
'3;;6:39;;Sokolov,,Závodu míru;X02\r\n' +
'1;;6:46;;Březová,,aut.st.;X02\r\n' +
'33;;6:49;;Sokolov,,sídl.Michal škola;X04\r\n' +
'3;;6:56;;Sokolov,Hrušková;X04\r\n' +
'3;;6:56;;Sokolov,,Závodu míru;X06\r\n' +
'3;;6:59;;Sokolov,,Závodu míru;X02\r\n' +
'1;;7:01;;Březová,,aut.st.;X03\r\n' +
'1;;7:05;;Březová,,aut.st.;X02\r\n' +
'3;;7:19;;Sokolov,,Závodu míru;X01\r\n' +
'6;;7:23;;Sokolov,,sídl.Michal škola;X04\r\n' +
'3;;7:27;;Sokolov,,sídl.Michal;X05\r\n' +
'2;;7:31;;Sokolov,,sídl.Michal;X04\r\n' +
'3;;7:34;;Sokolov,,Závodu míru;X04\r\n' +
'4;;7:34;;Sokolov,,Závodu míru;X02\r\n' +
'1;;7:35;;Březová,,aut.st.;X02\r\n' +
'3;;7:45;;Sokolov,,sídl.Michal;X02\r\n' +
'3;;7:51;;Sokolov,,Závodu míru;X03\r\n' +
'1;;7:55;;Březová,,aut.st.;X02\r\n' +
'1;;7:57;;Březová,,aut.st.;X03\r\n' +
'3;;7:58;;Sokolov,,Závodu míru;X04\r\n' +
'33;;8:01;;Sokolov,,sídl.Michal škola;X04\r\n' +
'3;;8:13;;Sokolov,,Závodu míru;X05\r\n' +
'3;;8:15;;Sokolov,,Závodu míru;X07\r\n' +
'1;;8:18;;Březová,,aut.st.;X02\r\n' +
'33;;8:29;;Sokolov,,sídl.Michal škola;X02\r\n' +
'3;;8:34;;Sokolov,,Závodu míru;X02\r\n' +
'3;;8:50;;Sokolov,Stará ovčárna;X02\r\n' +
'3;;8:51;;Sokolov,,Závodu míru;X03\r\n' +
'33;;8:54;;Sokolov,,sídl.Michal škola;X02\r\n' +
'1;;8:57;;Březová,,aut.st.;X03\r\n' +
'3;;9:04;;Sokolov,,Závodu míru;X02\r\n' +
'1;;9:09;;Březová,,aut.st.;X02\r\n' +
'3;;9:20;;Sokolov,,Závodu míru;X03\r\n' +
'3;;9:24;;Sokolov,,Závodu míru;X02\r\n' +
'33;;9:34;;Sokolov,,sídl.Michal škola;X02\r\n' +
'4;;9:41;;Sokolov,,sídl.Michal;X02\r\n' +
'1;;9:44;;Březová,,aut.st.;X03\r\n' +
'3;;9:45;;Sokolov,,Závodu míru;X02\r\n' +
'3;;9:51;;Sokolov,,Závodu míru;X03\r\n' +
'1;;9:58;;Březová,,aut.st.;X02\r\n' +
'3;;9:59;;Sokolov,,Závodu míru;X02\r\n' +
'7;;10:14;;Březová,,aut.st.;X02\r\n' +
'3;;10:19;;Sokolov,,Závodu míru;X03\r\n' +
'33;;10:24;;Sokolov,,sídl.Michal škola;X02\r\n' +
'3;;10:40;;Sokolov,,Závodu míru;X02\r\n' +
'1;;10:55;;Březová,,aut.st.;X02\r\n' +
'3;;10:55;;Sokolov,,Závodu míru;X02\r\n' +
'1;;10:57;;Březová,,aut.st.;X03\r\n' +
'3;;11:02;;Sokolov,,Závodu míru;X03\r\n' +
'3;;11:17;;Sokolov,,Závodu míru;X02\r\n' +
'3;;11:29;;Sokolov,,Závodu míru;X03\r\n' +
'33;;11:29;;Sokolov,,sídl.Michal škola;X02\r\n' +
'3;;11:44;;Sokolov,,Závodu míru;X02\r\n' +
'1;;11:46;;Březová,,aut.st.;X02\r\n' +
'1;;11:49;;Březová,,aut.st.;X03\r\n' +
'3;;11:51;;Sokolov,,Závodu míru;X03\r\n' +
'33;;11:56;;Sokolov,,sídl.Michal škola;X02\r\n' +
'3;;12:07;;Sokolov,,Závodu míru;X02\r\n' +
'3;;12:19;;Sokolov,,Závodu míru;X03\r\n' +
'3;;12:24;;Sokolov,,Závodu míru;X02\r\n' +
'1;;12:33;;Březová,,aut.st.;X02\r\n' +
'3;;12:44;;Sokolov,,Závodu míru;X02\r\n' +
'3;;12:51;;Sokolov,,Závodu míru;X03\r\n' +
'1;;12:57;;Březová,,aut.st.;X03\r\n' +
'3;;12:59;;Sokolov,,Závodu míru;X02\r\n' +
'6;;12:59;;Sokolov,,sídl.Michal škola;X04\r\n' +
'33;;13:04;;Sokolov,,sídl.Michal škola;X02\r\n' +
'1;;13:06;;Březová,,aut.st.;X02\r\n' +
'3;;13:15;;Sokolov,,Závodu míru;X02\r\n' +
'2;;13:17;;Sokolov,,sídl.Michal;X02\r\n' +
'1;;13:22;;Březová,,aut.st.;X02\r\n' +
'3;;13:24;;Sokolov,Stará ovčárna;X02\r\n' +
'3;;13:28;;Sokolov,,Závodu míru;X03\r\n' +
'33;;13:34;;Sokolov,,sídl.Michal škola;X02\r\n' +
'1;;13:48;;Březová,,aut.st.;X02\r\n' +
'3;;13:51;;Sokolov,,Závodu míru;X03\r\n' +
'1;;13:59;;Březová,,aut.st.;X03\r\n' +
'6;;13:59;;Sokolov,,sídl.Michal škola;X02\r\n' +
'33;;14:04;;Sokolov,,sídl.Michal škola;X02\r\n' +
'4;;14:06;;Sokolov,Stará ovčárna;X02\r\n' +
'3;;14:09;;Sokolov,,Závodu míru;X02\r\n' +
'1;;14:10;;Březová,,aut.st.;X02\r\n' +
'3;;14:19;;Sokolov,,Závodu míru;X03\r\n' +
'3;;14:21;;Sokolov,,Závodu míru;X02\r\n' +
'1;;14:34;;Březová,,aut.st.;X02\r\n' +
'6;;14:34;;Sokolov,,sídl.Michal škola;X02\r\n' +
'4;;14:42;;Sokolov,,Závodu míru;X02\r\n' +
'3;;14:43;;Sokolov,,Závodu míru;X02\r\n' +
'33;;14:46;;Sokolov,,sídl.Michal škola;X02\r\n' +
'1;;14:51;;Březová,,aut.st.;X03\r\n' +
'3;;14:51;;Sokolov,,Závodu míru;X03\r\n' +
'3;;14:52;;Sokolov,,Závodu míru;X02\r\n' +
'1;;15:09;;Březová,,aut.st.;X02\r\n' +
'33;;15:09;;Sokolov,,sídl.Michal škola;X02\r\n' +
'3;;15:13;;Sokolov,,Závodu míru;X02\r\n' +
'6;;15:14;;Sokolov,,sídl.Michal škola;X02\r\n' +
'3;;15:20;;Sokolov,,Závodu míru;X03\r\n' +
'3;;15:26;;Sokolov,Hrušková;X04\r\n' +
'1;;15:31;;Březová,,aut.st.;X02\r\n' +
'3;;15:34;;Sokolov,,Závodu míru;X02\r\n' +
'3;;15:39;;Sokolov,,Závodu míru;X02\r\n' +
'33;;15:39;;Sokolov,,sídl.Michal škola;X02\r\n' +
'3;;15:51;;Sokolov,,Závodu míru;X03\r\n' +
'7;;15:54;;Březová,,aut.st.;X02\r\n' +
'1;;15:57;;Březová,,aut.st.;X03\r\n' +
'3;;16:00;;Sokolov,,sídl.Michal škola;X04\r\n' +
'4;;16:08;;Sokolov,,Závodu míru;X02\r\n' +
'3;;16:14;;Sokolov,,Závodu míru;X02\r\n' +
'33;;16:16;;Sokolov,,sídl.Michal škola;X02\r\n' +
'1;;16:21;;Březová,,aut.st.;X02\r\n' +
'3;;16:28;;Sokolov,,Závodu míru;X03\r\n' +
'7;;16:29;;Březová,,aut.st.;X02\r\n' +
'3;;16:37;;Sokolov,,Závodu míru;X02\r\n' +
'6;;16:44;;Sokolov,,sídl.Michal škola;X04\r\n' +
'3;;16:48;;Sokolov,,Závodu míru;X02\r\n' +
'3;;16:50;;Sokolov,,Závodu míru;X03\r\n' +
'4;;16:51;;Sokolov,,Závodu míru;X04\r\n' +
'1;;16:57;;Březová,,aut.st.;X03\r\n' +
'7;;16:59;;Březová,,aut.st.;X02\r\n' +
'3;;17:12;;Sokolov,Stará ovčárna;X02\r\n' +
'3;;17:17;;Sokolov,,Závodu míru;X03\r\n' +
'3;;17:18;;Sokolov,,Závodu míru;X02\r\n' +
'3;;17:34;;Sokolov,,Závodu míru;X02\r\n' +
'1;;17:38;;Březová,,aut.st.;X02\r\n' +
'3;;17:51;;Sokolov,,Závodu míru;X03\r\n' +
'3;;17:57;;Sokolov,,Závodu míru;X02\r\n' +
'3;;18:14;;Sokolov,,Závodu míru;X02\r\n' +
'3;;18:21;;Sokolov,,Závodu míru;X02\r\n' +
'3;;18:21;;Sokolov,Stará ovčárna;X03\r\n' +
'1;;18:24;;Březová,,aut.st.;X03\r\n' +
'1;;18:26;;Březová,,aut.st.;X02\r\n' +
'3;;18:34;;Sokolov,,Závodu míru;X02\r\n' +
'3;;18:51;;Sokolov,,Závodu míru;X03\r\n' +
'3;;18:54;;Sokolov,,Závodu míru;X02\r\n' +
'1;;19:08;;Březová,,aut.st.;X02\r\n' +
'3;;19:14;;Sokolov,,Závodu míru;X03\r\n' +
'3;;19:19;;Sokolov,,Závodu míru;X02\r\n' +
'3;;19:34;;Sokolov,,Závodu míru;X02\r\n' +
'1;;19:53;;Březová,,aut.st.;X02\r\n' +
'3;;19:54;;Sokolov,,Závodu míru;X03\r\n' +
'3;;19:56;;Sokolov,,Závodu míru;X02\r\n' +
'1;;19:57;;Březová,,aut.st.;X03\r\n' +
'3;;20:19;;Sokolov,,Závodu míru;X02\r\n' +
'1;;20:28;;Březová,,aut.st.;X03\r\n' +
'3;;20:49;;Sokolov,,Závodu míru;X01\r\n' +
'1;;20:55;;Březová,,aut.st.;X02\r\n' +
'3;;21:09;;Sokolov,,Závodu míru;X02\r\n' +
'1;;21:23;;Březová,,aut.st.;X03\r\n' +
'3;;21:24;;Sokolov,Stará ovčárna;X02\r\n' +
'3;;21:27;;Sokolov,,Závodu míru;X03\r\n' +
'1;;21:38;;Březová,,aut.st.;X02\r\n' +
'3;;22:05;;Sokolov,,Závodu míru;X03\r\n' +
'3;;22:12;;Sokolov,Stará ovčárna;X02\r\n' +
'1;;22:28;;Březová,,aut.st.;X02\r\n' +
'3;;22:41;;Sokolov,,Závodu míru;X02\r\n',
origin: undefined,
headers: {
'content-type': 'application/octet-stream',
'last-modified': 'Mon, 05 May 2025 06:17:00 GMT',
'accept-ranges': 'bytes',
etag: '"056854f85bddb1:0"',
date: 'Tue, 27 May 2025 08:03:15 GMT',
connection: 'close',
'content-length': '7779',
'set-cookie': [
'TS01a3e872=013429363de6e56879fa8c0bcc9065ad2fef2ca60e8eea9a5cc44bd80858a4f8586e2d59ae6d8cf9c6126d3b4d2d9738c850914be7; Path=/; Domain=.bezpecne.sokolov.cz;'
],
'strict-transport-security': 'max-age=31536000; includeSubdomains; preload',
'content-security-policy': 'block-all-mixed-content; upgrade-insecure-requests',
'referrer-policy': 'no-referrer-when-downgrade',
'permissions-policy': 'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=()',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '1; mode=block',
'access-control-allow-origin': '*'
},
status: 200,
host: 'bezpecne.sokolov.cz',
cookies: undefined
}
const departures1 = [
[3, "4:09", "Sokolov, Závodu míru", "X01"],
[3, "4:24", "Sokolov, Závodu míru", "X02"],
[1, "4:50", "Březová, aut.st.", "X02"],
[3, "4:52", "Sokolov, Závodu míru", "X02"],
[3, "4:56", "Sokolov, Závodu míru", "X03"],
[3, "5:02", "Sokolov, Závodu míru", "X02"],
[4, "5:05", "Sokolov, Závodu míru", "X02"],
[6, "5:07", "Sokolov, sídl.Michal škola", "X04"],
[6, "5:07", "Sokolov, Závodu míru", "X05"],
[3, "5:09", "Sokolov, Závodu míru", "X04"],
[3, "5:22", "Sokolov, Závodu míru", "X02"],
[1, "5:23", "Březová, aut.st.", "X02"],
[3, "5:31", "Sokolov, sídl.Michal škola", "X04"],
[6, "5:34", "Sokolov, sídl.Michal škola", "X04"],
[4, "5:37", "Sokolov,Stará ovčárna", "X02"],
[3, "5:40", "Sokolov, sídl.Michal", "X05"],
[1, "5:47", "Březová, aut.st.", "X03"],
[1, "5:51", "Březová, aut.st.", "X02"],
[3, "5:57", "Sokolov, Závodu míru", "X03"],
[6, "5:59", "Sokolov, sídl.Michal škola", "X04"],
[3, "6:00", "Sokolov, Závodu míru", "X02"],
[1, "6:13", "Březová, aut.st.", "X02"],
[3, "6:16", "Sokolov, Závodu míru", "X04"],
[3, "6:19", "Sokolov, Závodu míru", "X05"],
[3, "6:24", "Sokolov, sídl.Michal", "X02"],
[3, "6:24", "Sokolov, Závodu míru", "X03"],
[6, "6:27", "Sokolov, sídl.Michal škola", "X05"],
[6, "6:29", "Sokolov, sídl.Michal škola", "X04"],
[4, "6:31", "Sokolov, Závodu míru", "X04"],
[3, "6:39", "Sokolov, Závodu míru", "X02"],
[1, "6:46", "Březová, aut.st.", "X02"],
[33, "6:49", "Sokolov, sídl.Michal škola", "X04"],
[3, "6:56", "Sokolov,Hrušková", "X04"],
[3, "6:56", "Sokolov, Závodu míru", "X06"],
[3, "6:59", "Sokolov, Závodu míru", "X02"],
[1, "7:01", "Březová, aut.st.", "X03"],
[1, "7:05", "Březová, aut.st.", "X02"],
[3, "7:19", "Sokolov, Závodu míru", "X01"],
[6, "7:23", "Sokolov, sídl.Michal škola", "X04"],
[3, "7:27", "Sokolov, sídl.Michal", "X05"],
[2, "7:31", "Sokolov, sídl.Michal", "X04"],
[3, "7:34", "Sokolov, Závodu míru", "X04"],
[4, "7:34", "Sokolov, Závodu míru", "X02"],
[1, "7:35", "Březová, aut.st.", "X02"],
[3, "7:45", "Sokolov, sídl.Michal", "X02"],
[3, "7:51", "Sokolov, Závodu míru", "X03"],
[1, "7:55", "Březová, aut.st.", "X02"],
[1, "7:57", "Březová, aut.st.", "X03"],
[3, "7:58", "Sokolov, Závodu míru", "X04"],
// and so on
];
}