gtfs-to-html 2.12.1 → 2.12.3

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/gtfs-to-html.ts","../src/lib/file-utils.ts","../src/lib/formatters.ts","../src/lib/time-utils.ts","../src/lib/utils.ts","../src/lib/geojson-utils.ts","../src/lib/log-utils.ts","../src/lib/template-functions.ts","../package.json"],"sourcesContent":["import path from 'node:path';\nimport { mkdir, writeFile } from 'node:fs/promises';\n\nimport { openDb, importGtfs, ConfigAgency } from 'gtfs';\nimport sanitize from 'sanitize-filename';\n\nimport {\n prepDirectory,\n copyStaticAssets,\n generateFolderName,\n renderPdf,\n zipFolder,\n generateCSVFileName,\n untildify,\n} from './file-utils.js';\nimport {\n progressBar,\n generateLogText,\n logStats,\n logError,\n log,\n} from './log-utils.js';\nimport {\n setDefaultConfig,\n getTimetablePagesForAgency,\n getFormattedTimetablePage,\n generateTimetableHTML,\n generateTimetableCSV,\n generateOverviewHTML,\n generateStats,\n} from './utils.js';\n\nimport type { Config } from '../types/index.ts';\n\n/*\n * Generate HTML timetables from GTFS.\n */\n/* eslint-disable complexity */\nconst gtfsToHtml = async (initialConfig: Config) => {\n const config = setDefaultConfig(initialConfig);\n\n // Start timer\n const startTime = process.hrtime.bigint();\n\n const agencyKey = config.agencies\n .map(\n (agency: ConfigAgency & { agencyKey?: string; agency_key?: string }) =>\n agency.agencyKey ?? agency.agency_key ?? 'unknown',\n )\n .join('-');\n const outputPath = config.outputPath\n ? untildify(config.outputPath)\n : path.join(process.cwd(), 'html', sanitize(agencyKey));\n\n await prepDirectory(outputPath, config);\n\n try {\n openDb(config);\n } catch (error: any) {\n if (error?.code === 'SQLITE_CANTOPEN') {\n logError(config)(\n `Unable to open sqlite database \"${config.sqlitePath}\" defined as \\`sqlitePath\\` config.json. Ensure the parent directory exists or remove \\`sqlitePath\\` from config.json.`,\n );\n }\n\n throw error;\n }\n\n if (!config.agencies || config.agencies.length === 0) {\n throw new Error('No agencies defined in `config.json`');\n }\n\n if (!config.skipImport) {\n await importGtfs(config);\n }\n\n const stats: {\n timetables: number;\n timetablePages: number;\n calendars: number;\n routes: number;\n trips: number;\n stops: number;\n warnings: string[];\n [key: string]: number | string[];\n } = {\n timetables: 0,\n timetablePages: 0,\n calendars: 0,\n routes: 0,\n trips: 0,\n stops: 0,\n warnings: [],\n };\n\n const timetablePages = [];\n const timetablePageIds = getTimetablePagesForAgency(config).map(\n (timetablePage) => timetablePage.timetable_page_id,\n );\n\n if (config.noHead !== true && ['html', 'pdf'].includes(config.outputFormat)) {\n await copyStaticAssets(config, outputPath);\n }\n\n const bar = progressBar(\n `${agencyKey}: Generating ${config.outputFormat.toUpperCase()} timetables {bar} {value}/{total}`,\n timetablePageIds.length,\n config,\n );\n\n /* eslint-disable no-await-in-loop */\n for (const timetablePageId of timetablePageIds) {\n try {\n const timetablePage = await getFormattedTimetablePage(\n timetablePageId as string,\n config,\n );\n\n for (const timetable of timetablePage.consolidatedTimetables) {\n if (timetable.warnings) {\n for (const warning of timetable.warnings) {\n stats.warnings.push(warning);\n bar?.interrupt(warning);\n }\n }\n }\n\n if (timetablePage.consolidatedTimetables.length === 0) {\n throw new Error(\n `No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`,\n );\n }\n\n stats.timetables += timetablePage.consolidatedTimetables.length;\n stats.timetablePages += 1;\n\n const datePath = generateFolderName(timetablePage);\n\n // Make directory if it doesn't exist\n await mkdir(path.join(outputPath, datePath), { recursive: true });\n config.assetPath = '../';\n\n timetablePage.relativePath = path.join(\n datePath,\n sanitize(timetablePage.filename),\n );\n\n if (config.outputFormat === 'csv') {\n for (const timetable of timetablePage.consolidatedTimetables) {\n const csv = await generateTimetableCSV(timetable);\n const csvPath = path.join(\n outputPath,\n datePath,\n generateCSVFileName(timetable, config),\n );\n await writeFile(csvPath, csv);\n }\n } else {\n const html = await generateTimetableHTML(timetablePage, config);\n const htmlPath = path.join(\n outputPath,\n datePath,\n sanitize(timetablePage.filename),\n );\n await writeFile(htmlPath, html);\n\n if (config.outputFormat === 'pdf') {\n await renderPdf(htmlPath);\n }\n }\n\n timetablePages.push(timetablePage);\n const timetableStats = generateStats(timetablePage);\n\n stats.stops += timetableStats.stops;\n stats.routes += timetableStats.routes;\n stats.trips += timetableStats.trips;\n stats.calendars += timetableStats.calendars;\n } catch (error: any) {\n stats.warnings.push(error?.message);\n bar?.interrupt(error.message);\n }\n\n bar?.increment();\n }\n /* eslint-enable no-await-in-loop */\n\n if (config.outputFormat === 'html') {\n // Generate overview HTML\n config.assetPath = '';\n const html = await generateOverviewHTML(timetablePages, config);\n await writeFile(path.join(outputPath, 'index.html'), html);\n }\n\n // Generate log.txt\n const logText = generateLogText(stats, config);\n await writeFile(path.join(outputPath, 'log.txt'), logText);\n\n // Zip output, if specified\n if (config.zipOutput) {\n await zipFolder(outputPath);\n }\n\n const fullOutputPath = path.join(\n outputPath,\n config.zipOutput ? '/timetables.zip' : '',\n );\n\n // Print stats\n log(config)(\n `${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullOutputPath}`,\n );\n\n logStats(config)(stats);\n\n const endTime = process.hrtime.bigint();\n const elapsedSeconds = Number(endTime - startTime) / 1_000_000_000;\n\n log(config)(\n `${agencyKey}: ${config.outputFormat.toUpperCase()} timetable generation required ${elapsedSeconds.toFixed(1)} seconds`,\n );\n\n return fullOutputPath;\n};\n/* eslint-enable complexity */\n\nexport default gtfsToHtml;\n","import { dirname, join, resolve } from 'node:path';\nimport cssEscape from 'css.escape';\nimport { createWriteStream } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport {\n access,\n cp,\n copyFile,\n mkdir,\n readdir,\n readFile,\n rm,\n} from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { findPackageJSON } from 'node:module';\n\nimport * as _ from 'lodash-es';\nimport { uniqBy } from 'lodash-es';\nimport archiver from 'archiver';\nimport beautify from 'js-beautify';\nimport sanitizeHtml from 'sanitize-html';\nimport { renderFile } from 'pug';\nimport puppeteer from 'puppeteer';\nimport sanitize from 'sanitize-filename';\nimport { marked } from 'marked';\n\nimport {\n isNullOrEmpty,\n formatDays,\n formatRouteColor,\n formatRouteTextColor,\n formatRouteNameForFilename,\n} from './formatters.js';\nimport * as templateFunctions from './template-functions.js';\n\nimport type {\n Config,\n FormattedTimetable,\n FormattedTimetablePage,\n} from '../types/index.ts';\n\nconst homeDirectory = homedir();\n\n/*\n * Attempt to parse the specified config JSON file.\n */\nexport async function getConfig(argv) {\n let data;\n let config;\n\n try {\n data = await readFile(resolve(untildify(argv.configPath)), 'utf8');\n } catch (error) {\n throw new Error(\n `Cannot find configuration file at \\`${argv.configPath}\\`. Use config-sample.json as a starting point, pass --configPath option`,\n );\n }\n\n try {\n config = JSON.parse(data);\n } catch (error) {\n throw new Error(\n `Cannot parse configuration file at \\`${argv.configPath}\\`. Check to ensure that it is valid JSON.`,\n );\n }\n\n if (argv.skipImport === true) {\n config.skipImport = argv.skipImport;\n }\n\n if (argv.showOnlyTimepoint === true) {\n config.showOnlyTimepoint = argv.showOnlyTimepoint;\n }\n\n return config;\n}\n\n/*\n * Get the full path to the views folder.\n */\nexport function getPathToViewsFolder(config: Config) {\n if (config.templatePath) {\n return untildify(config.templatePath);\n }\n\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n // Dynamically calculate the path to the views directory\n let viewsFolderPath;\n if (__dirname.endsWith('/dist/bin') || __dirname.endsWith('/dist/app')) {\n // When the file is in 'dist/bin' or 'dist/app'\n viewsFolderPath = resolve(__dirname, '../../views/default');\n } else if (__dirname.endsWith('/dist')) {\n // When the file is in 'dist'\n viewsFolderPath = resolve(__dirname, '../views/default');\n } else {\n // In case it's neither, fallback to project root\n viewsFolderPath = resolve(__dirname, '../../views/default');\n }\n\n return viewsFolderPath;\n}\n\n/*\n * Get the full path of a template file.\n */\nfunction getPathToTemplateFile(templateFileName: string, config: Config) {\n const fullTemplateFileName =\n config.noHead !== true\n ? `${templateFileName}_full.pug`\n : `${templateFileName}.pug`;\n\n return join(getPathToViewsFolder(config), fullTemplateFileName);\n}\n\n/*\n * Prepare the outputPath directory for writing timetable files.\n */\nexport async function prepDirectory(outputPath: string, config: Config) {\n // Check if outputPath exists\n try {\n await access(outputPath);\n } catch (error: any) {\n try {\n await mkdir(outputPath, { recursive: true });\n } catch (error: any) {\n if (error?.code === 'ENOENT') {\n throw new Error(\n `Unable to write to ${outputPath}. Try running this command from a writable directory.`,\n );\n }\n\n throw error;\n }\n }\n\n // Check if outputPath is empty\n const files = await readdir(outputPath);\n if (config.overwriteExistingFiles === false && files.length > 0) {\n throw new Error(\n `Output directory ${outputPath} is not empty. Please specify an empty directory.`,\n );\n }\n\n // Delete all files in outputPath if `overwriteExistingFiles` is true\n if (config.overwriteExistingFiles === true) {\n await rm(join(outputPath, '*'), { recursive: true, force: true });\n }\n}\n\n/*\n * Copy needed CSS and JS to export path.\n */\nexport async function copyStaticAssets(config: Config, outputPath: string) {\n const viewsFolderPath = getPathToViewsFolder(config);\n\n const foldersToCopy = ['css', 'js', 'img'];\n\n for (const folder of foldersToCopy) {\n if (\n await access(join(viewsFolderPath, folder))\n .then(() => true)\n .catch(() => false)\n ) {\n await cp(join(viewsFolderPath, folder), join(outputPath, folder), {\n recursive: true,\n });\n }\n }\n\n // Copy js libraries from node_modules if needed for GTFS-Realtime\n if (\n config.hasGtfsRealtimeVehiclePositions ||\n config.hasGtfsRealtimeTripUpdates ||\n config.hasGtfsRealtimeAlerts\n ) {\n await copyFile(\n join(\n dirname(findPackageJSON('pbf', import.meta.url) as string),\n 'dist/pbf.js',\n ),\n join(outputPath, 'js/pbf.js'),\n );\n\n await copyFile(\n join(\n dirname(\n findPackageJSON(\n 'gtfs-realtime-pbf-js-module',\n import.meta.url,\n ) as string,\n ),\n 'gtfs-realtime.browser.proto.js',\n ),\n join(outputPath, 'js/gtfs-realtime.browser.proto.js'),\n );\n }\n\n if (config.hasGtfsRealtimeAlerts) {\n await copyFile(\n join(\n dirname(findPackageJSON('anchorme', import.meta.url) as string),\n 'dist/browser/anchorme.min.js',\n ),\n join(outputPath, 'js/anchorme.min.js'),\n );\n }\n\n if (config.showMap) {\n await copyFile(\n join(\n dirname(findPackageJSON('maplibre-gl', import.meta.url) as string),\n 'dist/maplibre-gl.js',\n ),\n join(outputPath, 'js/maplibre-gl.js'),\n );\n\n await copyFile(\n join(\n dirname(findPackageJSON('maplibre-gl', import.meta.url) as string),\n 'dist/maplibre-gl.css',\n ),\n join(outputPath, 'css/maplibre-gl.css'),\n );\n\n await copyFile(\n join(\n dirname(\n findPackageJSON(\n '@maplibre/maplibre-gl-geocoder',\n import.meta.url,\n ) as string,\n ),\n 'dist/maplibre-gl-geocoder.js',\n ),\n join(outputPath, 'js/maplibre-gl-geocoder.js'),\n );\n\n await copyFile(\n join(\n dirname(\n findPackageJSON(\n '@maplibre/maplibre-gl-geocoder',\n import.meta.url,\n ) as string,\n ),\n 'dist/maplibre-gl-geocoder.css',\n ),\n join(outputPath, 'css/maplibre-gl-geocoder.css'),\n );\n }\n}\n\n/*\n * Zips the content of the specified folder.\n */\nexport function zipFolder(outputPath) {\n const output = createWriteStream(join(outputPath, 'timetables.zip'));\n const archive = archiver('zip');\n\n return new Promise((resolve, reject) => {\n output.on('close', resolve);\n archive.on('error', reject);\n archive.pipe(output);\n archive.glob('**/*.{txt,css,js,png,jpg,jpeg,svg,csv,pdf,html}', {\n cwd: outputPath,\n });\n archive.finalize();\n });\n}\n\n/*\n * Generate the filename for an html file.\n */\nexport function generateTimetablePageFileName(\n timetablePage: FormattedTimetablePage,\n config: Config,\n) {\n // If the timetable page is from timetable_pages.txt, use the filename specified.\n if (timetablePage.filename) {\n return sanitize(timetablePage.filename);\n }\n\n // Else if config.groupTimetablesIntoPages is true and all timetables share the same route, use the route as the filename\n if (\n config.groupTimetablesIntoPages === true &&\n uniqBy(timetablePage.timetables, 'route_id').length === 1\n ) {\n const route = timetablePage.timetables[0].routes[0];\n return sanitize(`${formatRouteNameForFilename(route).toLowerCase()}.html`);\n }\n\n const timetable = timetablePage.timetables[0];\n\n // Else use timetable_id for filename\n if (timetable.timetable_id) {\n return sanitize(\n `${timetable.timetable_id.replace(/\\|/g, '_').toLowerCase()}.html`,\n );\n }\n\n // Else generate a detailed filename\n let filename = '';\n\n for (const route of timetable.routes) {\n filename += `_${formatRouteNameForFilename(route)}`;\n }\n\n if (!isNullOrEmpty(timetable.direction_id)) {\n filename += `_${timetable.direction_id}`;\n }\n\n filename += `_${formatDays(timetable, config).replace(/\\s/g, '')}.html`;\n\n return sanitize(filename.toLowerCase());\n}\n\n/*\n * Generate the filename for a csv file.\n */\nexport function generateCSVFileName(\n timetable: FormattedTimetable,\n config: Config,\n) {\n let filename = timetable.timetable_id ?? '';\n\n for (const route of timetable.routes) {\n filename += `_${formatRouteNameForFilename(route)}`;\n }\n\n if (!isNullOrEmpty(timetable.direction_id)) {\n filename += `_${timetable.direction_id}`;\n }\n\n filename += `_${formatDays(timetable, config).replace(/\\s/g, '')}.csv`;\n\n return sanitize(filename).toLowerCase();\n}\n\n/*\n * Generates the folder name for a timetable page based on the date.\n */\nexport function generateFolderName(timetablePage) {\n // Use first timetable in timetable page for start date and end date\n const timetable = timetablePage.consolidatedTimetables[0];\n if (!timetable.start_date || !timetable.end_date) {\n return 'timetables';\n }\n\n return sanitize(`${timetable.start_date}-${timetable.end_date}`);\n}\n\n/*\n * Render the HTML for a timetable based on the config.\n */\nexport async function renderTemplate(\n templateFileName: string,\n templateVars,\n config: Config,\n) {\n const templatePath = getPathToTemplateFile(templateFileName, config);\n\n // Make template functions, lodash and marked available inside pug templates.\n const html = await renderFile(templatePath, {\n _,\n cssEscape,\n md: (text: string) => sanitizeHtml(marked.parseInline(text) as string),\n ...templateFunctions,\n formatRouteColor,\n formatRouteTextColor,\n ...templateVars,\n });\n\n // Beautify HTML if `beautify` is set in config.\n if (config.beautify === true) {\n return beautify.html_beautify(html, {\n indent_size: 2,\n });\n }\n\n return html;\n}\n\n/*\n * Render the PDF for a timetable based on the config.\n */\nexport async function renderPdf(htmlPath: string) {\n const pdfPath = htmlPath.replace(/html$/, 'pdf');\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.emulateMediaType('print');\n await page.goto(`file://${htmlPath}`, {\n waitUntil: 'networkidle0',\n });\n await page.pdf({\n path: pdfPath,\n });\n\n await browser.close();\n}\n\n/**\n * Converts a tilde path to a full path\n * @param pathWithTilde The path to convert\n * @returns The full path\n */\nexport function untildify(pathWithTilde: string): string {\n return homeDirectory\n ? pathWithTilde.replace(/^~(?=$|\\/|\\\\)/, homeDirectory)\n : pathWithTilde;\n}\n","import {\n clone,\n find,\n first,\n groupBy,\n last,\n omit,\n sortBy,\n zipObject,\n} from 'lodash-es';\nimport moment from 'moment';\nimport { Route } from 'gtfs';\n\nimport {\n fromGTFSTime,\n minutesAfterMidnight,\n calendarToCalendarCode,\n secondsAfterMidnight,\n toGTFSTime,\n updateTimeByOffset,\n} from './time-utils.js';\nimport { isTimepoint } from './utils.js';\n\n/*\n * Replace all instances in a string with items from an object.\n */\nfunction replaceAll(string, mapObject) {\n const re = new RegExp(Object.keys(mapObject).join('|'), 'gi');\n return string.replace(re, (matched) => mapObject[matched]);\n}\n\n/*\n * Determine if value is null or empty string.\n */\nexport function isNullOrEmpty(value) {\n return value === null || value === '';\n}\n\n/*\n * Format a date for display.\n */\nexport function formatDate(date, dateFormat) {\n if (date.holiday_name) {\n return date.holiday_name;\n }\n\n return moment(date.date, 'YYYYMMDD').format(dateFormat);\n}\n\n/*\n * Convert time to seconds.\n */\nexport function timeToSeconds(time) {\n return moment.duration(time).asSeconds();\n}\n\n/*\n * Format a single stoptime.\n */\n/* eslint-disable complexity */\nfunction formatStopTime(stoptime, timetable, config) {\n stoptime.classes = [];\n\n if (stoptime.type === 'arrival' && stoptime.arrival_time) {\n const arrivalTime = fromGTFSTime(stoptime.arrival_time);\n stoptime.formatted_time = arrivalTime.format(config.timeFormat);\n stoptime.classes.push(arrivalTime.format('a'));\n } else if (stoptime.type === 'departure' && stoptime.departure_time) {\n const departureTime = fromGTFSTime(stoptime.departure_time);\n stoptime.formatted_time = departureTime.format(config.timeFormat);\n stoptime.classes.push(departureTime.format('a'));\n }\n\n if (stoptime.pickup_type === 1) {\n stoptime.noPickup = true;\n stoptime.classes.push('no-pickup');\n if (timetable.noPickupSymbol !== null) {\n timetable.noPickupSymbolUsed = true;\n }\n } else if (stoptime.pickup_type === 2 || stoptime.pickup_type === 3) {\n stoptime.requestPickup = true;\n stoptime.classes.push('request-pickup');\n if (timetable.requestPickupSymbol !== null) {\n timetable.requestPickupSymbolUsed = true;\n }\n }\n\n if (stoptime.drop_off_type === 1) {\n stoptime.noDropoff = true;\n stoptime.classes.push('no-drop-off');\n if (timetable.noDropoffSymbol !== null) {\n timetable.noDropoffSymbolUsed = true;\n }\n } else if (stoptime.drop_off_type === 2 || stoptime.drop_off_type === 3) {\n stoptime.requestDropoff = true;\n stoptime.classes.push('request-drop-off');\n if (timetable.requestDropoffSymbol !== null) {\n timetable.requestDropoffSymbolUsed = true;\n }\n }\n\n if (stoptime.timepoint === 0 || stoptime.departure_time === '') {\n stoptime.interpolated = true;\n stoptime.classes.push('interpolated');\n if (timetable.interpolatedStopSymbol !== null) {\n timetable.interpolatedStopSymbolUsed = true;\n }\n }\n\n if (\n stoptime.timepoint === null &&\n stoptime.departure_time === null &&\n stoptime.stop_sequence === null\n ) {\n stoptime.skipped = true;\n stoptime.classes.push('skipped');\n if (timetable.noServiceSymbol !== null) {\n timetable.noServiceSymbolUsed = true;\n }\n }\n\n if (stoptime.timepoint === 1) {\n stoptime.classes.push('timepoint');\n }\n\n return stoptime;\n}\n/* eslint-enable complexity */\n\n/*\n * Find hourly times for each stop for hourly schedules.\n */\nfunction filterHourlyTimes(stops) {\n // Find all stoptimes within the first 60 minutes.\n const firstStopTimes = [];\n const firstTripMinutes = minutesAfterMidnight(stops[0].trips[0].arrival_time);\n for (const trip of stops[0].trips) {\n const minutes = minutesAfterMidnight(trip.arrival_time);\n if (minutes >= firstTripMinutes + 60) {\n break;\n }\n\n firstStopTimes.push(fromGTFSTime(trip.arrival_time));\n }\n\n // Sort stoptimes by minutes for first stop.\n const firstStopTimesAndIndex = firstStopTimes.map((time, idx) => ({\n idx,\n time,\n }));\n const sortedFirstStopTimesAndIndex = sortBy(firstStopTimesAndIndex, (item) =>\n Number.parseInt(item.time.format('m'), 10),\n );\n\n // Filter and arrange stoptimes for all stops based on sort.\n return stops.map((stop) => {\n stop.hourlyTimes = sortedFirstStopTimesAndIndex.map((item) =>\n fromGTFSTime(stop.trips[item.idx].arrival_time).format(':mm'),\n );\n\n return stop;\n });\n}\n\n/*\n * Format a calendar's list of days for display using abbreviated day names.\n */\nconst days = [\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n 'sunday',\n];\nexport function formatDays(calendar, config) {\n const daysShort = config.daysShortStrings;\n let daysInARow = 0;\n let dayString = '';\n\n if (!calendar) {\n return '';\n }\n\n for (let i = 0; i <= 6; i += 1) {\n const currentDayOperating = calendar[days[i]] === 1;\n const previousDayOperating = i > 0 ? calendar[days[i - 1]] === 1 : false;\n const nextDayOperating = i < 6 ? calendar[days[i + 1]] === 1 : false;\n\n if (currentDayOperating) {\n if (dayString.length > 0) {\n if (!previousDayOperating) {\n dayString += ', ';\n } else if (daysInARow === 1) {\n dayString += '-';\n }\n }\n\n daysInARow += 1;\n\n if (\n dayString.length === 0 ||\n !nextDayOperating ||\n i === 6 ||\n !previousDayOperating\n ) {\n dayString += daysShort[i];\n }\n } else {\n daysInARow = 0;\n }\n }\n\n if (dayString.length === 0) {\n dayString = config.noRegularServiceDaysText;\n }\n\n return dayString;\n}\n\n/*\n * Format a list of days for display using full names of days.\n */\nexport function formatDaysLong(dayList, config) {\n const mapObject = zipObject(config.daysShortStrings, config.daysStrings);\n\n return replaceAll(dayList, mapObject);\n}\n\n/*\n * Format a trip.\n */\nexport function formatTrip(trip, timetable, calendars, config) {\n trip.calendar = find(calendars, {\n service_id: trip.service_id,\n });\n trip.dayList = formatDays(trip.calendar, config);\n trip.dayListLong = formatDaysLong(trip.dayList, config);\n\n if (timetable.routes.length === 1) {\n trip.route_short_name = timetable.routes[0].route_short_name;\n } else {\n const route = timetable.routes.find(\n (route) => route.route_id === trip.route_id,\n );\n trip.route_short_name = route.route_short_name;\n }\n\n return trip;\n}\n\n/*\n * Format a frequency.\n */\nexport function formatFrequency(frequency, config) {\n const startTime = fromGTFSTime(frequency.start_time);\n const endTime = fromGTFSTime(frequency.end_time);\n const headway = moment.duration(frequency.headway_secs, 'seconds');\n frequency.start_formatted_time = startTime.format(config.timeFormat);\n frequency.end_formatted_time = endTime.format(config.timeFormat);\n frequency.headway_min = Math.round(headway.asMinutes());\n return frequency;\n}\n\n/*\n * Generate a timetable id.\n */\nexport function formatTimetableId({\n routeIds,\n directionId,\n days,\n dates,\n}: {\n routeIds: string[];\n directionId?: 0 | 1;\n days: {\n monday?: null | 0 | 1;\n tuesday?: null | 0 | 1;\n wednesday?: null | 0 | 1;\n thursday?: null | 0 | 1;\n friday?: null | 0 | 1;\n saturday?: null | 0 | 1;\n sunday?: null | 0 | 1;\n };\n dates?: number[];\n}) {\n let timetableId = routeIds.join('_');\n\n if (calendarToCalendarCode(days)) {\n timetableId += `|${calendarToCalendarCode(days)}`;\n } else if (dates && dates.length > 0) {\n timetableId += `|${dates.join('_')}`;\n }\n\n if (!isNullOrEmpty(directionId)) {\n timetableId += `|${directionId}`;\n }\n\n return timetableId;\n}\n\nfunction createEmptyStoptime(stopId, tripId) {\n return {\n id: null,\n trip_id: tripId,\n arrival_time: null,\n departure_time: null,\n stop_id: stopId,\n stop_sequence: null,\n stop_headsign: null,\n pickup_type: null,\n drop_off_type: null,\n continuous_pickup: null,\n continuous_drop_off: null,\n shape_dist_traveled: null,\n timepoint: null,\n };\n}\n\n/*\n * Format stops.\n */\nexport function formatStops(timetable, config) {\n for (const trip of timetable.orderedTrips) {\n let stopIndex = -1;\n for (const [idx, stoptime] of trip.stoptimes.entries()) {\n // Find a stop for the matching `stop_id` greater than the last `stopIndex`.\n const stop = find(timetable.stops, (st, idx) => {\n if (st.stop_id === stoptime.stop_id && idx > stopIndex) {\n stopIndex = idx;\n return true;\n }\n\n return false;\n });\n\n if (!stop) {\n continue;\n }\n\n // If first stoptime of the trip, remove drop_off_type information\n if (idx === 0) {\n stoptime.drop_off_type = 0;\n }\n\n // If last stoptime of the trip, remove pickup_type information\n if (idx === trip.stoptimes.length - 1) {\n stoptime.pickup_type = 0;\n }\n\n // If showing arrival and departure times as separate columns/rows, add\n // trip to the departure stop, unless it is the last stoptime of the trip.\n if (stop.type === 'arrival' && idx < trip.stoptimes.length - 1) {\n const departureStoptime = clone(stoptime);\n departureStoptime.type = 'departure';\n timetable.stops[stopIndex + 1].trips.push(\n formatStopTime(departureStoptime, timetable, config),\n );\n }\n\n // Show times if it is an arrival stop and is the first stoptime for the trip.\n if (!(stop.type === 'arrival' && idx === 0)) {\n stoptime.type = 'arrival';\n stop.trips.push(formatStopTime(stoptime, timetable, config));\n }\n }\n\n // Fill in any missing stoptimes for this trip.\n for (const stop of timetable.stops) {\n const lastStopTime = last(stop.trips);\n if (!lastStopTime || lastStopTime.trip_id !== trip.trip_id) {\n stop.trips.push(\n formatStopTime(\n createEmptyStoptime(stop.stop_id, trip.trip_id),\n timetable,\n config,\n ),\n );\n }\n }\n }\n\n if (timetable.orientation === 'hourly') {\n timetable.stops = filterHourlyTimes(timetable.stops);\n }\n\n for (const stop of timetable.stops) {\n stop.is_timepoint = stop.trips.some((stoptime) => isTimepoint(stoptime));\n }\n\n return timetable.stops;\n}\n\n/*\n * Formats a stop name.\n */\nexport function formatStopName(stop) {\n return `${stop.stop_name}${\n stop.type === 'arrival'\n ? ' (Arrival)'\n : stop.type === 'departure'\n ? ' (Departure)'\n : ''\n }`;\n}\n\n/*\n * Formats trip \"Continues from\".\n */\nexport function formatTripContinuesFrom(trip) {\n return trip.continues_from_route\n ? trip.continues_from_route.route.route_short_name\n : '';\n}\n\n/*\n * Formats trip \"Continues as\".\n */\nexport function formatTripContinuesAs(trip) {\n return trip.continues_as_route\n ? trip.continues_as_route.route.route_short_name\n : '';\n}\n\n/*\n * Change all stoptimes of a trip so the first trip starts at midnight. Useful\n * for hourly schedules.\n */\nexport function resetStoptimesToMidnight(trip) {\n const offsetSeconds = secondsAfterMidnight(\n first(trip.stoptimes).departure_time,\n );\n if (offsetSeconds > 0) {\n for (const stoptime of trip.stoptimes) {\n stoptime.departure_time = toGTFSTime(\n fromGTFSTime(stoptime.departure_time).subtract(\n offsetSeconds,\n 'seconds',\n ),\n );\n stoptime.arrival_time = toGTFSTime(\n fromGTFSTime(stoptime.arrival_time).subtract(offsetSeconds, 'seconds'),\n );\n }\n }\n\n return trip;\n}\n\n/*\n * Change all stoptimes of a trip by a specified number of seconds. Useful for\n * hourly schedules.\n */\nexport function updateStoptimesByOffset(trip, offsetSeconds) {\n return trip.stoptimes.map((stoptime) => {\n delete stoptime._id;\n stoptime.departure_time = updateTimeByOffset(\n stoptime.departure_time,\n offsetSeconds,\n );\n stoptime.arrival_time = updateTimeByOffset(\n stoptime.arrival_time,\n offsetSeconds,\n );\n stoptime.trip_id = trip.trip_id;\n return stoptime;\n });\n}\n\n/*\n * Format a route color as a hex color.\n */\nexport function formatRouteColor(route) {\n // Defaults to #000000 (black) if no color is provided.\n return route.route_color ? `#${route.route_color}` : '#000000';\n}\n\n/*\n * Format a route text color as a hex color.\n */\nexport function formatRouteTextColor(route) {\n // Defaults to #FFFFFF (white) if no color is provided.\n return route.route_text_color ? `#${route.route_text_color}` : '#FFFFFF';\n}\n\n/*\n * Format a label for a timetable.\n */\nexport function formatTimetableLabel(timetable) {\n if (!isNullOrEmpty(timetable.timetable_label)) {\n return timetable.timetable_label;\n }\n\n let timetableLabel = '';\n\n if (timetable.routes && timetable.routes.length > 0) {\n timetableLabel += 'Route ';\n if (!isNullOrEmpty(timetable.routes[0].route_short_name)) {\n timetableLabel += timetable.routes[0].route_short_name;\n } else if (!isNullOrEmpty(timetable.routes[0].route_long_name)) {\n timetableLabel += timetable.routes[0].route_long_name;\n }\n }\n\n if (timetable.stops && timetable.stops.length > 0) {\n const firstStop = timetable.stops[0].stop_name;\n const lastStop = timetable.stops[timetable.stops.length - 1].stop_name;\n if (firstStop === lastStop) {\n if (!isNullOrEmpty(timetable.routes[0].route_long_name)) {\n timetableLabel += ` - ${timetable.routes[0].route_long_name}`;\n }\n\n timetableLabel += ' - Loop';\n } else {\n timetableLabel += ` - ${firstStop} to ${lastStop}`;\n }\n } else if (timetable.direction_name !== null) {\n timetableLabel += ` to ${timetable.direction_name}`;\n }\n\n return timetableLabel;\n}\n\n/*\n * Format a route name.\n */\nexport const formatRouteName = (route: Route) => {\n if (route.route_long_name === null || route.route_long_name === '') {\n return `Route ${route.route_short_name}`;\n }\n\n return route.route_long_name ?? 'Unknown';\n};\n\n/*\n * Format a route name for use in a filename.\n */\nexport const formatRouteNameForFilename = (route: Route) => {\n if (route.route_short_name) {\n return route.route_short_name.replace(/\\s/g, '-');\n } else if (route.route_long_name) {\n return route.route_long_name.replace(/\\s/g, '-');\n }\n\n return 'Unknown';\n};\n\n/*\n * Format a list for display.\n */\nexport const formatListForDisplay = (list: string[]) => {\n return new Intl.ListFormat('en-US', {\n style: 'long',\n type: 'conjunction',\n }).format(list);\n};\n\n/*\n * Merge timetables with same `timetable_id`.\n */\nexport function mergeTimetablesWithSameId(timetables) {\n if (timetables.length === 0) {\n return [];\n }\n\n const mergedTimetables = groupBy(timetables, 'timetable_id');\n\n return Object.values(mergedTimetables).map((timetableGroup) => {\n const mergedTimetable = omit(timetableGroup[0], 'route_id');\n\n mergedTimetable.route_ids = timetableGroup.map(\n (timetable) => timetable.route_id,\n );\n\n return mergedTimetable;\n });\n}\n","import moment from 'moment';\n\n/*\n * Convert a GTFS formatted time string into a moment less than 24 hours.\n */\nexport function fromGTFSTime(timeString) {\n const duration = moment.duration(timeString);\n\n return moment({\n hour: duration.hours(),\n minute: duration.minutes(),\n second: duration.seconds(),\n });\n}\n\n/*\n * Convert a moment into a GTFS formatted time string.\n */\nexport function toGTFSTime(time) {\n return time.format('HH:mm:ss');\n}\n\n/*\n * Convert a object of weekdays into a a string containing 1s and 0s.\n */\nexport function calendarToCalendarCode(c: {\n monday?: null | 0 | 1;\n tuesday?: null | 0 | 1;\n wednesday?: null | 0 | 1;\n thursday?: null | 0 | 1;\n friday?: null | 0 | 1;\n saturday?: null | 0 | 1;\n sunday?: null | 0 | 1;\n}) {\n if (Object.values(c).every((value) => value === null)) {\n return '';\n }\n\n return `${c.monday}${c.tuesday}${c.wednesday}${c.thursday}${c.friday}${c.saturday}${c.sunday}`;\n}\n\n/*\n * Convert a string of 1s and 0s representing a weekday to an object.\n */\nexport function calendarCodeToCalendar(code) {\n const days = [\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n 'sunday',\n ];\n const calendar = {};\n\n for (const [index, day] of days.entries()) {\n calendar[day] = code[index];\n }\n\n return calendar;\n}\n\n/*\n * Get number of seconds after midnight of a GTFS formatted time string.\n */\nexport function secondsAfterMidnight(timeString) {\n return moment.duration(timeString).asSeconds();\n}\n\n/*\n * Get number of minutes after midnight of a GTFS formatted time string.\n */\nexport function minutesAfterMidnight(timeString) {\n return moment.duration(timeString).asMinutes();\n}\n\n/*\n * Add specified number of seconds to a GTFS formatted time string.\n */\nexport function updateTimeByOffset(timeString, offsetSeconds) {\n const newTime = fromGTFSTime(timeString);\n return toGTFSTime(newTime.add(offsetSeconds, 'seconds'));\n}\n","import {\n cloneDeep,\n compact,\n countBy,\n difference,\n entries,\n every,\n find,\n findLast,\n first,\n flatMap,\n flow,\n groupBy,\n head,\n last,\n maxBy,\n orderBy,\n partialRight,\n reduce,\n size,\n some,\n sortBy,\n uniq,\n uniqBy,\n zip,\n} from 'lodash-es';\nimport {\n getCalendarDates,\n getTrips,\n getTimetableNotesReferences,\n getTimetableNotes,\n getRoutes,\n getCalendars,\n getTimetableStopOrders,\n getStops,\n getStopAttributes,\n getStoptimes,\n getFrequencies,\n getTimetables,\n getTimetablePages,\n getAgencies,\n openDb,\n Calendar,\n CalendarDate,\n Frequency,\n Route,\n Trip,\n StopTime,\n Stop,\n} from 'gtfs';\nimport { stringify } from 'csv-stringify';\nimport moment from 'moment';\nimport sqlString from 'sqlstring';\nimport toposort from 'toposort';\n\nimport { generateTimetablePageFileName, renderTemplate } from './file-utils.js';\nimport {\n formatDate,\n formatDays,\n formatDaysLong,\n formatFrequency,\n formatListForDisplay,\n formatRouteName,\n formatStopName,\n formatStops,\n formatTimetableId,\n formatTimetableLabel,\n formatTrip,\n formatTripContinuesAs,\n formatTripContinuesFrom,\n isNullOrEmpty,\n mergeTimetablesWithSameId,\n resetStoptimesToMidnight,\n timeToSeconds,\n updateStoptimesByOffset,\n} from './formatters.js';\nimport { getTimetableGeoJSON, getAgencyGeoJSON } from './geojson-utils.js';\nimport {\n calendarToCalendarCode,\n secondsAfterMidnight,\n fromGTFSTime,\n calendarCodeToCalendar,\n} from './time-utils.js';\nimport { formatTripNameForCSV } from './template-functions.js';\n\nimport type {\n Config,\n FormattedTimetable,\n FormattedTimetablePage,\n} from '../types/index.ts';\n\nimport packageJson from '../../package.json' with { type: 'json' };\nconst { version } = packageJson;\n\ntype FormattedTrip = Trip & {\n firstStoptime: number;\n lastStoptime: number;\n stoptimes: StopTime[];\n};\n\n/*\n * Determine if a stoptime is a timepoint.\n */\nexport const isTimepoint = (stoptime: StopTime) => {\n if (isNullOrEmpty(stoptime.timepoint)) {\n return (\n !isNullOrEmpty(stoptime.arrival_time) &&\n !isNullOrEmpty(stoptime.departure_time)\n );\n }\n\n return stoptime.timepoint === 1;\n};\n\n/*\n * Find the longest trip (most stops) in a group of trips and return stoptimes.\n */\nconst getLongestTripStoptimes = (trips: FormattedTrip[], config: Config) => {\n const filteredTripStoptimes = trips.map((trip) =>\n trip.stoptimes.filter((stoptime) => {\n // If `showOnlyTimepoint` is true, then filter out all non-timepoints.\n if (config.showOnlyTimepoint === true) {\n return isTimepoint(stoptime);\n }\n return true;\n }),\n );\n\n return maxBy(filteredTripStoptimes, (stoptimes) => size(stoptimes));\n};\n\n/*\n * Find the first stop_id that all trips have in common, otherwise use the first\n * stoptime.\n */\nconst findCommonStopId = (trips: FormattedTrip[], config: Config) => {\n const longestTripStoptimes = getLongestTripStoptimes(trips, config);\n\n if (!longestTripStoptimes) {\n return null;\n }\n\n const commonStoptime = longestTripStoptimes.find((stoptime, idx) => {\n // If longest trip is a loop (first and last stops the same), then skip first stoptime.\n if (idx === 0 && stoptime.stop_id === last(longestTripStoptimes)?.stop_id) {\n return false;\n }\n\n // If stoptime doesn't have a time, skip it.\n if (isNullOrEmpty(stoptime.arrival_time)) {\n return false;\n }\n\n // Check if all trips have this stoptime and that they have a time.\n return every(trips, (trip) =>\n trip.stoptimes.find(\n (tripStoptime) =>\n tripStoptime.stop_id === stoptime.stop_id &&\n tripStoptime.arrival_time !== null,\n ),\n );\n });\n\n return commonStoptime ? commonStoptime.stop_id : null;\n};\n\n/*\n * Return a set of unique trips based on departure and arrival times.\n */\nconst deduplicateTrips = (trips: FormattedTrip[]) => {\n if (trips.length <= 1) {\n return trips;\n }\n\n const uniqueTrips = new Map<string, FormattedTrip>();\n\n for (const trip of trips) {\n // Create a unique signature for this trip based on departure and arrival times.\n const tripSignature = trip.stoptimes\n .map(\n (stoptime) =>\n `${stoptime.stop_id}|${stoptime.departure_time}|${stoptime.arrival_time}`,\n )\n .join('|');\n\n if (!uniqueTrips.has(tripSignature)) {\n uniqueTrips.set(tripSignature, trip);\n }\n }\n\n return Array.from(uniqueTrips.values());\n};\n\n/*\n * Sort trips chronologically, using specified config.sortingAlgorithm\n */\nconst sortTrips = (trips: FormattedTrip[], config: Config): FormattedTrip[] => {\n let sortedTrips;\n let commonStopId;\n\n if (config.sortingAlgorithm === 'common') {\n // Sort trips chronologically using the stoptime of a common stop across all trips.\n\n commonStopId = findCommonStopId(trips, config);\n\n if (commonStopId) {\n sortedTrips = sortTripsByStoptimeAtStop(trips, commonStopId);\n } else {\n // Default to 'beginning' if no common stop is found.\n sortedTrips = sortTrips(trips, {\n ...config,\n sortingAlgorithm: 'beginning',\n });\n }\n } else if (config.sortingAlgorithm === 'beginning') {\n // Sort trips chronologically using first stoptime of each trip, which can be at different stops.\n\n for (const trip of trips) {\n if (trip.stoptimes.length === 0) {\n continue;\n }\n\n trip.firstStoptime = timeToSeconds(trip.stoptimes[0].departure_time);\n trip.lastStoptime = timeToSeconds(\n trip.stoptimes[trip.stoptimes.length - 1].departure_time,\n );\n }\n\n sortedTrips = sortBy(trips, ['firstStoptime', 'lastStoptime']);\n } else if (config.sortingAlgorithm === 'end') {\n // Sort trips chronologically using last stoptime of each trip, which can be at different stops.\n\n for (const trip of trips) {\n if (trip.stoptimes.length === 0) {\n continue;\n }\n\n trip.firstStoptime = timeToSeconds(trip.stoptimes[0].departure_time);\n trip.lastStoptime = timeToSeconds(\n trip.stoptimes[trip.stoptimes.length - 1].departure_time,\n );\n }\n\n sortedTrips = sortBy(trips, ['lastStoptime', 'firstStoptime']);\n } else if (config.sortingAlgorithm === 'first') {\n // Sort trips chronologically using the stoptime of a the first stop of the longest trip.\n\n const longestTripStoptimes = getLongestTripStoptimes(trips, config);\n const firstStopId = first(longestTripStoptimes).stop_id;\n sortedTrips = sortTripsByStoptimeAtStop(trips, firstStopId);\n } else if (config.sortingAlgorithm === 'last') {\n // Sort trips chronologically using the stoptime of a the last stop of the longest trip.\n\n const longestTripStoptimes = getLongestTripStoptimes(trips, config);\n const lastStopId = last(longestTripStoptimes).stop_id;\n sortedTrips = sortTripsByStoptimeAtStop(trips, lastStopId);\n }\n\n return sortedTrips ?? [];\n};\n\n/*\n * Sort trips by stoptime at a specific stop\n */\nconst sortTripsByStoptimeAtStop = (trips: FormattedTrip[], stopId: string) =>\n sortBy(trips, (trip) => {\n const stoptime = find(trip.stoptimes, { stop_id: stopId });\n return stoptime ? timeToSeconds(stoptime.departure_time) : undefined;\n });\n\n/*\n * Get all calendar dates for a specific timetable.\n */\nconst getCalendarDatesForTimetable = (\n timetable: FormattedTimetable,\n config: Config,\n) => {\n const calendarDates = getCalendarDates(\n {\n service_id: timetable.service_ids,\n },\n [],\n [['date', 'ASC']],\n );\n const start = moment(timetable.start_date, 'YYYYMMDD');\n const end = moment(timetable.end_date, 'YYYYMMDD');\n const excludedDates = new Set();\n const includedDates = new Set();\n\n for (const calendarDate of calendarDates) {\n if (\n moment(calendarDate.date, 'YYYYMMDD').isBetween(\n start,\n end,\n undefined,\n '[]',\n )\n ) {\n if (calendarDate.exception_type === 1) {\n includedDates.add(formatDate(calendarDate, config.dateFormat));\n } else if (calendarDate.exception_type === 2) {\n excludedDates.add(formatDate(calendarDate, config.dateFormat));\n }\n }\n }\n\n // Remove dates that are both included and excluded from both lists\n const includedAndExcludedDates = new Set(\n [...excludedDates].filter((date) => includedDates.has(date)),\n );\n\n return {\n excludedDates: [...excludedDates].filter(\n (date) => !includedAndExcludedDates.has(date),\n ),\n includedDates: [...includedDates].filter(\n (date) => !includedAndExcludedDates.has(date),\n ),\n };\n};\n\n/*\n * Get days of the week from calendars.\n */\nconst getDaysFromCalendars = (calendars: Calendar[]) => {\n const days = {\n monday: 0,\n tuesday: 0,\n wednesday: 0,\n thursday: 0,\n friday: 0,\n saturday: 0,\n sunday: 0,\n };\n\n for (const calendar of calendars) {\n for (const day of Object.keys(days) as (keyof typeof days)[]) {\n /* eslint-disable-next-line no-bitwise */\n days[day] = days[day] | calendar[day];\n }\n }\n\n return days;\n};\n\n/*\n * Get the `trip_headsign` for a specific timetable.\n */\nconst getDirectionHeadsignFromTimetable = (timetable: FormattedTimetable) => {\n const trips = getTrips(\n {\n direction_id: timetable.direction_id,\n route_id: timetable.route_ids,\n },\n ['trip_headsign'],\n );\n\n if (trips.length === 0) {\n return '';\n }\n\n const mostCommonHeadsign = flow(\n countBy,\n entries,\n partialRight(maxBy, last),\n head,\n )(compact(trips.map((trip) => trip.trip_headsign)));\n\n return mostCommonHeadsign;\n};\n\n/*\n * Get the notes for a specific timetable.\n */\nconst getTimetableNotesForTimetable = (\n timetable: FormattedTimetable,\n config: Config,\n) => {\n const noteReferences = [\n // Get all notes for this timetable.\n ...getTimetableNotesReferences({\n timetable_id: timetable.timetable_id,\n }),\n\n // Get all notes for this route.\n ...getTimetableNotesReferences({\n route_id: timetable.routes.map((route) => route.route_id),\n timetable_id: null,\n }),\n\n // Get all notes for all trips in this timetable.\n ...getTimetableNotesReferences({\n trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),\n }),\n\n // Get all notes for all stops in this timetable.\n ...getTimetableNotesReferences({\n stop_id: timetable.stops.map((stop) => stop.stop_id),\n trip_id: null,\n route_id: null,\n timetable_id: null,\n }),\n ];\n\n const usedNoteReferences = [];\n // Check if stop_sequence matches any trip.\n for (const noteReference of noteReferences) {\n if (\n noteReference.stop_sequence === '' ||\n noteReference.stop_sequence === null\n ) {\n usedNoteReferences.push(noteReference);\n continue;\n }\n\n // Note references with stop_sequence must also have stop_id.\n if (noteReference.stop_id === '' || noteReference.stop_id === null) {\n timetable.warnings.push(\n `Timetable Note Reference for note_id=${noteReference.note_id} has a \\`stop_sequence\\` but no \\`stop_id\\` - ignoring`,\n );\n continue;\n }\n\n const stop = timetable.stops.find(\n (stop) => stop.stop_id === noteReference.stop_id,\n );\n\n if (!stop) {\n continue;\n }\n\n const tripWithMatchingStopSequence = stop.trips.find(\n (trip) => trip.stop_sequence === noteReference.stop_sequence,\n );\n\n if (tripWithMatchingStopSequence) {\n usedNoteReferences.push(noteReference);\n }\n }\n\n const notes = getTimetableNotes({\n note_id: usedNoteReferences.map((noteReference) => noteReference.note_id),\n });\n\n // Assign symbols to each note if unassigned. Use a-z then default to integers.\n const symbols = 'abcdefghijklmnopqrstuvwxyz'.split('');\n let symbolIndex = 0;\n for (const note of notes) {\n if (note.symbol === '' || note.symbol === null) {\n note.symbol =\n symbolIndex < symbols.length - 1\n ? symbols[symbolIndex]\n : symbolIndex - symbols.length;\n symbolIndex += 1;\n }\n }\n\n const formattedNotes = usedNoteReferences.map((noteReference) => ({\n ...noteReference,\n ...notes.find((note) => note.note_id === noteReference.note_id),\n }));\n\n return sortBy(formattedNotes, 'symbol');\n};\n\n/*\n * Create a timetable page from timetables. Used if no\n * `timetable_pages.txt` is present.\n */\nconst createTimetablePage = ({\n timetablePageId,\n timetables,\n config,\n}: {\n timetablePageId: string;\n timetables: FormattedTimetable[];\n config: Config;\n}) => {\n const updatedTimetables = timetables.map((timetable) => {\n if (!timetable.routes) {\n timetable.routes = getRoutes({\n route_id: timetable.route_ids,\n });\n }\n\n return timetable;\n });\n\n const timetablePage = {\n timetable_page_id: timetablePageId,\n timetables: updatedTimetables,\n routes: updatedTimetables.flatMap((timetable) => timetable.routes),\n };\n\n const filename = generateTimetablePageFileName(timetablePage, config);\n\n return {\n ...timetablePage,\n filename,\n };\n};\n\n/*\n * Create a timetable from a route/direction/calendars/calendarDates. Used if no `timetables.txt` is present.\n */\nconst createTimetable = ({\n route,\n directionId,\n tripHeadsign,\n calendars,\n calendarDates,\n}: {\n route: Route;\n directionId?: 0 | 1;\n tripHeadsign?: string;\n calendars?: Calendar[];\n calendarDates?: CalendarDate[];\n}): FormattedTimetable => {\n const serviceIds = uniq([\n ...(calendars?.map((calendar) => calendar.service_id) ?? []),\n ...(calendarDates?.map((calendarDate) => calendarDate.service_id) ?? []),\n ]);\n\n const days: {\n monday: null | 0 | 1;\n tuesday: null | 0 | 1;\n wednesday: null | 0 | 1;\n thursday: null | 0 | 1;\n friday: null | 0 | 1;\n saturday: null | 0 | 1;\n sunday: null | 0 | 1;\n } = {\n monday: null,\n tuesday: null,\n wednesday: null,\n thursday: null,\n friday: null,\n saturday: null,\n sunday: null,\n };\n let startDate: number | null = null;\n let endDate: number | null = null;\n\n if (calendars && calendars.length > 0) {\n Object.assign(days, getDaysFromCalendars(calendars));\n\n startDate = parseInt(\n moment\n .min(\n calendars.map((calendar) => moment(calendar.start_date, 'YYYYMMDD')),\n )\n .format('YYYYMMDD'),\n 10,\n );\n\n endDate = parseInt(\n moment\n .max(calendars.map((calendar) => moment(calendar.end_date, 'YYYYMMDD')))\n .format('YYYYMMDD'),\n 10,\n );\n }\n\n const timetableId = formatTimetableId({\n routeIds: [route.route_id],\n directionId: directionId,\n days: days,\n dates: calendarDates?.map((calendarDate) => calendarDate.date),\n });\n\n return {\n timetable_id: timetableId,\n route_ids: [route.route_id],\n direction_id: directionId === null ? null : directionId,\n direction_name: tripHeadsign === null ? null : tripHeadsign,\n routes: [route],\n include_exceptions: calendarDates && calendarDates.length > 0 ? 1 : 0,\n service_ids: serviceIds,\n service_notes: null,\n timetable_label: null,\n start_time: null,\n end_time: null,\n orientation: null,\n timetable_sequence: null,\n show_trip_continuation: null,\n start_date: startDate,\n end_date: endDate,\n ...days,\n };\n};\n\n/*\n * Create timetable pages for all routes in an agency. Used if no\n * `timetables.txt` is present.\n */\nconst convertRoutesToTimetablePages = (config: Config) => {\n const routes = getRoutes();\n const timetablePages: FormattedTimetablePage[] = [];\n const { calendars, calendarDates } = getCalendarsFromConfig(config);\n\n for (const route of routes) {\n const trips = getTrips(\n {\n route_id: route.route_id,\n },\n ['trip_headsign', 'direction_id', 'trip_id', 'service_id'],\n );\n const uniqueTripDirections = orderBy(\n uniqBy(trips, (trip) => trip.direction_id),\n 'direction_id',\n );\n const sortedCalendars = orderBy(calendars, calendarToCalendarCode, 'desc');\n const calendarGroups = groupBy(sortedCalendars, calendarToCalendarCode);\n const calendarDateGroups = groupBy(calendarDates, 'service_id');\n\n const timetables: Timetable[] = [];\n\n for (const uniqueTripDirection of uniqueTripDirections) {\n for (const calendars of Object.values(calendarGroups)) {\n const tripsForCalendars = trips.filter((trip) =>\n some(calendars, { service_id: trip.service_id }),\n );\n if (tripsForCalendars.length > 0) {\n timetables.push(\n createTimetable({\n route,\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendars,\n }),\n );\n }\n }\n\n for (const calendarDates of Object.values(calendarDateGroups)) {\n const tripsForCalendarDates = trips.filter((trip) =>\n some(calendarDates, { service_id: trip.service_id }),\n );\n if (tripsForCalendarDates.length > 0) {\n timetables.push(\n createTimetable({\n route,\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendarDates,\n }),\n );\n }\n }\n }\n\n if (timetables.length === 0) {\n continue;\n }\n\n if (config.groupTimetablesIntoPages === true) {\n timetablePages.push(\n createTimetablePage({\n timetablePageId: `route_${route.route_short_name ?? route.route_long_name}`,\n timetables,\n config,\n }),\n );\n } else {\n for (const timetable of timetables) {\n timetablePages.push(\n createTimetablePage({\n timetablePageId: timetable.timetable_id,\n timetables: [timetable],\n config,\n }),\n );\n }\n }\n }\n\n return timetablePages;\n};\n\n/*\n * Generate all trips based on a start trip and an array of frequencies.\n */\nconst generateTripsByFrequencies = (\n trip: FormattedTrip,\n frequencies: Frequency[],\n config: Config,\n) => {\n const formattedFrequencies = frequencies.map((frequency) =>\n formatFrequency(frequency, config),\n );\n const resetTrip = resetStoptimesToMidnight(trip);\n const trips = [];\n\n for (const frequency of formattedFrequencies) {\n const startSeconds = secondsAfterMidnight(frequency.start_time);\n const endSeconds = secondsAfterMidnight(frequency.end_time);\n\n for (\n let offset = startSeconds;\n offset < endSeconds;\n offset += frequency.headway_secs\n ) {\n const newTrip = cloneDeep(resetTrip);\n trips.push({\n ...newTrip,\n trip_id: `${resetTrip.trip_id}_freq_${trips.length}`,\n stoptimes: updateStoptimesByOffset(newTrip, offset),\n });\n }\n }\n\n return trips;\n};\n\n/*\n * Check if any stoptimes have different arrival and departure times and\n * if they do, duplicate the stop id unless it is the first or last stop.\n */\nconst duplicateStopsForDifferentArrivalDeparture = (\n stopIds: string[],\n timetable: Timetable,\n config: Config,\n) => {\n if (\n config.showArrivalOnDifference === null ||\n config.showArrivalOnDifference === undefined\n ) {\n return stopIds;\n }\n\n for (const trip of timetable.orderedTrips) {\n for (const stoptime of trip.stoptimes) {\n const timepointDifference = fromGTFSTime(stoptime.departure_time).diff(\n fromGTFSTime(stoptime.arrival_time),\n 'minutes',\n );\n\n if (timepointDifference < config.showArrivalOnDifference) {\n continue;\n }\n\n const index = stopIds.indexOf(stoptime.stop_id);\n if (index === 0 || index === stopIds.length - 1) {\n continue;\n }\n\n if (\n stoptime.stop_id === stopIds[index + 1] ||\n stoptime.stop_id === stopIds[index - 1]\n ) {\n continue;\n }\n\n stopIds.splice(index, 0, stoptime.stop_id);\n }\n }\n\n return stopIds;\n};\n\n/*\n * Get a sorted array of stop_ids for a specific timetable.\n */\nconst getStopOrder = (timetable: Timetable, config: Config) => {\n // First, check if `timetable_stop_order.txt` for route exists\n const timetableStopOrders = getTimetableStopOrders(\n {\n timetable_id: timetable.timetable_id,\n },\n ['stop_id'],\n [['stop_sequence', 'ASC']],\n );\n\n if (timetableStopOrders.length > 0) {\n return timetableStopOrders.map(\n (timetableStopOrder) => timetableStopOrder.stop_id,\n );\n }\n\n // Next, try using a directed graph to determine stop order.\n try {\n const stopGraph = [];\n\n // If a stop is marked as a timepoint in any trips, treat it as a timepoint in all trips for sorting purposes.\n const timepointStopIds = new Set(\n timetable.orderedTrips.flatMap((trip) =>\n trip.stoptimes\n .filter((stoptime) => isTimepoint(stoptime))\n .map((stoptime) => stoptime.stop_id),\n ),\n );\n\n for (const trip of timetable.orderedTrips) {\n const sortedStopIds = trip.stoptimes\n .filter((stoptime) => {\n // If `showOnlyTimepoint` is true, then filter out all non-timepoints.\n if (config.showOnlyTimepoint === true) {\n return timepointStopIds.has(stoptime.stop_id);\n }\n return true;\n })\n .map((stoptime) => stoptime.stop_id);\n\n for (const [index, stopId] of sortedStopIds.entries()) {\n if (index === sortedStopIds.length - 1) {\n continue;\n }\n\n stopGraph.push([stopId, sortedStopIds[index + 1]]);\n }\n }\n\n if (stopGraph.length === 0 && config.showOnlyTimepoint === true) {\n timetable.warnings.push(\n `Timetable ${timetable.timetable_id}'s trips have stoptimes with timepoints but \\`showOnlyTimepoint\\` is true. Try setting \\`showOnlyTimepoint\\` to false.`,\n );\n }\n\n const stopIds = toposort(stopGraph);\n\n return duplicateStopsForDifferentArrivalDeparture(\n stopIds,\n timetable,\n config,\n );\n } catch {\n // Fall back to using the stop order from the trip with the most stoptimes.\n // Note that this may miss some stops if the trip with the most stoptimes\n // does not contain all stops.\n const longestTripStoptimes = getLongestTripStoptimes(\n timetable.orderedTrips,\n config,\n );\n const stopIds = longestTripStoptimes.map(\n (stoptime) => stoptime.stop_id,\n ) as string[];\n\n const missingStopIds = difference(\n new Set(\n timetable.orderedTrips.flatMap((trip: Trip) =>\n trip.stoptimes.map((stoptime: StopTime) => stoptime.stop_id),\n ),\n ),\n new Set(stopIds),\n ) as string[];\n\n if (missingStopIds.length > 0) {\n timetable.warnings.push(\n `Timetable ${timetable.timetable_id} stops are unable to be topologically sorted and has no \\`timetable_stop_order.txt\\`. Falling back to using the using the stop order from trip with most stoptimes, but this does not include stop_ids ${formatListForDisplay(missingStopIds)}. Try manually specifying stops with \\`timetable_stop_order.txt\\`. Read more at https://gtfstohtml.com/docs/timetable-stop-order`,\n );\n }\n\n return duplicateStopsForDifferentArrivalDeparture(\n stopIds,\n timetable,\n config,\n );\n }\n};\n\n/*\n * Get an array of stops for a specific timetable.\n */\nconst getStopsForTimetable = (timetable: Timetable, config: Config) => {\n if (timetable.orderedTrips.length === 0) {\n return [];\n }\n\n const orderedStopIds = getStopOrder(timetable, config);\n const orderedStops = orderedStopIds.map((stopId, index) => {\n const stops = getStops({\n stop_id: stopId,\n });\n\n if (stops.length === 0) {\n throw new Error(\n `No stop found found for stop_id=${stopId} in timetable_id=${timetable.timetable_id}`,\n );\n }\n\n const stop = {\n ...stops[0],\n trips: [],\n };\n\n if (\n index < orderedStopIds.length - 1 &&\n stopId === orderedStopIds[index + 1]\n ) {\n stop.type = 'arrival';\n } else if (index > 0 && stopId === orderedStopIds[index - 1]) {\n stop.type = 'departure';\n }\n\n return stop;\n });\n\n // If `showStopCity` is true, look up stop attributes.\n if (config.showStopCity) {\n const stopAttributes = getStopAttributes({\n stop_id: orderedStopIds,\n });\n\n for (const stopAttribute of stopAttributes) {\n const stop = orderedStops.find(\n (stop) => stop.stop_id === stopAttribute.stop_id,\n );\n\n if (stop) {\n stop.stop_city = stopAttribute.stop_city;\n }\n }\n }\n\n return orderedStops;\n};\n\nconst getCalendarsFromConfig = (config: Config) => {\n const db = openDb();\n let whereClause = '';\n const whereClauses = [];\n\n if (config.endDate) {\n // Validate config.endDate is a valid date\n if (!moment(config.endDate).isValid()) {\n throw new Error(`Invalid endDate=${config.endDate} in config.json`);\n }\n\n whereClauses.push(\n `start_date <= ${sqlString.escape(moment(config.endDate).format('YYYYMMDD'))}`,\n );\n }\n\n if (config.startDate) {\n // Validate config.startDate is a valid date\n if (!moment(config.startDate).isValid()) {\n throw new Error(`Invalid startDate=${config.startDate} in config.json`);\n }\n\n whereClauses.push(\n `end_date >= ${sqlString.escape(moment(config.startDate).format('YYYYMMDD'))}`,\n );\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n const calendars: Calendar[] = db\n .prepare(`SELECT * FROM calendar ${whereClause}`)\n .all();\n\n // Find all calendar dates with service_ids not present in `calendar.txt`.\n const serviceIds = calendars.map((calendar) => calendar.service_id);\n const calendarDates = db\n .prepare(\n `SELECT * FROM calendar_dates WHERE exception_type = 1 AND service_id NOT IN (${serviceIds\n .map((serviceId) => `'${serviceId}'`)\n .join(', ')})`,\n )\n .all();\n\n return {\n calendars,\n calendarDates,\n };\n};\n\n/*\n * Get all calendars from a specific timetable.\n */\nconst getCalendarsFromTimetable = (timetable: Timetable) => {\n const db = openDb();\n let whereClause = '';\n const whereClauses = [];\n\n if (timetable.end_date) {\n // Validate timetable.end_date is a valid date\n if (!moment(timetable.end_date, 'YYYYMMDD', true).isValid()) {\n throw new Error(\n `Invalid end_date=${timetable.end_date} for timetable_id=${timetable.timetable_id}`,\n );\n }\n\n whereClauses.push(`start_date <= ${sqlString.escape(timetable.end_date)}`);\n }\n\n if (timetable.start_date) {\n // Validate timetable.start_date is a valid date\n if (!moment(timetable.start_date, 'YYYYMMDD', true).isValid()) {\n throw new Error(\n `Invalid start_date=${timetable.start_date} for timetable_id=${timetable.timetable_id}`,\n );\n }\n\n whereClauses.push(`end_date >= ${sqlString.escape(timetable.start_date)}`);\n }\n\n const days = getDaysFromCalendars([timetable]);\n // Create an 'OR' query array of days based on calendars.\n const dayQueries = reduce(\n days,\n (memo: string[], value: number, key: string) => {\n if (value === 1) {\n memo.push(`${key} = 1`);\n }\n\n return memo;\n },\n [],\n );\n\n if (dayQueries.length > 0) {\n whereClauses.push(`(${dayQueries.join(' OR ')})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db.prepare(`SELECT * FROM calendar ${whereClause}`).all();\n};\n\n/*\n * Get all calendar date service ids for an agency between two dates.\n */\nconst getCalendarDatesServiceIds = (\n startDate?: number | null,\n endDate?: number | null,\n) => {\n const db = openDb();\n const whereClauses = ['exception_type = 1'];\n\n if (endDate) {\n whereClauses.push(`date <= ${sqlString.escape(endDate)}`);\n }\n\n if (startDate) {\n whereClauses.push(`date >= ${sqlString.escape(startDate)}`);\n }\n\n const calendarDates: CalendarDate[] = db\n .prepare(\n `SELECT DISTINCT service_id FROM calendar_dates WHERE ${whereClauses.join(\n ' AND ',\n )}`,\n )\n .all();\n return calendarDates.map((calendarDate) => calendarDate.service_id);\n};\n\n/*\n * For a specific stop_id, returns an array all stop_ids within a parent station\n * and the stop_id of parent station itself. If no parent station, it returns the\n * stop_id.\n */\nconst getAllStationStopIds = (stopId: string) => {\n const stops = getStops({\n stop_id: stopId,\n });\n\n if (stops.length === 0) {\n throw new Error(`No stop found for stop_id=${stopId}`);\n }\n\n const stop = stops[0];\n\n if (isNullOrEmpty(stop.parent_station)) {\n return [stopId];\n }\n\n const stopsInParentStation = getStops(\n {\n parent_station: stop.parent_station,\n },\n ['stop_id'],\n );\n\n return [\n stop.parent_station,\n ...stopsInParentStation.map((stop) => stop.stop_id),\n ];\n};\n\n/*\n * Get trips with the same `block_id`.\n */\nconst getTripsWithSameBlock = (trip: FormattedTrip, timetable: Timetable) => {\n const trips = getTrips(\n {\n block_id: trip.block_id,\n service_id: timetable.service_ids,\n },\n ['trip_id', 'route_id'],\n );\n\n for (const blockTrip of trips) {\n const stopTimes = getStoptimes(\n {\n trip_id: blockTrip.trip_id,\n },\n [],\n [['stop_sequence', 'ASC']],\n );\n\n if (stopTimes.length === 0) {\n throw new Error(\n `No stoptimes found found for trip_id=${blockTrip.trip_id}`,\n );\n }\n\n blockTrip.firstStoptime = first(stopTimes);\n blockTrip.lastStoptime = last(stopTimes);\n }\n\n return sortBy(trips, (trip) => trip.firstStoptime.departure_timestamp);\n};\n\n/*\n * Get next trip and previous trip with the same `block_id` if it arrives or\n * departs from the same stop and is a different route.\n */\nconst addTripContinuation = (trip: FormattedTrip, timetable: Timetable) => {\n if (!trip.block_id || trip.stoptimes.length === 0) {\n return;\n }\n\n const maxContinuesAsWaitingTimeSeconds = 60 * 60;\n\n const firstStoptime = first(trip.stoptimes);\n const firstStopIds = getAllStationStopIds(firstStoptime.stop_id);\n const lastStoptime = last(trip.stoptimes);\n const lastStopIds = getAllStationStopIds(lastStoptime.stop_id);\n const blockTrips = getTripsWithSameBlock(trip, timetable);\n\n // \"Continues From\" trips must be the previous trip chronologically.\n const previousTrip = findLast(\n blockTrips,\n (blockTrip) =>\n blockTrip.lastStoptime.arrival_timestamp <=\n firstStoptime.departure_timestamp,\n );\n\n /*\n * \"Continues From\" trips\n * * must be a different route_id\n * * must not be more than 60 minutes before\n * * must have their last stop_id be the same as the next trip's first stop_id\n */\n if (\n previousTrip &&\n previousTrip.route_id !== trip.route_id &&\n previousTrip.lastStoptime.arrival_timestamp >=\n firstStoptime.departure_timestamp - maxContinuesAsWaitingTimeSeconds &&\n firstStopIds.includes(previousTrip.lastStoptime.stop_id)\n ) {\n const routes = getRoutes({\n route_id: previousTrip.route_id,\n });\n\n previousTrip.route = routes[0];\n\n trip.continues_from_route = previousTrip;\n }\n\n // \"Continues As\" trips must be the next trip chronologically.\n const nextTrip = find(\n blockTrips,\n (blockTrip) =>\n blockTrip.firstStoptime.departure_timestamp >=\n lastStoptime.arrival_timestamp,\n );\n\n // \"Continues As\" trips must be a different route_id.\n /*\n * \"Continues As\" trips\n * * must be a different route_id\n * * must not be more than 60 minutes later\n * * must have their first stop_id be the same as the previous trip's last stop_id\n */\n if (\n nextTrip &&\n nextTrip.route_id !== trip.route_id &&\n nextTrip.firstStoptime.departure_timestamp <=\n lastStoptime.arrival_timestamp + maxContinuesAsWaitingTimeSeconds &&\n lastStopIds.includes(nextTrip.firstStoptime.stop_id)\n ) {\n const routes = getRoutes({\n route_id: nextTrip.route_id,\n });\n\n nextTrip.route = routes[0];\n trip.continues_as_route = nextTrip;\n }\n};\n\n/*\n * Apply time range filters to trips and remove trips with less than two stoptimes for stops used in this timetable.\n * Stops can be excluded by using `timetable_stop_order.txt`. Additionally, remove trip stoptimes for unused stops.\n */\nconst filterTrips = (timetable: FormattedTimetable, config: Config) => {\n let filteredTrips = timetable.orderedTrips;\n\n // Combine adjacent stoptimes with the same `stop_id`\n for (const trip of filteredTrips) {\n const combinedStoptimes = [];\n\n for (const [index, stoptime] of trip.stoptimes.entries()) {\n if (\n index === 0 ||\n stoptime.stop_id !== trip.stoptimes[index - 1].stop_id\n ) {\n combinedStoptimes.push(stoptime);\n } else {\n // The `stoptime` is the same as previous, use `arrival_time` from previous and `departure_time` from this stoptime\n combinedStoptimes[combinedStoptimes.length - 1].departure_time =\n stoptime.departure_time;\n }\n }\n\n trip.stoptimes = combinedStoptimes;\n }\n\n // Remove stoptimes for stops not used in timetable\n const timetableStopIds = new Set(\n timetable.stops.map((stop: Stop) => stop.stop_id),\n );\n for (const trip of filteredTrips) {\n trip.stoptimes = trip.stoptimes.filter((stoptime: StopTime) =>\n timetableStopIds.has(stoptime.stop_id),\n );\n }\n\n // Exclude trips with less than two stops\n filteredTrips = filteredTrips.filter(\n (trip: Trip) => trip.stoptimes.length > 1,\n );\n\n if (config.showDuplicateTrips === false) {\n filteredTrips = deduplicateTrips(filteredTrips);\n }\n\n return filteredTrips;\n};\n\n/*\n * Get all trips from a timetable.\n */\n\n/* eslint-disable complexity */\nconst getTripsForTimetable = (\n timetable: FormattedTimetable,\n calendars: Calendar[],\n config: Config,\n) => {\n const tripQuery: {\n route_id: string[];\n service_id?: string[];\n direction_id?: number;\n } = {\n route_id: timetable.route_ids,\n service_id: timetable.service_ids,\n };\n\n if (!isNullOrEmpty(timetable.direction_id)) {\n tripQuery.direction_id = timetable.direction_id;\n }\n\n const trips = getTrips(tripQuery);\n\n if (trips.length === 0) {\n timetable.warnings.push(\n `No trips found for route_id=${timetable.route_ids.join(\n '_',\n )}, direction_id=${timetable.direction_id}, service_ids=${JSON.stringify(\n timetable.service_ids,\n )}, timetable_id=${timetable.timetable_id}`,\n );\n }\n\n const frequencies = getFrequencies({\n trip_id: trips.map((trip) => trip.trip_id),\n });\n\n // Updated timetable.serviceIds with only the service IDs actually used in one or more trip.\n timetable.service_ids = uniq(trips.map((trip) => trip.service_id));\n\n const formattedTrips = [];\n\n for (const trip of trips) {\n const formattedTrip = formatTrip(trip, timetable, calendars, config);\n formattedTrip.stoptimes = getStoptimes(\n {\n trip_id: formattedTrip.trip_id,\n },\n [],\n [['stop_sequence', 'ASC']],\n );\n\n if (formattedTrip.stoptimes.length === 0) {\n timetable.warnings.push(\n `No stoptimes found for trip_id=${\n formattedTrip.trip_id\n }, route_id=${timetable.route_ids.join('_')}, timetable_id=${\n timetable.timetable_id\n }`,\n );\n }\n\n // Exclude trips before timetable `start_timestamp`\n if (\n timetable.start_timestamp !== '' &&\n timetable.start_timestamp !== null &&\n timetable.start_timestamp !== undefined &&\n trip.stoptimes[0].arrival_timestamp < timetable.start_timestamp\n ) {\n return;\n }\n\n // Exclude trips after timetable `end_timestamp`\n if (\n timetable.end_timestamp !== '' &&\n timetable.end_timestamp !== null &&\n timetable.end_timestamp !== undefined &&\n trip.stoptimes[0].arrival_timestamp >= timetable.end_timestamp\n ) {\n return;\n }\n\n if (timetable.show_trip_continuation) {\n addTripContinuation(formattedTrip, timetable);\n\n if (formattedTrip.continues_as_route) {\n timetable.has_continues_as_route = true;\n }\n\n if (formattedTrip.continues_from_route) {\n timetable.has_continues_from_route = true;\n }\n }\n\n const tripFrequencies = frequencies.filter(\n (frequency) => frequency.trip_id === trip.trip_id,\n );\n\n if (tripFrequencies.length === 0) {\n formattedTrips.push(formattedTrip);\n } else {\n const frequencyTrips = generateTripsByFrequencies(\n formattedTrip,\n frequencies,\n config,\n );\n formattedTrips.push(...frequencyTrips);\n timetable.frequencies = frequencies;\n timetable.frequencyExactTimes = some(frequencies, {\n exact_times: 1,\n });\n }\n }\n\n if (config.useParentStation) {\n const stopIds = [];\n\n for (const trip of formattedTrips) {\n for (const stoptime of trip.stoptimes) {\n stopIds.push(stoptime.stop_id);\n }\n }\n\n const stops = getStops(\n {\n stop_id: uniq(stopIds),\n },\n ['parent_station', 'stop_id'],\n );\n\n for (const trip of formattedTrips) {\n for (const stoptime of trip.stoptimes) {\n const stop = stops.find((stop) => stop.stop_id === stoptime.stop_id);\n\n if (stop?.parent_station) {\n stoptime.stop_id = stop.parent_station;\n }\n }\n }\n }\n\n return sortTrips(formattedTrips, config);\n};\n/* eslint-enable complexity */\n\n/*\n * Format timetables for display.\n */\nconst formatTimetables = (timetables: Timetable[], config: Config) => {\n const formattedTimetables = timetables.map((timetable) => {\n timetable.warnings = [];\n const dayList = formatDays(timetable, config);\n const calendars = getCalendarsFromTimetable(timetable);\n let serviceIds = calendars.map((calendar: Calendar) => calendar.service_id);\n\n if (timetable.include_exceptions === 1) {\n const calendarDatesServiceIds = getCalendarDatesServiceIds(\n timetable.start_date,\n timetable.end_date,\n );\n serviceIds = uniq([...serviceIds, ...calendarDatesServiceIds]);\n }\n\n Object.assign(timetable, {\n noServiceSymbolUsed: false,\n requestDropoffSymbolUsed: false,\n noDropoffSymbolUsed: false,\n requestPickupSymbolUsed: false,\n noPickupSymbolUsed: false,\n interpolatedStopSymbolUsed: false,\n showStopCity: config.showStopCity,\n showStopDescription: config.showStopDescription,\n noServiceSymbol: config.noServiceSymbol,\n requestDropoffSymbol: config.requestDropoffSymbol,\n noDropoffSymbol: config.noDropoffSymbol,\n requestPickupSymbol: config.requestPickupSymbol,\n noPickupSymbol: config.noPickupSymbol,\n interpolatedStopSymbol: config.interpolatedStopSymbol,\n orientation: timetable.orientation || config.defaultOrientation,\n service_ids: serviceIds,\n dayList,\n dayListLong: formatDaysLong(dayList, config),\n });\n\n timetable.orderedTrips = getTripsForTimetable(timetable, calendars, config);\n timetable.stops = getStopsForTimetable(timetable, config);\n timetable.calendarDates = getCalendarDatesForTimetable(timetable, config);\n timetable.timetable_label = formatTimetableLabel(timetable);\n timetable.notes = getTimetableNotesForTimetable(timetable, config);\n\n if (config.showMap) {\n timetable.geojson = getTimetableGeoJSON(timetable, config);\n }\n\n timetable.trip_ids = uniq(\n timetable.orderedTrips.map((trip: Trip) => trip.trip_id),\n );\n\n // Filter trips after all timetable properties are assigned\n timetable.orderedTrips = filterTrips(timetable, config);\n\n // Format stops after all timetable properties are assigned\n timetable.stops = formatStops(timetable, config);\n\n return timetable;\n });\n\n if (config.allowEmptyTimetables) {\n return formattedTimetables;\n }\n\n return formattedTimetables.filter(\n (timetable) => timetable.orderedTrips.length > 0,\n );\n};\n\n/*\n * Get all timetable pages for an agency.\n */\nexport function getTimetablePagesForAgency(\n config: Config,\n): FormattedTimetablePage[] {\n const timetables = mergeTimetablesWithSameId(getTimetables());\n const routes = getRoutes();\n const formattedTimetables = timetables.map((timetable) => {\n return {\n ...timetable,\n routes: routes.filter((route) =>\n timetable.route_ids.includes(route.route_id),\n ),\n } as FormattedTimetable;\n });\n\n // If no timetables, build each route and direction into a timetable.\n if (timetables.length === 0) {\n return convertRoutesToTimetablePages(config);\n }\n\n const timetablePages = getTimetablePages(\n {},\n [],\n [['timetable_page_id', 'ASC']],\n );\n\n // Check if there are any timetable pages defined in `timetable_pages.txt`.\n if (timetablePages.length === 0) {\n // If no timetablepages, use timetables\n return formattedTimetables.map((timetable) =>\n createTimetablePage({\n timetablePageId: timetable.timetable_id,\n timetables: [timetable],\n config,\n }),\n );\n }\n\n // Otherwise, use timetable pages defined in `timetable_pages.txt`.\n return timetablePages.map((timetablePage) => {\n return {\n ...timetablePage,\n timetables: sortBy(\n formattedTimetables.filter(\n (timetable) =>\n timetable.timetable_page_id === timetablePage.timetable_page_id,\n ),\n 'timetable_sequence',\n ),\n } as FormattedTimetablePage;\n });\n}\n\nconst getDataForTimetablePageById = (timetablePageId: string) => {\n let calendarCode;\n let calendars;\n let calendarDates;\n let serviceId;\n let directionId: number | string | null = '';\n const parts = timetablePageId?.split('|') ?? [];\n if (parts.length > 2) {\n directionId = Number.parseInt(parts.pop(), 10);\n calendarCode = parts.pop();\n } else if (parts.length > 1) {\n directionId = null;\n calendarCode = parts.pop();\n }\n\n const routeId = parts.join('|');\n\n const routes = getRoutes({\n route_id: routeId,\n });\n\n const trips = getTrips(\n {\n route_id: routeId,\n direction_id: directionId,\n },\n ['trip_headsign', 'direction_id'],\n );\n const uniqueTripDirections = uniqBy(trips, (trip) => trip.direction_id);\n\n if (uniqueTripDirections.length === 0) {\n throw new Error(\n `No trips found for timetable_page_id=${timetablePageId} route_id=${routeId} direction_id=${directionId}`,\n );\n }\n\n if (/^[01]*$/.test(calendarCode ?? '')) {\n calendars = getCalendars({\n ...calendarCodeToCalendar(calendarCode),\n });\n } else {\n serviceId = calendarCode;\n calendarDates = getCalendarDates({\n exception_type: 1,\n service_id: serviceId,\n });\n }\n\n return {\n calendars,\n calendarDates,\n route: routes[0],\n directionId: uniqueTripDirections[0].direction_id,\n tripHeadsign: uniqueTripDirections[0].trip_headsign,\n };\n};\n\n/*\n * Get a timetable_page by id.\n */\nconst getTimetablePageById = (timetablePageId: string, config: Config) => {\n // Check if there are any timetable pages defined in `timetable_pages.txt`.\n const timetablePages = getTimetablePages({\n timetable_page_id: timetablePageId,\n });\n\n const timetables = mergeTimetablesWithSameId(\n getTimetables(),\n ) as FormattedTimetable[];\n\n if (timetablePages.length > 1) {\n throw new Error(\n `Multiple timetable_pages found for timetable_page_id=${timetablePageId}`,\n );\n }\n\n if (timetablePages.length === 1) {\n // Use timetablePage defined in `timetable_pages.txt`.\n const timetablePage = timetablePages[0];\n timetablePage.timetables = sortBy(\n timetables.filter(\n (timetable) => timetable.timetable_page_id === timetablePageId,\n ),\n 'timetable_sequence',\n );\n\n // Add routes for each timetable\n for (const timetable of timetablePage.timetables) {\n timetable.routes = getRoutes({\n route_id: timetable.route_ids,\n });\n }\n\n return timetablePage;\n }\n\n if (timetables.length > 0) {\n // If no timetable_page, use timetable defined in `timetables.txt`.\n const timetablePageTimetables = timetables.filter(\n (timetable) => timetable.timetable_id === timetablePageId,\n );\n\n if (timetablePageTimetables.length === 0) {\n throw new Error(\n `No timetable found for timetable_page_id=${timetablePageId}`,\n );\n }\n\n return createTimetablePage({\n timetablePageId: timetablePageId,\n timetables: [timetablePageTimetables[0]],\n config,\n });\n }\n\n // If no `timetables.txt` in GTFS and timetable_page_id starts with \"route_\", build the route into a timetable page using all calendars and directions.\n if (timetablePageId.startsWith('route_')) {\n const routes = getRoutes({\n route_short_name: timetablePageId.split('_')[1],\n });\n\n if (routes.length === 0) {\n throw new Error(\n `No route found for timetable_page_id=${timetablePageId}`,\n );\n }\n\n const { calendars, calendarDates } = getCalendarsFromConfig(config);\n\n const trips = getTrips(\n {\n route_id: routes[0].route_id,\n },\n ['trip_headsign', 'direction_id', 'trip_id', 'service_id'],\n );\n const uniqueTripDirections = orderBy(\n uniqBy(trips, (trip) => trip.direction_id),\n 'direction_id',\n );\n const sortedCalendars = orderBy(calendars, calendarToCalendarCode, 'desc');\n const calendarGroups = groupBy(sortedCalendars, calendarToCalendarCode);\n const calendarDateGroups = groupBy(calendarDates, 'service_id');\n\n const timetables: FormattedTimetable[] = [];\n\n for (const uniqueTripDirection of uniqueTripDirections) {\n for (const calendars of Object.values(calendarGroups)) {\n const tripsForCalendars = trips.filter((trip) =>\n some(calendars, { service_id: trip.service_id }),\n );\n if (tripsForCalendars.length > 0) {\n timetables.push(\n createTimetable({\n route: routes[0],\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendars,\n }),\n );\n }\n }\n\n for (const calendarDates of Object.values(calendarDateGroups)) {\n const tripsForCalendarDates = trips.filter((trip) =>\n some(calendarDates, { service_id: trip.service_id }),\n );\n if (tripsForCalendarDates.length > 0) {\n timetables.push(\n createTimetable({\n route: routes[0],\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendarDates,\n }),\n );\n }\n }\n }\n\n return createTimetablePage({\n timetablePageId,\n timetables,\n config,\n });\n }\n\n // If no `timetables.txt` in GTFS, try to parse the timetable_page_id and build the route and direction into a timetable.\n const { calendars, calendarDates, route, directionId, tripHeadsign } =\n getDataForTimetablePageById(timetablePageId);\n\n const timetable = createTimetable({\n route,\n directionId,\n tripHeadsign,\n calendars,\n calendarDates,\n });\n\n return createTimetablePage({\n timetablePageId,\n timetables: [timetable],\n config,\n });\n};\n\n/*\n * Initialize configuration with defaults.\n */\nexport function setDefaultConfig(initialConfig: Config) {\n const defaults = {\n allowEmptyTimetables: false,\n beautify: false,\n coordinatePrecision: 5,\n dateFormat: 'MMM D, YYYY',\n daysShortStrings: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],\n daysStrings: [\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n 'Sunday',\n ],\n defaultOrientation: 'vertical',\n interpolatedStopSymbol: '•',\n interpolatedStopText: 'Estimated time of arrival',\n groupTimetablesIntoPages: true,\n gtfsToHtmlVersion: version,\n linkStopUrls: false,\n mapStyleUrl: 'https://tiles.openfreemap.org/styles/positron',\n menuType: 'jump',\n noDropoffSymbol: '‡',\n noDropoffText: 'No drop off available',\n noHead: false,\n noPickupSymbol: '**',\n noPickupText: 'No pickup available',\n noRegularServiceDaysText: 'No regular service days',\n noServiceSymbol: '-',\n noServiceText: 'No service at this stop',\n outputFormat: 'html',\n overwriteExistingFiles: true,\n requestDropoffSymbol: '†',\n requestDropoffText: 'Must request drop off',\n requestPickupSymbol: '***',\n requestPickupText: 'Request stop - call for pickup',\n serviceNotProvidedOnText: 'Service not provided on',\n serviceProvidedOnText: 'Service provided on',\n showArrivalOnDifference: 0.2,\n showCalendarExceptions: true,\n showDuplicateTrips: false,\n showMap: false,\n showOnlyTimepoint: false,\n showRouteTitle: true,\n showStopCity: false,\n showStopDescription: false,\n showStoptimesForRequestStops: true,\n skipImport: false,\n sortingAlgorithm: 'common',\n timeFormat: 'h:mma',\n useParentStation: true,\n verbose: true,\n zipOutput: false,\n };\n\n const config = Object.assign(defaults, initialConfig);\n\n if (config.outputFormat === 'pdf') {\n // Force `noHead` to false to false if pdfs are asked for\n config.noHead = false;\n config.menuType = 'none';\n }\n\n // Add values to config if gtfs realtime URLs are present\n config.hasGtfsRealtimeVehiclePositions = config.agencies.some(\n (agency) => agency.realtimeVehiclePositions?.url,\n );\n\n config.hasGtfsRealtimeTripUpdates = config.agencies.some(\n (agency) => agency.realtimeTripUpdates?.url,\n );\n\n config.hasGtfsRealtimeAlerts = config.agencies.some(\n (agency) => agency.realtimeAlerts?.url,\n );\n\n return config;\n}\n\n/*\n * Get a timetable page by id.\n */\nexport function getFormattedTimetablePage(\n timetablePageId: string,\n config: Config,\n) {\n const timetablePage = getTimetablePageById(\n timetablePageId,\n config,\n ) as FormattedTimetablePage;\n\n const consolidatedTimetables = formatTimetables(\n timetablePage.timetables,\n config,\n );\n\n // Get `direction_name` for each timetable.\n for (const timetable of consolidatedTimetables) {\n if (isNullOrEmpty(timetable.direction_name)) {\n timetable.direction_name = getDirectionHeadsignFromTimetable(timetable);\n }\n\n if (!timetable.routes) {\n timetable.routes = getRoutes({\n route_id: timetable.route_ids,\n });\n }\n }\n\n const uniqueRoutes = uniqBy(\n flatMap(consolidatedTimetables, (timetable) => timetable.routes),\n 'route_id',\n );\n\n const formattedTimetablePage = {\n ...timetablePage,\n consolidatedTimetables,\n dayList: formatDays(getDaysFromCalendars(consolidatedTimetables), config),\n dayLists: uniq(\n consolidatedTimetables.map((timetable) => timetable.dayList),\n ),\n route_ids: uniqueRoutes.map((route) => route.route_id),\n agency_ids: uniq(compact(uniqueRoutes.map((route) => route.agency_id))),\n filename:\n timetablePage.filename ?? `${timetablePage.timetable_page_id}.html`,\n timetable_page_label:\n timetablePage.timetable_page_label ??\n formatListForDisplay(uniqueRoutes.map((route) => formatRouteName(route))),\n };\n\n return formattedTimetablePage;\n}\n\n/*\n * Generate stats about timetable page.\n */\nexport const generateStats = (timetablePage: FormattedTimetablePage) => {\n const routeIds: { [key: string]: boolean } = {};\n const serviceIds: { [key: string]: boolean } = {};\n const stats = {\n stops: 0,\n trips: 0,\n routes: 0,\n calendars: 0,\n };\n\n for (const timetable of timetablePage.consolidatedTimetables) {\n stats.stops += timetable.stops.length;\n stats.trips += timetable.orderedTrips.length;\n for (const serviceId of timetable.service_ids) {\n serviceIds[serviceId] = true;\n }\n\n for (const routeId of timetable.route_ids) {\n routeIds[routeId] = true;\n }\n }\n\n stats.routes = size(routeIds);\n stats.calendars = size(serviceIds);\n\n return stats;\n};\n\n/*\n * Generate the HTML timetable for a timetable page.\n */\nexport function generateTimetableHTML(\n timetablePage: FormattedTimetablePage,\n config: Config,\n) {\n const agencies = getAgencies() as { agency_name: string }[];\n const templateVars = {\n timetablePage,\n config,\n title: `${timetablePage.timetable_page_label} | ${formatListForDisplay(agencies.map((agency) => agency.agency_name))}`,\n };\n return renderTemplate('timetablepage', templateVars, config);\n}\n\n/*\n * Generate the CSV timetable for a timetable page.\n */\nexport function generateTimetableCSV(timetable) {\n // Generate horizontal orientation, then transpose if vertical is needed.\n const lines = [];\n\n lines.push([\n '',\n ...timetable.orderedTrips.map((trip) =>\n formatTripNameForCSV(trip, timetable),\n ),\n ]);\n\n if (timetable.has_continues_from_route) {\n lines.push([\n 'Continues from route',\n ...timetable.orderedTrips.map((trip) => formatTripContinuesFrom(trip)),\n ]);\n }\n\n for (const stop of timetable.stops) {\n lines.push([\n formatStopName(stop),\n ...stop.trips.map((stoptime) => stoptime.formatted_time),\n ]);\n }\n\n if (timetable.has_continues_as_route) {\n lines.push([\n 'Continues as route',\n ...timetable.orderedTrips.map((trip) => formatTripContinuesAs(trip)),\n ]);\n }\n\n if (timetable.orientation === 'vertical') {\n return stringify(zip(...lines));\n }\n\n return stringify(lines);\n}\n\n/*\n * Generate the HTML for the agency overview page.\n */\nexport function generateOverviewHTML(\n timetablePages: FormattedTimetablePage[],\n config: Config,\n) {\n const agencies = getAgencies() as { agency_name: string }[];\n if (agencies.length === 0) {\n throw new Error('No agencies found');\n }\n\n const geojson = config.showMap ? getAgencyGeoJSON(config) : undefined;\n\n const templateVars = {\n agency: {\n ...first(agencies),\n geojson,\n }, // Legacy agency object\n agencies,\n geojson,\n config,\n timetablePages,\n title: `${formatListForDisplay(agencies.map((agency) => agency.agency_name))} Timetables`,\n };\n return renderTemplate('overview', templateVars, config);\n}\n","import { getShapesAsGeoJSON, getStopsAsGeoJSON } from 'gtfs';\nimport simplify from '@turf/simplify';\nimport { featureCollection, round } from '@turf/helpers';\nimport { logWarning } from './log-utils.js';\n\n/*\n * Merge any number of geojson objects into one. Only works for `FeatureCollection`.\n */\nconst mergeGeojson = (...geojsons) =>\n featureCollection(geojsons.flatMap((geojson) => geojson.features));\n\n/*\n * Truncate a geojson coordinates to a specific number of decimal places.\n */\nconst truncateGeoJSONDecimals = (geojson, config) => {\n for (const feature of geojson.features) {\n if (feature.geometry.coordinates) {\n if (feature.geometry.type.toLowerCase() === 'point') {\n feature.geometry.coordinates = feature.geometry.coordinates.map(\n (number) => round(number, config.coordinatePrecision),\n );\n } else if (feature.geometry.type.toLowerCase() === 'linestring') {\n feature.geometry.coordinates = feature.geometry.coordinates.map(\n (coordinate) =>\n coordinate.map((number) =>\n round(number, config.coordinatePrecision),\n ),\n );\n } else if (feature.geometry.type.toLowerCase() === 'multilinestring') {\n feature.geometry.coordinates = feature.geometry.coordinates.map(\n (linestring) =>\n linestring.map((coordinate) =>\n coordinate.map((number) =>\n round(number, config.coordinatePrecision),\n ),\n ),\n );\n }\n }\n }\n\n return geojson;\n};\n\n/*\n * Get the geoJSON for a timetable.\n */\nexport function getTimetableGeoJSON(timetable, config) {\n const shapesGeojsons = timetable.route_ids.map((routeId) =>\n getShapesAsGeoJSON({\n route_id: routeId,\n direction_id: timetable.direction_id,\n trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),\n }),\n );\n\n const stopsGeojsons = timetable.route_ids.map((routeId) =>\n getStopsAsGeoJSON({\n route_id: routeId,\n direction_id: timetable.direction_id,\n trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),\n }),\n );\n\n const geojson = mergeGeojson(...shapesGeojsons, ...stopsGeojsons);\n\n let simplifiedGeojson;\n try {\n simplifiedGeojson = simplify(geojson, {\n tolerance: 1 / 10 ** config.coordinatePrecision,\n highQuality: true,\n });\n } catch {\n timetable.warnings.push(\n `Timetable ${timetable.timetable_id} - Unable to simplify geojson`,\n );\n simplifiedGeojson = geojson;\n }\n\n return truncateGeoJSONDecimals(simplifiedGeojson, config);\n}\n\n/*\n * Get the geoJSON for an agency (all routes and stops).\n */\nexport function getAgencyGeoJSON(config) {\n const shapesGeojsons = getShapesAsGeoJSON();\n const stopsGeojsons = getStopsAsGeoJSON();\n\n const geojson = mergeGeojson(shapesGeojsons, stopsGeojsons);\n\n let simplifiedGeojson;\n try {\n simplifiedGeojson = simplify(geojson, {\n tolerance: 1 / 10 ** config.coordinatePrecision,\n highQuality: true,\n });\n } catch {\n logWarning(config)('Unable to simplify geojson');\n simplifiedGeojson = geojson;\n }\n\n return truncateGeoJSONDecimals(simplifiedGeojson, config);\n}\n","import { clearLine, cursorTo } from 'node:readline';\nimport { noop } from 'lodash-es';\nimport * as colors from 'yoctocolors';\nimport { getAgencies, getFeedInfo } from 'gtfs';\nimport Table from 'cli-table';\nimport { Config } from '../types/index.ts';\n\n/*\n * Creates text for a log of output details.\n */\nexport function generateLogText(outputStats, config: Config) {\n const feedInfo = getFeedInfo();\n const agencies = getAgencies();\n const feedVersion =\n feedInfo.length > 0 && feedInfo[0].feed_version\n ? feedInfo[0].feed_version\n : 'Unknown';\n\n const logText = [\n `Agencies: ${agencies.map((agency) => agency.agency_name).join(', ')}`,\n `Feed Version: ${feedVersion}`,\n `GTFS-to-HTML Version: ${config.gtfsToHtmlVersion}`,\n `Date Generated: ${new Date().toISOString()}`,\n `Timetable Page Count: ${outputStats.timetablePages}`,\n `Timetable Count: ${outputStats.timetables}`,\n `Calendar Service ID Count: ${outputStats.calendars}`,\n `Route Count: ${outputStats.routes}`,\n `Trip Count: ${outputStats.trips}`,\n `Stop Count: ${outputStats.stops}`,\n ];\n\n for (const agency of config.agencies) {\n if (agency.url) {\n logText.push(`Source: ${agency.url}`);\n } else if (agency.path) {\n logText.push(`Source: ${agency.path}`);\n }\n }\n\n if (outputStats.warnings.length > 0) {\n logText.push('', 'Warnings:', ...outputStats.warnings);\n }\n\n return logText.join('\\n');\n}\n\n/*\n * Returns a log function based on config settings\n */\nexport function log(config: Config) {\n if (config.verbose === false) {\n return noop;\n }\n\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string, overwrite: boolean) => {\n if (overwrite === true && process.stdout.isTTY) {\n clearLine(process.stdout, 0);\n cursorTo(process.stdout, 0);\n } else {\n process.stdout.write('\\n');\n }\n\n process.stdout.write(text);\n };\n}\n\n/*\n * Returns an warning log function based on config settings\n */\nexport function logWarning(config: Config) {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string) => {\n process.stdout.write(`\\n${formatWarning(text)}\\n`);\n };\n}\n\n/*\n * Returns an error log function based on config settings\n */\nexport function logError(config: Config) {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string) => {\n process.stdout.write(`\\n${formatError(text)}\\n`);\n };\n}\n\n/*\n * Format console warning text\n */\nexport function formatWarning(text: string) {\n const warningMessage = `${colors.underline('Warning')}: ${text}`;\n return colors.yellow(warningMessage);\n}\n\n/*\n * Format console error text\n */\nexport function formatError(error: any) {\n const messageText = error instanceof Error ? error.message : error;\n const errorMessage = `${colors.underline('Error')}: ${messageText.replace(\n 'Error: ',\n '',\n )}`;\n return colors.red(errorMessage);\n}\n\n/*\n * Print a table of stats to the console.\n */\nexport function logStats(config: Config) {\n // Hide stats table from custom log functions\n if (config.logFunction) {\n return noop;\n }\n\n return (stats: any) => {\n const table = new Table({\n colWidths: [40, 20],\n head: ['Item', 'Count'],\n });\n\n table.push(\n ['📄 Timetable Pages', stats.timetablePages],\n ['🕑 Timetables', stats.timetables],\n ['📅 Calendar Service IDs', stats.calendars],\n ['🔄 Routes', stats.routes],\n ['🚍 Trips', stats.trips],\n ['🛑 Stops', stats.stops],\n ['⛔️ Warnings', stats.warnings.length],\n );\n\n log(config)(table.toString());\n };\n}\n\n/*\n * Create progress bar text string\n */\nconst generateProgressBarString = (barTotal, barProgress, size = 40) => {\n const line = '-';\n const slider = '=';\n if (!barTotal) {\n throw new Error('Total value is either not provided or invalid');\n }\n\n if (!barProgress && barProgress !== 0) {\n throw new Error('Current value is either not provided or invalid');\n }\n\n if (isNaN(barTotal)) {\n throw new Error('Total value is not an integer');\n }\n\n if (isNaN(barProgress)) {\n throw new Error('Current value is not an integer');\n }\n\n if (isNaN(size)) {\n throw new Error('Size is not an integer');\n }\n\n if (barProgress > barTotal) {\n return slider.repeat(size + 2);\n }\n\n const percentage = barProgress / barTotal;\n const progress = Math.round(size * percentage);\n const emptyProgress = size - progress;\n const progressText = slider.repeat(progress);\n const emptyProgressText = line.repeat(emptyProgress);\n return progressText + emptyProgressText;\n};\n\n/*\n * Print a progress bar to the console.\n */\nexport function progressBar(\n formatString: string,\n barTotal: number,\n config: Config,\n) {\n let barProgress = 0;\n\n if (config.verbose === false) {\n return {\n increment: noop,\n interrupt: noop,\n };\n }\n\n if (barTotal === 0) {\n return null;\n }\n\n const renderProgressString = () =>\n formatString\n .replace('{value}', barProgress)\n .replace('{total}', barTotal)\n .replace('{bar}', generateProgressBarString(barTotal, barProgress));\n\n log(config)(renderProgressString(), true);\n\n return {\n interrupt(text: string) {\n // Log two lines to avoid overwrite by progress bar\n logWarning(config)(text);\n log(config)('');\n },\n increment() {\n barProgress += 1;\n log(config)(renderProgressString(), true);\n },\n };\n}\n","import { every } from 'lodash-es';\n\n/*\n * Discern if a day list should be shown for a specific timetable (if some\n * trips happen on different days).\n */\nexport function timetableHasDifferentDays(timetable) {\n return !every(timetable.orderedTrips, (trip, idx) => {\n if (idx === 0) {\n return true;\n }\n\n return trip.dayList === timetable.orderedTrips[idx - 1].dayList;\n });\n}\n\n/*\n * Discern if a day list should be shown for a specific timetable page's menu (if some\n * timetables are for different days).\n */\nexport function timetablePageHasDifferentDays(timetablePage) {\n return !every(timetablePage.consolidatedTimetables, (timetable, idx) => {\n if (idx === 0) {\n return true;\n }\n\n return (\n timetable.dayListLong ===\n timetablePage.consolidatedTimetables[idx - 1].dayListLong\n );\n });\n}\n\n/*\n * Discern if individual timetable labels should be shown (if some\n * timetables have different labels).\n */\nexport function timetablePageHasDifferentLabels(timetablePage) {\n return !every(timetablePage.consolidatedTimetables, (timetable, idx) => {\n if (idx === 0) {\n return true;\n }\n\n return (\n timetable.timetable_label ===\n timetablePage.consolidatedTimetables[idx - 1].timetable_label\n );\n });\n}\n\n/*\n * Discern if a timetable has any notes or notices to display.\n */\nexport function hasNotesOrNotices(timetable) {\n return (\n timetable.requestPickupSymbolUsed ||\n timetable.noPickupSymbolUsed ||\n timetable.requestDropoffSymbolUsed ||\n timetable.noDropoffSymbolUsed ||\n timetable.noServiceSymbolUsed ||\n timetable.interpolatedStopSymbolUsed ||\n timetable.notes.length > 0\n );\n}\n\n/*\n * Return an array of all timetable notes that relate to the entire timetable or route.\n */\nexport function getNotesForTimetableLabel(notes) {\n return notes.filter((note) => !note.stop_id && !note.trip_id);\n}\n\n/*\n * Return an array of all timetable notes for a specific stop and stop_sequence.\n */\nexport function getNotesForStop(notes, stop) {\n return notes.filter((note) => {\n // Don't show if note applies only to a specific trip.\n if (note.trip_id) {\n return false;\n }\n\n // Don't show if note applies only to a specific stop_sequence that is not found.\n if (\n note.stop_sequence &&\n !stop.trips.some((trip) => trip.stop_sequence === note.stop_sequence)\n ) {\n return false;\n }\n\n return note.stop_id === stop.stop_id;\n });\n}\n\n/*\n * Return an array of all timetable notes for a specific trip.\n */\nexport function getNotesForTrip(notes, trip) {\n return notes.filter((note) => {\n // Don't show if note applies only to a specific stop.\n if (note.stop_id) {\n return false;\n }\n\n return note.trip_id === trip.trip_id;\n });\n}\n\n/*\n * Return an array of all timetable notes for a specific stoptime.\n */\nexport function getNotesForStoptime(notes, stoptime) {\n return notes.filter((note) => {\n // Show notes that apply to all trips at this stop if `show_on_stoptime` is true.\n if (\n !note.trip_id &&\n note.stop_id === stoptime.stop_id &&\n note.show_on_stoptime === 1\n ) {\n return true;\n }\n\n // Show notes that apply to all stops of this trip if `show_on_stoptime` is true.\n if (\n !note.stop_id &&\n note.trip_id === stoptime.trip_id &&\n note.show_on_stoptime === 1\n ) {\n return true;\n }\n\n return (\n note.trip_id === stoptime.trip_id && note.stop_id === stoptime.stop_id\n );\n });\n}\n\n/*\n * Formats a trip name for HTML timetable.\n * Deprecated, use `formatTripName` in formatting_functions.pug instead.\n */\nexport function formatTripName(trip, index, timetable) {\n let tripName;\n if (timetable.routes.length > 1) {\n tripName = trip.route_short_name;\n } else if (timetable.orientation === 'horizontal') {\n // Only add this to horizontal timetables.\n if (trip.trip_short_name) {\n tripName = trip.trip_short_name;\n } else {\n tripName = `Run #${index + 1}`;\n }\n }\n\n if (timetableHasDifferentDays(timetable)) {\n tripName += ` ${trip.dayList}`;\n }\n\n return tripName;\n}\n\n/*\n * Formats a trip name for CSV export.\n */\nexport function formatTripNameForCSV(trip, timetable) {\n let tripName = '';\n if (timetable.routes.length > 1) {\n tripName += `${trip.route_short_name} - `;\n }\n\n if (trip.trip_short_name) {\n tripName += trip.trip_short_name;\n } else {\n tripName += trip.trip_id;\n }\n\n if (trip.trip_headsign) {\n tripName += ` - ${trip.trip_headsign}`;\n }\n\n if (timetableHasDifferentDays(timetable)) {\n tripName += ` - ${trip.dayList}`;\n }\n\n return tripName;\n}\n","{\n \"name\": \"gtfs-to-html\",\n \"version\": \"2.12.1\",\n \"private\": false,\n \"description\": \"Build human readable transit timetables as HTML, PDF or CSV from GTFS\",\n \"keywords\": [\n \"transit\",\n \"gtfs\",\n \"gtfs-realtime\",\n \"transportation\",\n \"timetables\"\n ],\n \"homepage\": \"https://gtfstohtml.com\",\n \"bugs\": {\n \"url\": \"https://github.com/blinktaginc/gtfs-to-html/issues\"\n },\n \"repository\": \"git://github.com/blinktaginc/gtfs-to-html\",\n \"license\": \"MIT\",\n \"author\": \"Brendan Nee <brendan@blinktag.com>\",\n \"contributors\": [\n \"Evan Siroky <evan.siroky@yahoo.com>\",\n \"Nathan Selikoff\",\n \"Aaron Antrim <aaron@trilliumtransit.com>\",\n \"Thomas Craig <thomas@trilliumtransit.com>\",\n \"Holly Kvalheim\",\n \"Pawajoro\",\n \"Andrea Mignone\",\n \"Evo Stamatov\",\n \"Sebastian Knopf\"\n ],\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"docker\",\n \"examples\",\n \"views/default\",\n \"config-sample.json\"\n ],\n \"bin\": {\n \"gtfs-to-html\": \"dist/bin/gtfs-to-html.js\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"start\": \"node ./dist/app\",\n \"prepare\": \"husky\"\n },\n \"dependencies\": {\n \"@maplibre/maplibre-gl-geocoder\": \"^1.9.1\",\n \"@turf/helpers\": \"^7.3.0\",\n \"@turf/simplify\": \"^7.3.0\",\n \"anchorme\": \"^3.0.8\",\n \"archiver\": \"^7.0.1\",\n \"cli-table\": \"^0.3.11\",\n \"css.escape\": \"^1.5.1\",\n \"csv-stringify\": \"^6.6.0\",\n \"express\": \"^5.1.0\",\n \"gtfs\": \"^4.18.1\",\n \"gtfs-realtime-pbf-js-module\": \"^1.0.0\",\n \"js-beautify\": \"^1.15.4\",\n \"lodash-es\": \"^4.17.21\",\n \"maplibre-gl\": \"^5.13.0\",\n \"marked\": \"^17.0.0\",\n \"moment\": \"^2.30.1\",\n \"pbf\": \"^4.0.1\",\n \"pretty-error\": \"^4.0.0\",\n \"pug\": \"^3.0.3\",\n \"puppeteer\": \"^24.30.0\",\n \"sanitize-filename\": \"^1.6.3\",\n \"sanitize-html\": \"^2.17.0\",\n \"sqlstring\": \"^2.3.3\",\n \"toposort\": \"^2.0.2\",\n \"yargs\": \"^18.0.0\",\n \"yoctocolors\": \"^2.1.2\"\n },\n \"devDependencies\": {\n \"@types/archiver\": \"^7.0.0\",\n \"@types/cli-table\": \"^0.3.4\",\n \"@types/express\": \"^5.0.5\",\n \"@types/insane\": \"^1.0.0\",\n \"@types/js-beautify\": \"^1.14.3\",\n \"@types/lodash-es\": \"^4.17.12\",\n \"@types/morgan\": \"^1.9.10\",\n \"@types/node\": \"^24\",\n \"@types/pug\": \"^2.0.10\",\n \"@types/sanitize-html\": \"^2.16.0\",\n \"@types/sqlstring\": \"^2.3.2\",\n \"@types/toposort\": \"^2.0.7\",\n \"@types/yargs\": \"^17.0.35\",\n \"husky\": \"^9.1.7\",\n \"lint-staged\": \"^16.2.7\",\n \"prettier\": \"^3.6.2\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.9.3\"\n },\n \"engines\": {\n \"node\": \">= 22\"\n },\n \"release-it\": {\n \"github\": {\n \"release\": true\n },\n \"plugins\": {\n \"@release-it/keep-a-changelog\": {\n \"filename\": \"CHANGELOG.md\"\n }\n },\n \"hooks\": {\n \"after:bump\": \"npm run build\"\n }\n },\n \"prettier\": {\n \"singleQuote\": true\n },\n \"lint-staged\": {\n \"*.js\": \"prettier --write\",\n \"*.ts\": \"prettier --write\",\n \"*.json\": \"prettier --write\"\n }\n}\n"],"mappings":"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","names":["mkdir","openDb","sanitize","uniqBy","find","first","groupBy","last","sortBy","moment","days","every","getAgencies","moment","size","every","moment","days","stop","calendars","calendarDates","trip","timetable","timetables","getAgencies","moment","sortBy","find","route","days","idx","last","first","groupBy","error","resolve","uniqBy","sanitize","openDb","mkdir"]}
1
+ {"version":3,"sources":["../src/lib/gtfs-to-html.ts","../src/lib/file-utils.ts","../src/lib/formatters.ts","../src/lib/time-utils.ts","../src/lib/utils.ts","../src/lib/geojson-utils.ts","../src/lib/log-utils.ts","../src/lib/template-functions.ts","../package.json"],"sourcesContent":["import path from 'node:path';\nimport { mkdir, writeFile } from 'node:fs/promises';\n\nimport { openDb, importGtfs, ConfigAgency } from 'gtfs';\nimport sanitize from 'sanitize-filename';\n\nimport {\n prepDirectory,\n copyStaticAssets,\n generateFolderName,\n renderPdf,\n zipFolder,\n generateCSVFileName,\n untildify,\n} from './file-utils.js';\nimport {\n progressBar,\n generateLogText,\n logStats,\n logError,\n log,\n} from './log-utils.js';\nimport {\n setDefaultConfig,\n getTimetablePagesForAgency,\n getFormattedTimetablePage,\n generateTimetableHTML,\n generateTimetableCSV,\n generateOverviewHTML,\n generateStats,\n} from './utils.js';\n\nimport type { Config } from '../types/index.ts';\n\n/*\n * Generate HTML timetables from GTFS.\n */\n/* eslint-disable complexity */\nconst gtfsToHtml = async (initialConfig: Config) => {\n const config = setDefaultConfig(initialConfig);\n\n // Start timer\n const startTime = process.hrtime.bigint();\n\n const agencyKey = config.agencies\n .map(\n (agency: ConfigAgency & { agencyKey?: string; agency_key?: string }) =>\n agency.agencyKey ?? agency.agency_key ?? 'unknown',\n )\n .join('-');\n const outputPath = config.outputPath\n ? untildify(config.outputPath)\n : path.join(process.cwd(), 'html', sanitize(agencyKey));\n\n await prepDirectory(outputPath, config);\n\n try {\n openDb(config);\n } catch (error: any) {\n if (error?.code === 'SQLITE_CANTOPEN') {\n logError(config)(\n `Unable to open sqlite database \"${config.sqlitePath}\" defined as \\`sqlitePath\\` config.json. Ensure the parent directory exists or remove \\`sqlitePath\\` from config.json.`,\n );\n }\n\n throw error;\n }\n\n if (!config.agencies || config.agencies.length === 0) {\n throw new Error('No agencies defined in `config.json`');\n }\n\n if (!config.skipImport) {\n await importGtfs(config);\n }\n\n const stats: {\n timetables: number;\n timetablePages: number;\n calendars: number;\n routes: number;\n trips: number;\n stops: number;\n warnings: string[];\n [key: string]: number | string[];\n } = {\n timetables: 0,\n timetablePages: 0,\n calendars: 0,\n routes: 0,\n trips: 0,\n stops: 0,\n warnings: [],\n };\n\n const timetablePages = [];\n const timetablePageIds = getTimetablePagesForAgency(config).map(\n (timetablePage) => timetablePage.timetable_page_id,\n );\n\n if (config.noHead !== true && ['html', 'pdf'].includes(config.outputFormat)) {\n await copyStaticAssets(config, outputPath);\n }\n\n const bar = progressBar(\n `${agencyKey}: Generating ${config.outputFormat.toUpperCase()} timetables {bar} {value}/{total}`,\n timetablePageIds.length,\n config,\n );\n\n /* eslint-disable no-await-in-loop */\n for (const timetablePageId of timetablePageIds) {\n try {\n const timetablePage = await getFormattedTimetablePage(\n timetablePageId as string,\n config,\n );\n\n for (const timetable of timetablePage.consolidatedTimetables) {\n if (timetable.warnings) {\n for (const warning of timetable.warnings) {\n stats.warnings.push(warning);\n bar?.interrupt(warning);\n }\n }\n }\n\n if (timetablePage.consolidatedTimetables.length === 0) {\n throw new Error(\n `No timetables found for timetable_page_id=${timetablePage.timetable_page_id}`,\n );\n }\n\n stats.timetables += timetablePage.consolidatedTimetables.length;\n stats.timetablePages += 1;\n\n const datePath = generateFolderName(timetablePage);\n\n // Make directory if it doesn't exist\n await mkdir(path.join(outputPath, datePath), { recursive: true });\n config.assetPath = '../';\n\n timetablePage.relativePath = path.join(\n datePath,\n sanitize(timetablePage.filename),\n );\n\n if (config.outputFormat === 'csv') {\n for (const timetable of timetablePage.consolidatedTimetables) {\n const csv = await generateTimetableCSV(timetable);\n const csvPath = path.join(\n outputPath,\n datePath,\n generateCSVFileName(timetable, config),\n );\n await writeFile(csvPath, csv);\n }\n } else {\n const html = await generateTimetableHTML(timetablePage, config);\n const htmlPath = path.join(\n outputPath,\n datePath,\n sanitize(timetablePage.filename),\n );\n await writeFile(htmlPath, html);\n\n if (config.outputFormat === 'pdf') {\n await renderPdf(htmlPath);\n }\n }\n\n timetablePages.push(timetablePage);\n const timetableStats = generateStats(timetablePage);\n\n stats.stops += timetableStats.stops;\n stats.routes += timetableStats.routes;\n stats.trips += timetableStats.trips;\n stats.calendars += timetableStats.calendars;\n } catch (error: any) {\n stats.warnings.push(error?.message);\n bar?.interrupt(error.message);\n }\n\n bar?.increment();\n }\n /* eslint-enable no-await-in-loop */\n\n if (config.outputFormat === 'html') {\n // Generate overview HTML\n config.assetPath = '';\n const html = await generateOverviewHTML(timetablePages, config);\n await writeFile(path.join(outputPath, 'index.html'), html);\n }\n\n // Generate log.txt\n const logText = generateLogText(stats, config);\n await writeFile(path.join(outputPath, 'log.txt'), logText);\n\n // Zip output, if specified\n if (config.zipOutput) {\n await zipFolder(outputPath);\n }\n\n const fullOutputPath = path.join(\n outputPath,\n config.zipOutput ? '/timetables.zip' : '',\n );\n\n // Print stats\n log(config)(\n `${agencyKey}: ${config.outputFormat.toUpperCase()} timetables created at ${fullOutputPath}`,\n );\n\n logStats(config)(stats);\n\n const endTime = process.hrtime.bigint();\n const elapsedSeconds = Number(endTime - startTime) / 1_000_000_000;\n\n log(config)(\n `${agencyKey}: ${config.outputFormat.toUpperCase()} timetable generation required ${elapsedSeconds.toFixed(1)} seconds`,\n );\n\n return fullOutputPath;\n};\n/* eslint-enable complexity */\n\nexport default gtfsToHtml;\n","import { dirname, join, resolve } from 'node:path';\nimport cssEscape from 'css.escape';\nimport { createWriteStream } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport {\n access,\n cp,\n copyFile,\n mkdir,\n readdir,\n readFile,\n rm,\n} from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { findPackageJSON } from 'node:module';\n\nimport * as _ from 'lodash-es';\nimport { uniqBy } from 'lodash-es';\nimport archiver from 'archiver';\nimport beautify from 'js-beautify';\nimport sanitizeHtml from 'sanitize-html';\nimport { renderFile } from 'pug';\nimport puppeteer from 'puppeteer';\nimport sanitize from 'sanitize-filename';\nimport { marked } from 'marked';\n\nimport {\n isNullOrEmpty,\n formatDays,\n formatRouteColor,\n formatRouteTextColor,\n formatRouteNameForFilename,\n} from './formatters.js';\nimport * as templateFunctions from './template-functions.js';\n\nimport type {\n Config,\n FormattedTimetable,\n FormattedTimetablePage,\n} from '../types/index.ts';\n\nconst homeDirectory = homedir();\n\n/*\n * Attempt to parse the specified config JSON file.\n */\nexport async function getConfig(argv) {\n let data;\n let config;\n\n try {\n data = await readFile(resolve(untildify(argv.configPath)), 'utf8');\n } catch (error) {\n throw new Error(\n `Cannot find configuration file at \\`${argv.configPath}\\`. Use config-sample.json as a starting point, pass --configPath option`,\n );\n }\n\n try {\n config = JSON.parse(data);\n } catch (error) {\n throw new Error(\n `Cannot parse configuration file at \\`${argv.configPath}\\`. Check to ensure that it is valid JSON.`,\n );\n }\n\n if (argv.skipImport === true) {\n config.skipImport = argv.skipImport;\n }\n\n if (argv.showOnlyTimepoint === true) {\n config.showOnlyTimepoint = argv.showOnlyTimepoint;\n }\n\n return config;\n}\n\n/*\n * Get the full path to this module's folder.\n */\nexport function getPathToThisModuleFolder() {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n // Dynamically calculate the path to this module's folder\n let distFolderPath;\n if (__dirname.endsWith('/dist/bin') || __dirname.endsWith('/dist/app')) {\n // When the file is in 'dist/bin' or 'dist/app'\n distFolderPath = resolve(__dirname, '../../');\n } else if (__dirname.endsWith('/dist')) {\n // When the file is in 'dist'\n distFolderPath = resolve(__dirname, '../');\n } else {\n // In case it's neither, fallback to project root\n distFolderPath = resolve(__dirname, '../../');\n }\n\n return distFolderPath;\n}\n\n/*\n * Get the full path to the views folder.\n */\nexport function getPathToViewsFolder(config: Config) {\n if (config.templatePath) {\n return untildify(config.templatePath);\n }\n\n return join(getPathToThisModuleFolder(), 'views/default');\n}\n\n/*\n * Get the full path of a template file.\n */\nfunction getPathToTemplateFile(templateFileName: string, config: Config) {\n const fullTemplateFileName =\n config.noHead !== true\n ? `${templateFileName}_full.pug`\n : `${templateFileName}.pug`;\n\n return join(getPathToViewsFolder(config), fullTemplateFileName);\n}\n\n/*\n * Prepare the outputPath directory for writing timetable files.\n */\nexport async function prepDirectory(outputPath: string, config: Config) {\n // Check if outputPath exists\n try {\n await access(outputPath);\n } catch (error: any) {\n try {\n await mkdir(outputPath, { recursive: true });\n } catch (error: any) {\n if (error?.code === 'ENOENT') {\n throw new Error(\n `Unable to write to ${outputPath}. Try running this command from a writable directory.`,\n );\n }\n\n throw error;\n }\n }\n\n // Check if outputPath is empty\n const files = await readdir(outputPath);\n if (config.overwriteExistingFiles === false && files.length > 0) {\n throw new Error(\n `Output directory ${outputPath} is not empty. Please specify an empty directory.`,\n );\n }\n\n // Delete all files in outputPath if `overwriteExistingFiles` is true\n if (config.overwriteExistingFiles === true) {\n await rm(join(outputPath, '*'), { recursive: true, force: true });\n }\n}\n\n/*\n * Copy needed CSS and JS to export path.\n */\nexport async function copyStaticAssets(config: Config, outputPath: string) {\n const viewsFolderPath = getPathToViewsFolder(config);\n const thisModuleFolderPath = getPathToThisModuleFolder();\n\n const foldersToCopy = ['css', 'js', 'img'];\n\n for (const folder of foldersToCopy) {\n if (\n await access(join(viewsFolderPath, folder))\n .then(() => true)\n .catch(() => false)\n ) {\n await cp(join(viewsFolderPath, folder), join(outputPath, folder), {\n recursive: true,\n });\n }\n }\n\n // Copy js libraries from node_modules if needed for GTFS-Realtime\n if (\n config.hasGtfsRealtimeVehiclePositions ||\n config.hasGtfsRealtimeTripUpdates ||\n config.hasGtfsRealtimeAlerts\n ) {\n await copyFile(\n join(thisModuleFolderPath, 'dist/frontend_libraries/pbf.js'),\n join(outputPath, 'js/pbf.js'),\n );\n\n await copyFile(\n join(\n thisModuleFolderPath,\n 'dist/frontend_libraries/gtfs-realtime.browser.proto.js',\n ),\n join(outputPath, 'js/gtfs-realtime.browser.proto.js'),\n );\n }\n\n if (config.hasGtfsRealtimeAlerts) {\n await copyFile(\n join(thisModuleFolderPath, 'dist/frontend_libraries/anchorme.min.js'),\n join(outputPath, 'js/anchorme.min.js'),\n );\n }\n\n if (config.showMap) {\n await copyFile(\n join(thisModuleFolderPath, 'dist/frontend_libraries/maplibre-gl.js'),\n join(outputPath, 'js/maplibre-gl.js'),\n );\n\n await copyFile(\n join(thisModuleFolderPath, 'dist/frontend_libraries/maplibre-gl.css'),\n join(outputPath, 'css/maplibre-gl.css'),\n );\n\n await copyFile(\n join(\n thisModuleFolderPath,\n 'dist/frontend_libraries/maplibre-gl-geocoder.js',\n ),\n join(outputPath, 'js/maplibre-gl-geocoder.js'),\n );\n\n await copyFile(\n join(\n thisModuleFolderPath,\n 'dist/frontend_libraries/maplibre-gl-geocoder.css',\n ),\n join(outputPath, 'css/maplibre-gl-geocoder.css'),\n );\n }\n}\n\n/*\n * Zips the content of the specified folder.\n */\nexport function zipFolder(outputPath) {\n const output = createWriteStream(join(outputPath, 'timetables.zip'));\n const archive = archiver('zip');\n\n return new Promise((resolve, reject) => {\n output.on('close', resolve);\n archive.on('error', reject);\n archive.pipe(output);\n archive.glob('**/*.{txt,css,js,png,jpg,jpeg,svg,csv,pdf,html}', {\n cwd: outputPath,\n });\n archive.finalize();\n });\n}\n\n/*\n * Generate the filename for an html file.\n */\nexport function generateTimetablePageFileName(\n timetablePage: FormattedTimetablePage,\n config: Config,\n) {\n // If the timetable page is from timetable_pages.txt, use the filename specified.\n if (timetablePage.filename) {\n return sanitize(timetablePage.filename);\n }\n\n // Else if config.groupTimetablesIntoPages is true and all timetables share the same route, use the route as the filename\n if (\n config.groupTimetablesIntoPages === true &&\n uniqBy(timetablePage.timetables, 'route_id').length === 1\n ) {\n const route = timetablePage.timetables[0].routes[0];\n return sanitize(`${formatRouteNameForFilename(route).toLowerCase()}.html`);\n }\n\n const timetable = timetablePage.timetables[0];\n\n // Else use timetable_id for filename\n if (timetable.timetable_id) {\n return sanitize(\n `${timetable.timetable_id.replace(/\\|/g, '_').toLowerCase()}.html`,\n );\n }\n\n // Else generate a detailed filename\n let filename = '';\n\n for (const route of timetable.routes) {\n filename += `_${formatRouteNameForFilename(route)}`;\n }\n\n if (!isNullOrEmpty(timetable.direction_id)) {\n filename += `_${timetable.direction_id}`;\n }\n\n filename += `_${formatDays(timetable, config).replace(/\\s/g, '')}.html`;\n\n return sanitize(filename.toLowerCase());\n}\n\n/*\n * Generate the filename for a csv file.\n */\nexport function generateCSVFileName(\n timetable: FormattedTimetable,\n config: Config,\n) {\n let filename = timetable.timetable_id ?? '';\n\n for (const route of timetable.routes) {\n filename += `_${formatRouteNameForFilename(route)}`;\n }\n\n if (!isNullOrEmpty(timetable.direction_id)) {\n filename += `_${timetable.direction_id}`;\n }\n\n filename += `_${formatDays(timetable, config).replace(/\\s/g, '')}.csv`;\n\n return sanitize(filename).toLowerCase();\n}\n\n/*\n * Generates the folder name for a timetable page based on the date.\n */\nexport function generateFolderName(timetablePage) {\n // Use first timetable in timetable page for start date and end date\n const timetable = timetablePage.consolidatedTimetables[0];\n if (!timetable.start_date || !timetable.end_date) {\n return 'timetables';\n }\n\n return sanitize(`${timetable.start_date}-${timetable.end_date}`);\n}\n\n/*\n * Render the HTML for a timetable based on the config.\n */\nexport async function renderTemplate(\n templateFileName: string,\n templateVars,\n config: Config,\n) {\n const templatePath = getPathToTemplateFile(templateFileName, config);\n\n // Make template functions, lodash and marked available inside pug templates.\n const html = await renderFile(templatePath, {\n _,\n cssEscape,\n md: (text: string) => sanitizeHtml(marked.parseInline(text) as string),\n ...templateFunctions,\n formatRouteColor,\n formatRouteTextColor,\n ...templateVars,\n });\n\n // Beautify HTML if `beautify` is set in config.\n if (config.beautify === true) {\n return beautify.html_beautify(html, {\n indent_size: 2,\n });\n }\n\n return html;\n}\n\n/*\n * Render the PDF for a timetable based on the config.\n */\nexport async function renderPdf(htmlPath: string) {\n const pdfPath = htmlPath.replace(/html$/, 'pdf');\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.emulateMediaType('print');\n await page.goto(`file://${htmlPath}`, {\n waitUntil: 'networkidle0',\n });\n await page.pdf({\n path: pdfPath,\n });\n\n await browser.close();\n}\n\n/**\n * Converts a tilde path to a full path\n * @param pathWithTilde The path to convert\n * @returns The full path\n */\nexport function untildify(pathWithTilde: string): string {\n return homeDirectory\n ? pathWithTilde.replace(/^~(?=$|\\/|\\\\)/, homeDirectory)\n : pathWithTilde;\n}\n","import {\n clone,\n find,\n first,\n groupBy,\n last,\n omit,\n sortBy,\n zipObject,\n} from 'lodash-es';\nimport moment from 'moment';\nimport { Route } from 'gtfs';\n\nimport {\n fromGTFSTime,\n minutesAfterMidnight,\n calendarToCalendarCode,\n secondsAfterMidnight,\n toGTFSTime,\n updateTimeByOffset,\n} from './time-utils.js';\nimport { isTimepoint } from './utils.js';\n\n/*\n * Replace all instances in a string with items from an object.\n */\nfunction replaceAll(string, mapObject) {\n const re = new RegExp(Object.keys(mapObject).join('|'), 'gi');\n return string.replace(re, (matched) => mapObject[matched]);\n}\n\n/*\n * Determine if value is null or empty string.\n */\nexport function isNullOrEmpty(value) {\n return value === null || value === '';\n}\n\n/*\n * Format a date for display.\n */\nexport function formatDate(date, dateFormat) {\n if (date.holiday_name) {\n return date.holiday_name;\n }\n\n return moment(date.date, 'YYYYMMDD').format(dateFormat);\n}\n\n/*\n * Convert time to seconds.\n */\nexport function timeToSeconds(time) {\n return moment.duration(time).asSeconds();\n}\n\n/*\n * Format a single stoptime.\n */\n/* eslint-disable complexity */\nfunction formatStopTime(stoptime, timetable, config) {\n stoptime.classes = [];\n\n if (stoptime.type === 'arrival' && stoptime.arrival_time) {\n const arrivalTime = fromGTFSTime(stoptime.arrival_time);\n stoptime.formatted_time = arrivalTime.format(config.timeFormat);\n stoptime.classes.push(arrivalTime.format('a'));\n } else if (stoptime.type === 'departure' && stoptime.departure_time) {\n const departureTime = fromGTFSTime(stoptime.departure_time);\n stoptime.formatted_time = departureTime.format(config.timeFormat);\n stoptime.classes.push(departureTime.format('a'));\n }\n\n if (stoptime.pickup_type === 1) {\n stoptime.noPickup = true;\n stoptime.classes.push('no-pickup');\n if (timetable.noPickupSymbol !== null) {\n timetable.noPickupSymbolUsed = true;\n }\n } else if (stoptime.pickup_type === 2 || stoptime.pickup_type === 3) {\n stoptime.requestPickup = true;\n stoptime.classes.push('request-pickup');\n if (timetable.requestPickupSymbol !== null) {\n timetable.requestPickupSymbolUsed = true;\n }\n }\n\n if (stoptime.drop_off_type === 1) {\n stoptime.noDropoff = true;\n stoptime.classes.push('no-drop-off');\n if (timetable.noDropoffSymbol !== null) {\n timetable.noDropoffSymbolUsed = true;\n }\n } else if (stoptime.drop_off_type === 2 || stoptime.drop_off_type === 3) {\n stoptime.requestDropoff = true;\n stoptime.classes.push('request-drop-off');\n if (timetable.requestDropoffSymbol !== null) {\n timetable.requestDropoffSymbolUsed = true;\n }\n }\n\n if (stoptime.timepoint === 0 || stoptime.departure_time === '') {\n stoptime.interpolated = true;\n stoptime.classes.push('interpolated');\n if (timetable.interpolatedStopSymbol !== null) {\n timetable.interpolatedStopSymbolUsed = true;\n }\n }\n\n if (\n stoptime.timepoint === null &&\n stoptime.departure_time === null &&\n stoptime.stop_sequence === null\n ) {\n stoptime.skipped = true;\n stoptime.classes.push('skipped');\n if (timetable.noServiceSymbol !== null) {\n timetable.noServiceSymbolUsed = true;\n }\n }\n\n if (stoptime.timepoint === 1) {\n stoptime.classes.push('timepoint');\n }\n\n return stoptime;\n}\n/* eslint-enable complexity */\n\n/*\n * Find hourly times for each stop for hourly schedules.\n */\nfunction filterHourlyTimes(stops) {\n // Find all stoptimes within the first 60 minutes.\n const firstStopTimes = [];\n const firstTripMinutes = minutesAfterMidnight(stops[0].trips[0].arrival_time);\n for (const trip of stops[0].trips) {\n const minutes = minutesAfterMidnight(trip.arrival_time);\n if (minutes >= firstTripMinutes + 60) {\n break;\n }\n\n firstStopTimes.push(fromGTFSTime(trip.arrival_time));\n }\n\n // Sort stoptimes by minutes for first stop.\n const firstStopTimesAndIndex = firstStopTimes.map((time, idx) => ({\n idx,\n time,\n }));\n const sortedFirstStopTimesAndIndex = sortBy(firstStopTimesAndIndex, (item) =>\n Number.parseInt(item.time.format('m'), 10),\n );\n\n // Filter and arrange stoptimes for all stops based on sort.\n return stops.map((stop) => {\n stop.hourlyTimes = sortedFirstStopTimesAndIndex.map((item) =>\n fromGTFSTime(stop.trips[item.idx].arrival_time).format(':mm'),\n );\n\n return stop;\n });\n}\n\n/*\n * Format a calendar's list of days for display using abbreviated day names.\n */\nconst days = [\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n 'sunday',\n];\nexport function formatDays(calendar, config) {\n const daysShort = config.daysShortStrings;\n let daysInARow = 0;\n let dayString = '';\n\n if (!calendar) {\n return '';\n }\n\n for (let i = 0; i <= 6; i += 1) {\n const currentDayOperating = calendar[days[i]] === 1;\n const previousDayOperating = i > 0 ? calendar[days[i - 1]] === 1 : false;\n const nextDayOperating = i < 6 ? calendar[days[i + 1]] === 1 : false;\n\n if (currentDayOperating) {\n if (dayString.length > 0) {\n if (!previousDayOperating) {\n dayString += ', ';\n } else if (daysInARow === 1) {\n dayString += '-';\n }\n }\n\n daysInARow += 1;\n\n if (\n dayString.length === 0 ||\n !nextDayOperating ||\n i === 6 ||\n !previousDayOperating\n ) {\n dayString += daysShort[i];\n }\n } else {\n daysInARow = 0;\n }\n }\n\n if (dayString.length === 0) {\n dayString = config.noRegularServiceDaysText;\n }\n\n return dayString;\n}\n\n/*\n * Format a list of days for display using full names of days.\n */\nexport function formatDaysLong(dayList, config) {\n const mapObject = zipObject(config.daysShortStrings, config.daysStrings);\n\n return replaceAll(dayList, mapObject);\n}\n\n/*\n * Format a trip.\n */\nexport function formatTrip(trip, timetable, calendars, config) {\n trip.calendar = find(calendars, {\n service_id: trip.service_id,\n });\n trip.dayList = formatDays(trip.calendar, config);\n trip.dayListLong = formatDaysLong(trip.dayList, config);\n\n if (timetable.routes.length === 1) {\n trip.route_short_name = timetable.routes[0].route_short_name;\n } else {\n const route = timetable.routes.find(\n (route) => route.route_id === trip.route_id,\n );\n trip.route_short_name = route.route_short_name;\n }\n\n return trip;\n}\n\n/*\n * Format a frequency.\n */\nexport function formatFrequency(frequency, config) {\n const startTime = fromGTFSTime(frequency.start_time);\n const endTime = fromGTFSTime(frequency.end_time);\n const headway = moment.duration(frequency.headway_secs, 'seconds');\n frequency.start_formatted_time = startTime.format(config.timeFormat);\n frequency.end_formatted_time = endTime.format(config.timeFormat);\n frequency.headway_min = Math.round(headway.asMinutes());\n return frequency;\n}\n\n/*\n * Generate a timetable id.\n */\nexport function formatTimetableId({\n routeIds,\n directionId,\n days,\n dates,\n}: {\n routeIds: string[];\n directionId?: 0 | 1;\n days: {\n monday?: null | 0 | 1;\n tuesday?: null | 0 | 1;\n wednesday?: null | 0 | 1;\n thursday?: null | 0 | 1;\n friday?: null | 0 | 1;\n saturday?: null | 0 | 1;\n sunday?: null | 0 | 1;\n };\n dates?: number[];\n}) {\n let timetableId = routeIds.join('_');\n\n if (calendarToCalendarCode(days)) {\n timetableId += `|${calendarToCalendarCode(days)}`;\n } else if (dates && dates.length > 0) {\n timetableId += `|${dates.join('_')}`;\n }\n\n if (!isNullOrEmpty(directionId)) {\n timetableId += `|${directionId}`;\n }\n\n return timetableId;\n}\n\nfunction createEmptyStoptime(stopId, tripId) {\n return {\n id: null,\n trip_id: tripId,\n arrival_time: null,\n departure_time: null,\n stop_id: stopId,\n stop_sequence: null,\n stop_headsign: null,\n pickup_type: null,\n drop_off_type: null,\n continuous_pickup: null,\n continuous_drop_off: null,\n shape_dist_traveled: null,\n timepoint: null,\n };\n}\n\n/*\n * Format stops.\n */\nexport function formatStops(timetable, config) {\n for (const trip of timetable.orderedTrips) {\n let stopIndex = -1;\n for (const [idx, stoptime] of trip.stoptimes.entries()) {\n // Find a stop for the matching `stop_id` greater than the last `stopIndex`.\n const stop = find(timetable.stops, (st, idx) => {\n if (st.stop_id === stoptime.stop_id && idx > stopIndex) {\n stopIndex = idx;\n return true;\n }\n\n return false;\n });\n\n if (!stop) {\n continue;\n }\n\n // If first stoptime of the trip, remove drop_off_type information\n if (idx === 0) {\n stoptime.drop_off_type = 0;\n }\n\n // If last stoptime of the trip, remove pickup_type information\n if (idx === trip.stoptimes.length - 1) {\n stoptime.pickup_type = 0;\n }\n\n // If showing arrival and departure times as separate columns/rows, add\n // trip to the departure stop, unless it is the last stoptime of the trip.\n if (stop.type === 'arrival' && idx < trip.stoptimes.length - 1) {\n const departureStoptime = clone(stoptime);\n departureStoptime.type = 'departure';\n timetable.stops[stopIndex + 1].trips.push(\n formatStopTime(departureStoptime, timetable, config),\n );\n }\n\n // Show times if it is an arrival stop and is the first stoptime for the trip.\n if (!(stop.type === 'arrival' && idx === 0)) {\n stoptime.type = 'arrival';\n stop.trips.push(formatStopTime(stoptime, timetable, config));\n }\n }\n\n // Fill in any missing stoptimes for this trip.\n for (const stop of timetable.stops) {\n const lastStopTime = last(stop.trips);\n if (!lastStopTime || lastStopTime.trip_id !== trip.trip_id) {\n stop.trips.push(\n formatStopTime(\n createEmptyStoptime(stop.stop_id, trip.trip_id),\n timetable,\n config,\n ),\n );\n }\n }\n }\n\n if (timetable.orientation === 'hourly') {\n timetable.stops = filterHourlyTimes(timetable.stops);\n }\n\n for (const stop of timetable.stops) {\n stop.is_timepoint = stop.trips.some((stoptime) => isTimepoint(stoptime));\n }\n\n return timetable.stops;\n}\n\n/*\n * Formats a stop name.\n */\nexport function formatStopName(stop) {\n return `${stop.stop_name}${\n stop.type === 'arrival'\n ? ' (Arrival)'\n : stop.type === 'departure'\n ? ' (Departure)'\n : ''\n }`;\n}\n\n/*\n * Formats trip \"Continues from\".\n */\nexport function formatTripContinuesFrom(trip) {\n return trip.continues_from_route\n ? trip.continues_from_route.route.route_short_name\n : '';\n}\n\n/*\n * Formats trip \"Continues as\".\n */\nexport function formatTripContinuesAs(trip) {\n return trip.continues_as_route\n ? trip.continues_as_route.route.route_short_name\n : '';\n}\n\n/*\n * Change all stoptimes of a trip so the first trip starts at midnight. Useful\n * for hourly schedules.\n */\nexport function resetStoptimesToMidnight(trip) {\n const offsetSeconds = secondsAfterMidnight(\n first(trip.stoptimes).departure_time,\n );\n if (offsetSeconds > 0) {\n for (const stoptime of trip.stoptimes) {\n stoptime.departure_time = toGTFSTime(\n fromGTFSTime(stoptime.departure_time).subtract(\n offsetSeconds,\n 'seconds',\n ),\n );\n stoptime.arrival_time = toGTFSTime(\n fromGTFSTime(stoptime.arrival_time).subtract(offsetSeconds, 'seconds'),\n );\n }\n }\n\n return trip;\n}\n\n/*\n * Change all stoptimes of a trip by a specified number of seconds. Useful for\n * hourly schedules.\n */\nexport function updateStoptimesByOffset(trip, offsetSeconds) {\n return trip.stoptimes.map((stoptime) => {\n delete stoptime._id;\n stoptime.departure_time = updateTimeByOffset(\n stoptime.departure_time,\n offsetSeconds,\n );\n stoptime.arrival_time = updateTimeByOffset(\n stoptime.arrival_time,\n offsetSeconds,\n );\n stoptime.trip_id = trip.trip_id;\n return stoptime;\n });\n}\n\n/*\n * Format a route color as a hex color.\n */\nexport function formatRouteColor(route) {\n // Defaults to #000000 (black) if no color is provided.\n return route.route_color ? `#${route.route_color}` : '#000000';\n}\n\n/*\n * Format a route text color as a hex color.\n */\nexport function formatRouteTextColor(route) {\n // Defaults to #FFFFFF (white) if no color is provided.\n return route.route_text_color ? `#${route.route_text_color}` : '#FFFFFF';\n}\n\n/*\n * Format a label for a timetable.\n */\nexport function formatTimetableLabel(timetable) {\n if (!isNullOrEmpty(timetable.timetable_label)) {\n return timetable.timetable_label;\n }\n\n let timetableLabel = '';\n\n if (timetable.routes && timetable.routes.length > 0) {\n timetableLabel += 'Route ';\n if (!isNullOrEmpty(timetable.routes[0].route_short_name)) {\n timetableLabel += timetable.routes[0].route_short_name;\n } else if (!isNullOrEmpty(timetable.routes[0].route_long_name)) {\n timetableLabel += timetable.routes[0].route_long_name;\n }\n }\n\n if (timetable.stops && timetable.stops.length > 0) {\n const firstStop = timetable.stops[0].stop_name;\n const lastStop = timetable.stops[timetable.stops.length - 1].stop_name;\n if (firstStop === lastStop) {\n if (!isNullOrEmpty(timetable.routes[0].route_long_name)) {\n timetableLabel += ` - ${timetable.routes[0].route_long_name}`;\n }\n\n timetableLabel += ' - Loop';\n } else {\n timetableLabel += ` - ${firstStop} to ${lastStop}`;\n }\n } else if (timetable.direction_name !== null) {\n timetableLabel += ` to ${timetable.direction_name}`;\n }\n\n return timetableLabel;\n}\n\n/*\n * Format a route name.\n */\nexport const formatRouteName = (route: Route) => {\n if (route.route_long_name === null || route.route_long_name === '') {\n return `Route ${route.route_short_name}`;\n }\n\n return route.route_long_name ?? 'Unknown';\n};\n\n/*\n * Format a route name for use in a filename.\n */\nexport const formatRouteNameForFilename = (route: Route) => {\n if (route.route_short_name) {\n return route.route_short_name.replace(/\\s/g, '-');\n } else if (route.route_long_name) {\n return route.route_long_name.replace(/\\s/g, '-');\n }\n\n return 'Unknown';\n};\n\n/*\n * Format a list for display.\n */\nexport const formatListForDisplay = (list: string[]) => {\n return new Intl.ListFormat('en-US', {\n style: 'long',\n type: 'conjunction',\n }).format(list);\n};\n\n/*\n * Merge timetables with same `timetable_id`.\n */\nexport function mergeTimetablesWithSameId(timetables) {\n if (timetables.length === 0) {\n return [];\n }\n\n const mergedTimetables = groupBy(timetables, 'timetable_id');\n\n return Object.values(mergedTimetables).map((timetableGroup) => {\n const mergedTimetable = omit(timetableGroup[0], 'route_id');\n\n mergedTimetable.route_ids = timetableGroup.map(\n (timetable) => timetable.route_id,\n );\n\n return mergedTimetable;\n });\n}\n","import moment from 'moment';\n\ntype CalendarBit = '0' | '1';\nexport type CalendarCode =\n `${CalendarBit}${CalendarBit}${CalendarBit}${CalendarBit}${CalendarBit}${CalendarBit}${CalendarBit}`;\n\n/*\n * Convert a GTFS formatted time string into a moment less than 24 hours.\n */\nexport function fromGTFSTime(timeString) {\n const duration = moment.duration(timeString);\n\n return moment({\n hour: duration.hours(),\n minute: duration.minutes(),\n second: duration.seconds(),\n });\n}\n\n/*\n * Convert a moment into a GTFS formatted time string.\n */\nexport function toGTFSTime(time) {\n return time.format('HH:mm:ss');\n}\n\n/*\n * Convert a object of weekdays into a a string containing 1s and 0s.\n */\nexport function calendarToCalendarCode(calendar: {\n monday?: null | 0 | 1;\n tuesday?: null | 0 | 1;\n wednesday?: null | 0 | 1;\n thursday?: null | 0 | 1;\n friday?: null | 0 | 1;\n saturday?: null | 0 | 1;\n sunday?: null | 0 | 1;\n}): CalendarCode | '' {\n if (Object.values(calendar).every((value) => value === null)) {\n return '';\n }\n\n return `${calendar.monday ?? '0'}${calendar.tuesday ?? '0'}${calendar.wednesday ?? '0'}${calendar.thursday ?? '0'}${calendar.friday ?? '0'}${calendar.saturday ?? '0'}${calendar.sunday ?? '0'}`;\n}\n\n/*\n * Convert a string of 1s and 0s representing a weekday to an object.\n */\nexport function calendarCodeToCalendar(code: CalendarCode) {\n const days = [\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n 'sunday',\n ];\n const calendar: {\n monday?: null | 0 | 1;\n tuesday?: null | 0 | 1;\n wednesday?: null | 0 | 1;\n thursday?: null | 0 | 1;\n friday?: null | 0 | 1;\n saturday?: null | 0 | 1;\n sunday?: null | 0 | 1;\n } = {};\n\n for (const [index, day] of days.entries()) {\n calendar[day] = code[index];\n }\n\n return calendar;\n}\n\n/* Concert an object of weekdays and a date range into a list of dates. */\nexport function calendarToDateList(\n calendar: {\n monday?: null | 0 | 1;\n tuesday?: null | 0 | 1;\n wednesday?: null | 0 | 1;\n thursday?: null | 0 | 1;\n friday?: null | 0 | 1;\n saturday?: null | 0 | 1;\n sunday?: null | 0 | 1;\n },\n startDate: number,\n endDate: number | null,\n) {\n if (!startDate || !endDate) {\n return [];\n }\n\n const activeWeekdays = [\n calendar.monday === 1 ? 1 : null,\n calendar.tuesday === 1 ? 2 : null,\n calendar.wednesday === 1 ? 3 : null,\n calendar.thursday === 1 ? 4 : null,\n calendar.friday === 1 ? 5 : null,\n calendar.saturday === 1 ? 6 : null,\n calendar.sunday === 1 ? 7 : null,\n ].filter((weekday): weekday is number => weekday !== null);\n\n if (activeWeekdays.length === 0) {\n return [];\n }\n\n const activeWeekdaySet = new Set(activeWeekdays);\n const dates = new Set<number>();\n const date = moment(startDate.toString(), 'YYYYMMDD');\n const endDateMoment = moment(endDate.toString(), 'YYYYMMDD');\n\n while (date.isSameOrBefore(endDateMoment)) {\n const isoWeekday = date.isoWeekday();\n if (activeWeekdaySet.has(isoWeekday)) {\n dates.add(parseInt(date.format('YYYYMMDD'), 10));\n }\n date.add(1, 'day');\n }\n\n return Array.from(dates);\n}\n\n/*\n * Get number of seconds after midnight of a GTFS formatted time string.\n */\nexport function secondsAfterMidnight(timeString) {\n return moment.duration(timeString).asSeconds();\n}\n\n/*\n * Get number of minutes after midnight of a GTFS formatted time string.\n */\nexport function minutesAfterMidnight(timeString) {\n return moment.duration(timeString).asMinutes();\n}\n\n/*\n * Add specified number of seconds to a GTFS formatted time string.\n */\nexport function updateTimeByOffset(timeString, offsetSeconds) {\n const newTime = fromGTFSTime(timeString);\n return toGTFSTime(newTime.add(offsetSeconds, 'seconds'));\n}\n","import {\n cloneDeep,\n compact,\n countBy,\n difference,\n entries,\n every,\n find,\n findLast,\n first,\n flatMap,\n flow,\n groupBy,\n head,\n last,\n maxBy,\n orderBy,\n partialRight,\n reduce,\n size,\n some,\n sortBy,\n uniq,\n uniqBy,\n zip,\n} from 'lodash-es';\nimport {\n getCalendarDates,\n getTrips,\n getTimetableNotesReferences,\n getTimetableNotes,\n getRoutes,\n getCalendars,\n getTimetableStopOrders,\n getStops,\n getStopAttributes,\n getStoptimes,\n getFrequencies,\n getTimetables,\n getTimetablePages,\n getAgencies,\n openDb,\n Calendar,\n CalendarDate,\n Frequency,\n Route,\n Trip,\n StopTime,\n Stop,\n} from 'gtfs';\nimport { stringify } from 'csv-stringify';\nimport moment from 'moment';\nimport sqlString from 'sqlstring';\nimport toposort from 'toposort';\n\nimport { generateTimetablePageFileName, renderTemplate } from './file-utils.js';\nimport {\n formatDate,\n formatDays,\n formatDaysLong,\n formatFrequency,\n formatListForDisplay,\n formatRouteName,\n formatStopName,\n formatStops,\n formatTimetableId,\n formatTimetableLabel,\n formatTrip,\n formatTripContinuesAs,\n formatTripContinuesFrom,\n isNullOrEmpty,\n mergeTimetablesWithSameId,\n resetStoptimesToMidnight,\n timeToSeconds,\n updateStoptimesByOffset,\n} from './formatters.js';\nimport { getTimetableGeoJSON, getAgencyGeoJSON } from './geojson-utils.js';\nimport {\n calendarToCalendarCode,\n secondsAfterMidnight,\n fromGTFSTime,\n calendarCodeToCalendar,\n calendarToDateList,\n} from './time-utils.js';\nimport { formatTripNameForCSV } from './template-functions.js';\n\nimport type {\n Config,\n FormattedTimetable,\n FormattedTimetablePage,\n} from '../types/index.ts';\n\nimport packageJson from '../../package.json' with { type: 'json' };\nconst { version } = packageJson;\n\ntype FormattedTrip = Trip & {\n firstStoptime: number;\n lastStoptime: number;\n stoptimes: StopTime[];\n};\n\n/*\n * Determine if a stoptime is a timepoint.\n */\nexport const isTimepoint = (stoptime: StopTime) => {\n if (isNullOrEmpty(stoptime.timepoint)) {\n return (\n !isNullOrEmpty(stoptime.arrival_time) &&\n !isNullOrEmpty(stoptime.departure_time)\n );\n }\n\n return stoptime.timepoint === 1;\n};\n\n/*\n * Find the longest trip (most stops) in a group of trips and return stoptimes.\n */\nconst getLongestTripStoptimes = (trips: FormattedTrip[], config: Config) => {\n const filteredTripStoptimes = trips.map((trip) =>\n trip.stoptimes.filter((stoptime) => {\n // If `showOnlyTimepoint` is true, then filter out all non-timepoints.\n if (config.showOnlyTimepoint === true) {\n return isTimepoint(stoptime);\n }\n return true;\n }),\n );\n\n return maxBy(filteredTripStoptimes, (stoptimes) => size(stoptimes));\n};\n\n/*\n * Find the first stop_id that all trips have in common, otherwise use the first\n * stoptime.\n */\nconst findCommonStopId = (trips: FormattedTrip[], config: Config) => {\n const longestTripStoptimes = getLongestTripStoptimes(trips, config);\n\n if (!longestTripStoptimes) {\n return null;\n }\n\n const commonStoptime = longestTripStoptimes.find((stoptime, idx) => {\n // If longest trip is a loop (first and last stops the same), then skip first stoptime.\n if (idx === 0 && stoptime.stop_id === last(longestTripStoptimes)?.stop_id) {\n return false;\n }\n\n // If stoptime doesn't have a time, skip it.\n if (isNullOrEmpty(stoptime.arrival_time)) {\n return false;\n }\n\n // Check if all trips have this stoptime and that they have a time.\n return every(trips, (trip) =>\n trip.stoptimes.find(\n (tripStoptime) =>\n tripStoptime.stop_id === stoptime.stop_id &&\n tripStoptime.arrival_time !== null,\n ),\n );\n });\n\n return commonStoptime ? commonStoptime.stop_id : null;\n};\n\n/*\n * Return a set of unique trips based on departure and arrival times.\n */\nconst deduplicateTrips = (trips: FormattedTrip[]) => {\n if (trips.length <= 1) {\n return trips;\n }\n\n const uniqueTrips = new Map<string, FormattedTrip>();\n\n for (const trip of trips) {\n // Create a unique signature for this trip based on departure and arrival times.\n const tripSignature = trip.stoptimes\n .map(\n (stoptime) =>\n `${stoptime.stop_id}|${stoptime.departure_time}|${stoptime.arrival_time}`,\n )\n .join('|');\n\n if (!uniqueTrips.has(tripSignature)) {\n uniqueTrips.set(tripSignature, trip);\n }\n }\n\n return Array.from(uniqueTrips.values());\n};\n\n/*\n * Sort trips chronologically, using specified config.sortingAlgorithm\n */\nconst sortTrips = (trips: FormattedTrip[], config: Config): FormattedTrip[] => {\n let sortedTrips;\n let commonStopId;\n\n if (config.sortingAlgorithm === 'common') {\n // Sort trips chronologically using the stoptime of a common stop across all trips.\n\n commonStopId = findCommonStopId(trips, config);\n\n if (commonStopId) {\n sortedTrips = sortTripsByStoptimeAtStop(trips, commonStopId);\n } else {\n // Default to 'beginning' if no common stop is found.\n sortedTrips = sortTrips(trips, {\n ...config,\n sortingAlgorithm: 'beginning',\n });\n }\n } else if (config.sortingAlgorithm === 'beginning') {\n // Sort trips chronologically using first stoptime of each trip, which can be at different stops.\n\n for (const trip of trips) {\n if (trip.stoptimes.length === 0) {\n continue;\n }\n\n trip.firstStoptime = timeToSeconds(trip.stoptimes[0].departure_time);\n trip.lastStoptime = timeToSeconds(\n trip.stoptimes[trip.stoptimes.length - 1].departure_time,\n );\n }\n\n sortedTrips = sortBy(trips, ['firstStoptime', 'lastStoptime']);\n } else if (config.sortingAlgorithm === 'end') {\n // Sort trips chronologically using last stoptime of each trip, which can be at different stops.\n\n for (const trip of trips) {\n if (trip.stoptimes.length === 0) {\n continue;\n }\n\n trip.firstStoptime = timeToSeconds(trip.stoptimes[0].departure_time);\n trip.lastStoptime = timeToSeconds(\n trip.stoptimes[trip.stoptimes.length - 1].departure_time,\n );\n }\n\n sortedTrips = sortBy(trips, ['lastStoptime', 'firstStoptime']);\n } else if (config.sortingAlgorithm === 'first') {\n // Sort trips chronologically using the stoptime of a the first stop of the longest trip.\n\n const longestTripStoptimes = getLongestTripStoptimes(trips, config);\n const firstStopId = first(longestTripStoptimes).stop_id;\n sortedTrips = sortTripsByStoptimeAtStop(trips, firstStopId);\n } else if (config.sortingAlgorithm === 'last') {\n // Sort trips chronologically using the stoptime of a the last stop of the longest trip.\n\n const longestTripStoptimes = getLongestTripStoptimes(trips, config);\n const lastStopId = last(longestTripStoptimes).stop_id;\n sortedTrips = sortTripsByStoptimeAtStop(trips, lastStopId);\n }\n\n return sortedTrips ?? [];\n};\n\n/*\n * Sort trips by stoptime at a specific stop\n */\nconst sortTripsByStoptimeAtStop = (trips: FormattedTrip[], stopId: string) =>\n sortBy(trips, (trip) => {\n const stoptime = find(trip.stoptimes, { stop_id: stopId });\n return stoptime ? timeToSeconds(stoptime.departure_time) : undefined;\n });\n\n/*\n * Get all calendar dates for a specific timetable.\n */\nconst getCalendarDatesForTimetable = (\n timetable: FormattedTimetable,\n config: Config,\n) => {\n const calendarDates = getCalendarDates(\n {\n service_id: timetable.service_ids,\n },\n [],\n [['date', 'ASC']],\n );\n const start = moment(timetable.start_date, 'YYYYMMDD');\n const end = moment(timetable.end_date, 'YYYYMMDD');\n const excludedDates = new Set();\n const includedDates = new Set();\n\n for (const calendarDate of calendarDates) {\n if (\n moment(calendarDate.date, 'YYYYMMDD').isBetween(\n start,\n end,\n undefined,\n '[]',\n )\n ) {\n if (calendarDate.exception_type === 1) {\n includedDates.add(formatDate(calendarDate, config.dateFormat));\n } else if (calendarDate.exception_type === 2) {\n excludedDates.add(formatDate(calendarDate, config.dateFormat));\n }\n }\n }\n\n // Remove dates that are both included and excluded from both lists\n const includedAndExcludedDates = new Set(\n [...excludedDates].filter((date) => includedDates.has(date)),\n );\n\n return {\n excludedDates: [...excludedDates].filter(\n (date) => !includedAndExcludedDates.has(date),\n ),\n includedDates: [...includedDates].filter(\n (date) => !includedAndExcludedDates.has(date),\n ),\n };\n};\n\n/*\n * Get days of the week from calendars.\n */\nconst getDaysFromCalendars = (calendars: Calendar[]) => {\n const days = {\n monday: 0,\n tuesday: 0,\n wednesday: 0,\n thursday: 0,\n friday: 0,\n saturday: 0,\n sunday: 0,\n };\n\n for (const calendar of calendars) {\n for (const day of Object.keys(days) as (keyof typeof days)[]) {\n /* eslint-disable-next-line no-bitwise */\n days[day] = days[day] | calendar[day];\n }\n }\n\n return days;\n};\n\n/*\n * Get the `trip_headsign` for a specific timetable.\n */\nconst getDirectionHeadsignFromTimetable = (timetable: FormattedTimetable) => {\n const trips = getTrips(\n {\n direction_id: timetable.direction_id,\n route_id: timetable.route_ids,\n },\n ['trip_headsign'],\n );\n\n if (trips.length === 0) {\n return '';\n }\n\n const mostCommonHeadsign = flow(\n countBy,\n entries,\n partialRight(maxBy, last),\n head,\n )(compact(trips.map((trip) => trip.trip_headsign)));\n\n return mostCommonHeadsign;\n};\n\n/*\n * Get the notes for a specific timetable.\n */\nconst getTimetableNotesForTimetable = (\n timetable: FormattedTimetable,\n config: Config,\n) => {\n const noteReferences = [\n // Get all notes for this timetable.\n ...getTimetableNotesReferences({\n timetable_id: timetable.timetable_id,\n }),\n\n // Get all notes for this route.\n ...getTimetableNotesReferences({\n route_id: timetable.routes.map((route) => route.route_id),\n timetable_id: null,\n }),\n\n // Get all notes for all trips in this timetable.\n ...getTimetableNotesReferences({\n trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),\n }),\n\n // Get all notes for all stops in this timetable.\n ...getTimetableNotesReferences({\n stop_id: timetable.stops.map((stop) => stop.stop_id),\n trip_id: null,\n route_id: null,\n timetable_id: null,\n }),\n ];\n\n const usedNoteReferences = [];\n // Check if stop_sequence matches any trip.\n for (const noteReference of noteReferences) {\n if (\n noteReference.stop_sequence === '' ||\n noteReference.stop_sequence === null\n ) {\n usedNoteReferences.push(noteReference);\n continue;\n }\n\n // Note references with stop_sequence must also have stop_id.\n if (noteReference.stop_id === '' || noteReference.stop_id === null) {\n timetable.warnings.push(\n `Timetable Note Reference for note_id=${noteReference.note_id} has a \\`stop_sequence\\` but no \\`stop_id\\` - ignoring`,\n );\n continue;\n }\n\n const stop = timetable.stops.find(\n (stop) => stop.stop_id === noteReference.stop_id,\n );\n\n if (!stop) {\n continue;\n }\n\n const tripWithMatchingStopSequence = stop.trips.find(\n (trip) => trip.stop_sequence === noteReference.stop_sequence,\n );\n\n if (tripWithMatchingStopSequence) {\n usedNoteReferences.push(noteReference);\n }\n }\n\n const notes = getTimetableNotes({\n note_id: usedNoteReferences.map((noteReference) => noteReference.note_id),\n });\n\n // Assign symbols to each note if unassigned. Use a-z then default to integers.\n const symbols = 'abcdefghijklmnopqrstuvwxyz'.split('');\n let symbolIndex = 0;\n for (const note of notes) {\n if (note.symbol === '' || note.symbol === null) {\n note.symbol =\n symbolIndex < symbols.length - 1\n ? symbols[symbolIndex]\n : symbolIndex - symbols.length;\n symbolIndex += 1;\n }\n }\n\n const formattedNotes = usedNoteReferences.map((noteReference) => ({\n ...noteReference,\n ...notes.find((note) => note.note_id === noteReference.note_id),\n }));\n\n return sortBy(formattedNotes, 'symbol');\n};\n\n/*\n * Create a timetable page from timetables. Used if no\n * `timetable_pages.txt` is present.\n */\nconst createTimetablePage = ({\n timetablePageId,\n timetables,\n config,\n}: {\n timetablePageId: string;\n timetables: FormattedTimetable[];\n config: Config;\n}) => {\n const updatedTimetables = timetables.map((timetable) => {\n if (!timetable.routes) {\n timetable.routes = getRoutes({\n route_id: timetable.route_ids,\n });\n }\n\n return timetable;\n });\n\n const timetablePage = {\n timetable_page_id: timetablePageId,\n timetables: updatedTimetables,\n routes: updatedTimetables.flatMap((timetable) => timetable.routes),\n };\n\n const filename = generateTimetablePageFileName(timetablePage, config);\n\n return {\n ...timetablePage,\n filename,\n };\n};\n\n/*\n * Create a timetable from a route/direction/calendars/calendarDates. Used if no `timetables.txt` is present.\n */\nconst createTimetable = ({\n route,\n directionId,\n tripHeadsign,\n calendars,\n calendarDates,\n}: {\n route: Route;\n directionId?: 0 | 1;\n tripHeadsign?: string;\n calendars?: Calendar[];\n calendarDates?: CalendarDate[];\n}): FormattedTimetable => {\n const serviceIds = uniq([\n ...(calendars?.map((calendar) => calendar.service_id) ?? []),\n ...(calendarDates?.map((calendarDate) => calendarDate.service_id) ?? []),\n ]);\n\n const days: {\n monday: null | 0 | 1;\n tuesday: null | 0 | 1;\n wednesday: null | 0 | 1;\n thursday: null | 0 | 1;\n friday: null | 0 | 1;\n saturday: null | 0 | 1;\n sunday: null | 0 | 1;\n } = {\n monday: null,\n tuesday: null,\n wednesday: null,\n thursday: null,\n friday: null,\n saturday: null,\n sunday: null,\n };\n let startDate: number | null = null;\n let endDate: number | null = null;\n\n if (calendars && calendars.length > 0) {\n Object.assign(days, getDaysFromCalendars(calendars));\n\n startDate = parseInt(\n moment\n .min(\n calendars.map((calendar) => moment(calendar.start_date, 'YYYYMMDD')),\n )\n .format('YYYYMMDD'),\n 10,\n );\n\n endDate = parseInt(\n moment\n .max(calendars.map((calendar) => moment(calendar.end_date, 'YYYYMMDD')))\n .format('YYYYMMDD'),\n 10,\n );\n }\n\n const timetableId = formatTimetableId({\n routeIds: [route.route_id],\n directionId: directionId,\n days: days,\n dates: calendarDates?.map((calendarDate) => calendarDate.date),\n });\n\n return {\n timetable_id: timetableId,\n route_ids: [route.route_id],\n direction_id: directionId === null ? null : directionId,\n direction_name: tripHeadsign === null ? null : tripHeadsign,\n routes: [route],\n include_exceptions: calendarDates && calendarDates.length > 0 ? 1 : 0,\n service_ids: serviceIds,\n service_notes: null,\n timetable_label: null,\n start_time: null,\n end_time: null,\n orientation: null,\n timetable_sequence: null,\n show_trip_continuation: null,\n start_date: startDate,\n end_date: endDate,\n ...days,\n };\n};\n\n/*\n * Create timetable pages for all routes in an agency. Used if no\n * `timetables.txt` is present.\n */\nconst convertRoutesToTimetablePages = (config: Config) => {\n const routes = getRoutes();\n const timetablePages: FormattedTimetablePage[] = [];\n const { calendars, calendarDates } = getCalendarsFromConfig(config);\n\n for (const route of routes) {\n const trips = getTrips(\n {\n route_id: route.route_id,\n },\n ['trip_headsign', 'direction_id', 'trip_id', 'service_id'],\n );\n const uniqueTripDirections = orderBy(\n uniqBy(trips, (trip) => trip.direction_id),\n 'direction_id',\n );\n const sortedCalendars = orderBy(calendars, calendarToCalendarCode, 'desc');\n const calendarGroups = groupBy(sortedCalendars, calendarToCalendarCode);\n const calendarDateGroups = groupBy(calendarDates, 'service_id');\n\n const timetables: Timetable[] = [];\n\n for (const uniqueTripDirection of uniqueTripDirections) {\n for (const calendars of Object.values(calendarGroups)) {\n const tripsForCalendars = trips.filter((trip) =>\n some(calendars, { service_id: trip.service_id }),\n );\n if (tripsForCalendars.length > 0) {\n timetables.push(\n createTimetable({\n route,\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendars,\n }),\n );\n }\n }\n\n for (const calendarDates of Object.values(calendarDateGroups)) {\n const tripsForCalendarDates = trips.filter((trip) =>\n some(calendarDates, { service_id: trip.service_id }),\n );\n if (tripsForCalendarDates.length > 0) {\n timetables.push(\n createTimetable({\n route,\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendarDates,\n }),\n );\n }\n }\n }\n\n if (timetables.length === 0) {\n continue;\n }\n\n if (config.groupTimetablesIntoPages === true) {\n timetablePages.push(\n createTimetablePage({\n timetablePageId: `route_${route.route_short_name ?? route.route_long_name}`,\n timetables,\n config,\n }),\n );\n } else {\n for (const timetable of timetables) {\n timetablePages.push(\n createTimetablePage({\n timetablePageId: timetable.timetable_id,\n timetables: [timetable],\n config,\n }),\n );\n }\n }\n }\n\n return timetablePages;\n};\n\n/*\n * Generate all trips based on a start trip and an array of frequencies.\n */\nconst generateTripsByFrequencies = (\n trip: FormattedTrip,\n frequencies: Frequency[],\n config: Config,\n) => {\n const formattedFrequencies = frequencies.map((frequency) =>\n formatFrequency(frequency, config),\n );\n const resetTrip = resetStoptimesToMidnight(trip);\n const trips = [];\n\n for (const frequency of formattedFrequencies) {\n const startSeconds = secondsAfterMidnight(frequency.start_time);\n const endSeconds = secondsAfterMidnight(frequency.end_time);\n\n for (\n let offset = startSeconds;\n offset < endSeconds;\n offset += frequency.headway_secs\n ) {\n const newTrip = cloneDeep(resetTrip);\n trips.push({\n ...newTrip,\n trip_id: `${resetTrip.trip_id}_freq_${trips.length}`,\n stoptimes: updateStoptimesByOffset(newTrip, offset),\n });\n }\n }\n\n return trips;\n};\n\n/*\n * Check if any stoptimes have different arrival and departure times and\n * if they do, duplicate the stop id unless it is the first or last stop.\n */\nconst duplicateStopsForDifferentArrivalDeparture = (\n stopIds: string[],\n timetable: Timetable,\n config: Config,\n) => {\n if (\n config.showArrivalOnDifference === null ||\n config.showArrivalOnDifference === undefined\n ) {\n return stopIds;\n }\n\n for (const trip of timetable.orderedTrips) {\n for (const stoptime of trip.stoptimes) {\n const timepointDifference = fromGTFSTime(stoptime.departure_time).diff(\n fromGTFSTime(stoptime.arrival_time),\n 'minutes',\n );\n\n if (timepointDifference < config.showArrivalOnDifference) {\n continue;\n }\n\n const index = stopIds.indexOf(stoptime.stop_id);\n if (index === 0 || index === stopIds.length - 1) {\n continue;\n }\n\n if (\n stoptime.stop_id === stopIds[index + 1] ||\n stoptime.stop_id === stopIds[index - 1]\n ) {\n continue;\n }\n\n stopIds.splice(index, 0, stoptime.stop_id);\n }\n }\n\n return stopIds;\n};\n\n/*\n * Get a sorted array of stop_ids for a specific timetable.\n */\nconst getStopOrder = (timetable: Timetable, config: Config) => {\n // First, check if `timetable_stop_order.txt` for route exists\n const timetableStopOrders = getTimetableStopOrders(\n {\n timetable_id: timetable.timetable_id,\n },\n ['stop_id'],\n [['stop_sequence', 'ASC']],\n );\n\n if (timetableStopOrders.length > 0) {\n return timetableStopOrders.map(\n (timetableStopOrder) => timetableStopOrder.stop_id,\n );\n }\n\n // Next, try using a directed graph to determine stop order.\n try {\n const stopGraph = [];\n\n // If a stop is marked as a timepoint in any trips, treat it as a timepoint in all trips for sorting purposes.\n const timepointStopIds = new Set(\n timetable.orderedTrips.flatMap((trip) =>\n trip.stoptimes\n .filter((stoptime) => isTimepoint(stoptime))\n .map((stoptime) => stoptime.stop_id),\n ),\n );\n\n for (const trip of timetable.orderedTrips) {\n const sortedStopIds = trip.stoptimes\n .filter((stoptime) => {\n // If `showOnlyTimepoint` is true, then filter out all non-timepoints.\n if (config.showOnlyTimepoint === true) {\n return timepointStopIds.has(stoptime.stop_id);\n }\n return true;\n })\n .map((stoptime) => stoptime.stop_id);\n\n for (const [index, stopId] of sortedStopIds.entries()) {\n if (index === sortedStopIds.length - 1) {\n continue;\n }\n\n stopGraph.push([stopId, sortedStopIds[index + 1]]);\n }\n }\n\n if (stopGraph.length === 0 && config.showOnlyTimepoint === true) {\n timetable.warnings.push(\n `Timetable ${timetable.timetable_id}'s trips have stoptimes with timepoints but \\`showOnlyTimepoint\\` is true. Try setting \\`showOnlyTimepoint\\` to false.`,\n );\n }\n\n const stopIds = toposort(stopGraph);\n\n return duplicateStopsForDifferentArrivalDeparture(\n stopIds,\n timetable,\n config,\n );\n } catch {\n // Fall back to using the stop order from the trip with the most stoptimes.\n // Note that this may miss some stops if the trip with the most stoptimes\n // does not contain all stops.\n const longestTripStoptimes = getLongestTripStoptimes(\n timetable.orderedTrips,\n config,\n );\n const stopIds = longestTripStoptimes.map(\n (stoptime) => stoptime.stop_id,\n ) as string[];\n\n const missingStopIds = difference(\n new Set(\n timetable.orderedTrips.flatMap((trip: Trip) =>\n trip.stoptimes.map((stoptime: StopTime) => stoptime.stop_id),\n ),\n ),\n new Set(stopIds),\n ) as string[];\n\n if (missingStopIds.length > 0) {\n timetable.warnings.push(\n `Timetable ${timetable.timetable_id} stops are unable to be topologically sorted and has no \\`timetable_stop_order.txt\\`. Falling back to using the using the stop order from trip with most stoptimes, but this does not include stop_ids ${formatListForDisplay(missingStopIds)}. Try manually specifying stops with \\`timetable_stop_order.txt\\`. Read more at https://gtfstohtml.com/docs/timetable-stop-order`,\n );\n }\n\n return duplicateStopsForDifferentArrivalDeparture(\n stopIds,\n timetable,\n config,\n );\n }\n};\n\n/*\n * Get an array of stops for a specific timetable.\n */\nconst getStopsForTimetable = (timetable: Timetable, config: Config) => {\n if (timetable.orderedTrips.length === 0) {\n return [];\n }\n\n const orderedStopIds = getStopOrder(timetable, config);\n const orderedStops = orderedStopIds.map((stopId, index) => {\n const stops = getStops({\n stop_id: stopId,\n });\n\n if (stops.length === 0) {\n throw new Error(\n `No stop found found for stop_id=${stopId} in timetable_id=${timetable.timetable_id}`,\n );\n }\n\n const stop = {\n ...stops[0],\n trips: [],\n };\n\n if (\n index < orderedStopIds.length - 1 &&\n stopId === orderedStopIds[index + 1]\n ) {\n stop.type = 'arrival';\n } else if (index > 0 && stopId === orderedStopIds[index - 1]) {\n stop.type = 'departure';\n }\n\n return stop;\n });\n\n // If `showStopCity` is true, look up stop attributes.\n if (config.showStopCity) {\n const stopAttributes = getStopAttributes({\n stop_id: orderedStopIds,\n });\n\n for (const stopAttribute of stopAttributes) {\n const stop = orderedStops.find(\n (stop) => stop.stop_id === stopAttribute.stop_id,\n );\n\n if (stop) {\n stop.stop_city = stopAttribute.stop_city;\n }\n }\n }\n\n return orderedStops;\n};\n\nconst getCalendarsFromConfig = (config: Config) => {\n const db = openDb();\n let whereClause = '';\n const whereClauses = [];\n\n if (config.endDate) {\n // Validate config.endDate is a valid date\n if (!moment(config.endDate).isValid()) {\n throw new Error(`Invalid endDate=${config.endDate} in config.json`);\n }\n\n whereClauses.push(\n `start_date <= ${sqlString.escape(moment(config.endDate).format('YYYYMMDD'))}`,\n );\n }\n\n if (config.startDate) {\n // Validate config.startDate is a valid date\n if (!moment(config.startDate).isValid()) {\n throw new Error(`Invalid startDate=${config.startDate} in config.json`);\n }\n\n whereClauses.push(\n `end_date >= ${sqlString.escape(moment(config.startDate).format('YYYYMMDD'))}`,\n );\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n const calendars: Calendar[] = db\n .prepare(`SELECT * FROM calendar ${whereClause}`)\n .all();\n\n // Find all calendar dates with service_ids not present in `calendar.txt`.\n const serviceIds = calendars.map((calendar) => calendar.service_id);\n const calendarDates = db\n .prepare(\n `SELECT * FROM calendar_dates WHERE exception_type = 1 AND service_id NOT IN (${serviceIds\n .map((serviceId) => `'${serviceId}'`)\n .join(', ')})`,\n )\n .all();\n\n return {\n calendars,\n calendarDates,\n };\n};\n\n/*\n * Get all calendars from a specific timetable.\n */\nconst getCalendarsFromTimetable = (timetable: Timetable) => {\n const db = openDb();\n let whereClause = '';\n const whereClauses = [];\n\n if (timetable.end_date) {\n // Validate timetable.end_date is a valid date\n if (!moment(timetable.end_date, 'YYYYMMDD', true).isValid()) {\n throw new Error(\n `Invalid end_date=${timetable.end_date} for timetable_id=${timetable.timetable_id}`,\n );\n }\n\n whereClauses.push(`start_date <= ${sqlString.escape(timetable.end_date)}`);\n }\n\n if (timetable.start_date) {\n // Validate timetable.start_date is a valid date\n if (!moment(timetable.start_date, 'YYYYMMDD', true).isValid()) {\n throw new Error(\n `Invalid start_date=${timetable.start_date} for timetable_id=${timetable.timetable_id}`,\n );\n }\n\n whereClauses.push(`end_date >= ${sqlString.escape(timetable.start_date)}`);\n }\n\n const days = getDaysFromCalendars([timetable]);\n // Create an 'OR' query array of days based on calendars.\n const dayQueries = reduce(\n days,\n (memo: string[], value: number, key: string) => {\n if (value === 1) {\n memo.push(`${key} = 1`);\n }\n\n return memo;\n },\n [],\n );\n\n if (dayQueries.length > 0) {\n whereClauses.push(`(${dayQueries.join(' OR ')})`);\n }\n\n if (whereClauses.length > 0) {\n whereClause = `WHERE ${whereClauses.join(' AND ')}`;\n }\n\n return db.prepare(`SELECT * FROM calendar ${whereClause}`).all();\n};\n\n/*\n * Get all calendar dates for an agency between two dates.\n */\nconst getCalendarDatesForDateRange = (\n startDate?: number | null,\n endDate?: number | null,\n) => {\n const db = openDb();\n const whereClauses = [];\n\n if (endDate) {\n whereClauses.push(`date <= ${sqlString.escape(endDate)}`);\n }\n\n if (startDate) {\n whereClauses.push(`date >= ${sqlString.escape(startDate)}`);\n }\n\n const calendarDates: CalendarDate[] = db\n .prepare(\n `SELECT service_id, date, exception_type FROM calendar_dates WHERE ${whereClauses.join(\n ' AND ',\n )}`,\n )\n .all();\n return calendarDates;\n};\n\n/*\n * For a specific stop_id, returns an array all stop_ids within a parent station\n * and the stop_id of parent station itself. If no parent station, it returns the\n * stop_id.\n */\nconst getAllStationStopIds = (stopId: string) => {\n const stops = getStops({\n stop_id: stopId,\n });\n\n if (stops.length === 0) {\n throw new Error(`No stop found for stop_id=${stopId}`);\n }\n\n const stop = stops[0];\n\n if (isNullOrEmpty(stop.parent_station)) {\n return [stopId];\n }\n\n const stopsInParentStation = getStops(\n {\n parent_station: stop.parent_station,\n },\n ['stop_id'],\n );\n\n return [\n stop.parent_station,\n ...stopsInParentStation.map((stop) => stop.stop_id),\n ];\n};\n\n/*\n * Get trips with the same `block_id`.\n */\nconst getTripsWithSameBlock = (trip: FormattedTrip, timetable: Timetable) => {\n const trips = getTrips(\n {\n block_id: trip.block_id,\n service_id: timetable.service_ids,\n },\n ['trip_id', 'route_id'],\n );\n\n for (const blockTrip of trips) {\n const stopTimes = getStoptimes(\n {\n trip_id: blockTrip.trip_id,\n },\n [],\n [['stop_sequence', 'ASC']],\n );\n\n if (stopTimes.length === 0) {\n throw new Error(\n `No stoptimes found found for trip_id=${blockTrip.trip_id}`,\n );\n }\n\n blockTrip.firstStoptime = first(stopTimes);\n blockTrip.lastStoptime = last(stopTimes);\n }\n\n return sortBy(trips, (trip) => trip.firstStoptime.departure_timestamp);\n};\n\n/*\n * Get next trip and previous trip with the same `block_id` if it arrives or\n * departs from the same stop and is a different route.\n */\nconst addTripContinuation = (trip: FormattedTrip, timetable: Timetable) => {\n if (!trip.block_id || trip.stoptimes.length === 0) {\n return;\n }\n\n const maxContinuesAsWaitingTimeSeconds = 60 * 60;\n\n const firstStoptime = first(trip.stoptimes);\n const firstStopIds = getAllStationStopIds(firstStoptime.stop_id);\n const lastStoptime = last(trip.stoptimes);\n const lastStopIds = getAllStationStopIds(lastStoptime.stop_id);\n const blockTrips = getTripsWithSameBlock(trip, timetable);\n\n // \"Continues From\" trips must be the previous trip chronologically.\n const previousTrip = findLast(\n blockTrips,\n (blockTrip) =>\n blockTrip.lastStoptime.arrival_timestamp <=\n firstStoptime.departure_timestamp,\n );\n\n /*\n * \"Continues From\" trips\n * * must be a different route_id\n * * must not be more than 60 minutes before\n * * must have their last stop_id be the same as the next trip's first stop_id\n */\n if (\n previousTrip &&\n previousTrip.route_id !== trip.route_id &&\n previousTrip.lastStoptime.arrival_timestamp >=\n firstStoptime.departure_timestamp - maxContinuesAsWaitingTimeSeconds &&\n firstStopIds.includes(previousTrip.lastStoptime.stop_id)\n ) {\n const routes = getRoutes({\n route_id: previousTrip.route_id,\n });\n\n previousTrip.route = routes[0];\n\n trip.continues_from_route = previousTrip;\n }\n\n // \"Continues As\" trips must be the next trip chronologically.\n const nextTrip = find(\n blockTrips,\n (blockTrip) =>\n blockTrip.firstStoptime.departure_timestamp >=\n lastStoptime.arrival_timestamp,\n );\n\n // \"Continues As\" trips must be a different route_id.\n /*\n * \"Continues As\" trips\n * * must be a different route_id\n * * must not be more than 60 minutes later\n * * must have their first stop_id be the same as the previous trip's last stop_id\n */\n if (\n nextTrip &&\n nextTrip.route_id !== trip.route_id &&\n nextTrip.firstStoptime.departure_timestamp <=\n lastStoptime.arrival_timestamp + maxContinuesAsWaitingTimeSeconds &&\n lastStopIds.includes(nextTrip.firstStoptime.stop_id)\n ) {\n const routes = getRoutes({\n route_id: nextTrip.route_id,\n });\n\n nextTrip.route = routes[0];\n trip.continues_as_route = nextTrip;\n }\n};\n\n/*\n * Apply time range filters to trips and remove trips with less than two stoptimes for stops used in this timetable.\n * Stops can be excluded by using `timetable_stop_order.txt`. Additionally, remove trip stoptimes for unused stops.\n */\nconst filterTrips = (timetable: FormattedTimetable, config: Config) => {\n let filteredTrips = timetable.orderedTrips;\n\n // Combine adjacent stoptimes with the same `stop_id`\n for (const trip of filteredTrips) {\n const combinedStoptimes = [];\n\n for (const [index, stoptime] of trip.stoptimes.entries()) {\n if (\n index === 0 ||\n stoptime.stop_id !== trip.stoptimes[index - 1].stop_id\n ) {\n combinedStoptimes.push(stoptime);\n } else {\n // The `stoptime` is the same as previous, use `arrival_time` from previous and `departure_time` from this stoptime\n combinedStoptimes[combinedStoptimes.length - 1].departure_time =\n stoptime.departure_time;\n }\n }\n\n trip.stoptimes = combinedStoptimes;\n }\n\n // Remove stoptimes for stops not used in timetable\n const timetableStopIds = new Set(\n timetable.stops.map((stop: Stop) => stop.stop_id),\n );\n for (const trip of filteredTrips) {\n trip.stoptimes = trip.stoptimes.filter((stoptime: StopTime) =>\n timetableStopIds.has(stoptime.stop_id),\n );\n }\n\n // Exclude trips with less than two stops\n filteredTrips = filteredTrips.filter(\n (trip: Trip) => trip.stoptimes.length > 1,\n );\n\n if (config.showDuplicateTrips === false) {\n filteredTrips = deduplicateTrips(filteredTrips);\n }\n\n return filteredTrips;\n};\n\n/*\n * Get all trips from a timetable.\n */\n\n/* eslint-disable complexity */\nconst getTripsForTimetable = (\n timetable: FormattedTimetable,\n calendars: Calendar[],\n config: Config,\n) => {\n const tripQuery: {\n route_id: string[];\n service_id?: string[];\n direction_id?: number;\n } = {\n route_id: timetable.route_ids,\n service_id: timetable.service_ids,\n };\n\n if (!isNullOrEmpty(timetable.direction_id)) {\n tripQuery.direction_id = timetable.direction_id;\n }\n\n const trips = getTrips(tripQuery);\n\n if (trips.length === 0) {\n timetable.warnings.push(\n `No trips found for route_id=${timetable.route_ids.join(\n '_',\n )}, direction_id=${timetable.direction_id}, service_ids=${JSON.stringify(\n timetable.service_ids,\n )}, timetable_id=${timetable.timetable_id}`,\n );\n }\n\n const frequencies = getFrequencies({\n trip_id: trips.map((trip) => trip.trip_id),\n });\n\n // Updated timetable.serviceIds with only the service IDs actually used in one or more trip.\n timetable.service_ids = uniq(trips.map((trip) => trip.service_id));\n\n const formattedTrips = [];\n\n for (const trip of trips) {\n const formattedTrip = formatTrip(trip, timetable, calendars, config);\n formattedTrip.stoptimes = getStoptimes(\n {\n trip_id: formattedTrip.trip_id,\n },\n [],\n [['stop_sequence', 'ASC']],\n );\n\n if (formattedTrip.stoptimes.length === 0) {\n timetable.warnings.push(\n `No stoptimes found for trip_id=${\n formattedTrip.trip_id\n }, route_id=${timetable.route_ids.join('_')}, timetable_id=${\n timetable.timetable_id\n }`,\n );\n }\n\n // Exclude trips before timetable `start_timestamp`\n if (\n timetable.start_timestamp !== '' &&\n timetable.start_timestamp !== null &&\n timetable.start_timestamp !== undefined &&\n trip.stoptimes[0].arrival_timestamp < timetable.start_timestamp\n ) {\n return;\n }\n\n // Exclude trips after timetable `end_timestamp`\n if (\n timetable.end_timestamp !== '' &&\n timetable.end_timestamp !== null &&\n timetable.end_timestamp !== undefined &&\n trip.stoptimes[0].arrival_timestamp >= timetable.end_timestamp\n ) {\n return;\n }\n\n if (timetable.show_trip_continuation) {\n addTripContinuation(formattedTrip, timetable);\n\n if (formattedTrip.continues_as_route) {\n timetable.has_continues_as_route = true;\n }\n\n if (formattedTrip.continues_from_route) {\n timetable.has_continues_from_route = true;\n }\n }\n\n const tripFrequencies = frequencies.filter(\n (frequency) => frequency.trip_id === trip.trip_id,\n );\n\n if (tripFrequencies.length === 0) {\n formattedTrips.push(formattedTrip);\n } else {\n const frequencyTrips = generateTripsByFrequencies(\n formattedTrip,\n frequencies,\n config,\n );\n formattedTrips.push(...frequencyTrips);\n timetable.frequencies = frequencies;\n timetable.frequencyExactTimes = some(frequencies, {\n exact_times: 1,\n });\n }\n }\n\n if (config.useParentStation) {\n const stopIds = [];\n\n for (const trip of formattedTrips) {\n for (const stoptime of trip.stoptimes) {\n stopIds.push(stoptime.stop_id);\n }\n }\n\n const stops = getStops(\n {\n stop_id: uniq(stopIds),\n },\n ['parent_station', 'stop_id'],\n );\n\n for (const trip of formattedTrips) {\n for (const stoptime of trip.stoptimes) {\n const stop = stops.find((stop) => stop.stop_id === stoptime.stop_id);\n\n if (stop?.parent_station) {\n stoptime.stop_id = stop.parent_station;\n }\n }\n }\n }\n\n return sortTrips(formattedTrips, config);\n};\n/* eslint-enable complexity */\n\n/*\n * Format timetables for display.\n */\nconst formatTimetables = (timetables: Timetable[], config: Config) => {\n const formattedTimetables = timetables.map((timetable) => {\n timetable.warnings = [];\n const dayList = formatDays(timetable, config);\n const calendars = getCalendarsFromTimetable(timetable);\n const serviceIds = new Set();\n\n // Add all service IDs from calendars\n for (const calendar of calendars) {\n serviceIds.add(calendar.service_id);\n }\n\n if (timetable.include_exceptions === 1) {\n const calendarDates = getCalendarDatesForDateRange(\n timetable.start_date,\n timetable.end_date,\n );\n\n const calendarDateGroups = groupBy(calendarDates, 'service_id');\n\n for (const [serviceId, calendarDateGroup] of Object.entries(\n calendarDateGroups,\n )) {\n // Check if there is a corresponding calendar.txt entry for this service_id\n const calendar = calendars.find(\n (c: Calendar) => c.service_id === serviceId,\n );\n\n // Add service_id if any dates are added\n if (\n calendarDateGroup.some(\n (calendarDate) => calendarDate.exception_type === 1,\n )\n ) {\n serviceIds.add(serviceId);\n }\n\n const calendarDateGroupExceptionType2 = calendarDateGroup.filter(\n (calendarDate) => calendarDate.exception_type === 2,\n );\n\n // Check if ALL dates are excluded\n if (\n timetable.start_date &&\n timetable.end_date &&\n calendar &&\n calendarDateGroupExceptionType2.length > 0\n ) {\n const datesDuringDateRange = calendarToDateList(\n calendar,\n timetable.start_date,\n timetable.end_date,\n );\n\n // If no dates are are within the date range, remove service_id\n if (datesDuringDateRange.length === 0) {\n serviceIds.delete(serviceId);\n }\n\n // Check if every date is excluded and remove service_id if so\n const everyDateIsExcluded = datesDuringDateRange.every(\n (dateDuringDateRange) =>\n calendarDateGroupExceptionType2.some(\n (calendarDate) => calendarDate.date === dateDuringDateRange,\n ),\n );\n\n if (everyDateIsExcluded) {\n serviceIds.delete(serviceId);\n }\n }\n }\n }\n\n Object.assign(timetable, {\n noServiceSymbolUsed: false,\n requestDropoffSymbolUsed: false,\n noDropoffSymbolUsed: false,\n requestPickupSymbolUsed: false,\n noPickupSymbolUsed: false,\n interpolatedStopSymbolUsed: false,\n showStopCity: config.showStopCity,\n showStopDescription: config.showStopDescription,\n noServiceSymbol: config.noServiceSymbol,\n requestDropoffSymbol: config.requestDropoffSymbol,\n noDropoffSymbol: config.noDropoffSymbol,\n requestPickupSymbol: config.requestPickupSymbol,\n noPickupSymbol: config.noPickupSymbol,\n interpolatedStopSymbol: config.interpolatedStopSymbol,\n orientation: timetable.orientation || config.defaultOrientation,\n service_ids: Array.from(serviceIds),\n dayList,\n dayListLong: formatDaysLong(dayList, config),\n });\n\n timetable.orderedTrips = getTripsForTimetable(timetable, calendars, config);\n timetable.stops = getStopsForTimetable(timetable, config);\n timetable.calendarDates = getCalendarDatesForTimetable(timetable, config);\n timetable.timetable_label = formatTimetableLabel(timetable);\n timetable.notes = getTimetableNotesForTimetable(timetable, config);\n\n if (config.showMap) {\n timetable.geojson = getTimetableGeoJSON(timetable, config);\n }\n\n timetable.trip_ids = uniq(\n timetable.orderedTrips.map((trip: Trip) => trip.trip_id),\n );\n\n // Filter trips after all timetable properties are assigned\n timetable.orderedTrips = filterTrips(timetable, config);\n\n // Format stops after all timetable properties are assigned\n timetable.stops = formatStops(timetable, config);\n\n return timetable;\n });\n\n if (config.allowEmptyTimetables) {\n return formattedTimetables;\n }\n\n return formattedTimetables.filter(\n (timetable) => timetable.orderedTrips.length > 0,\n );\n};\n\n/*\n * Get all timetable pages for an agency.\n */\nexport function getTimetablePagesForAgency(\n config: Config,\n): FormattedTimetablePage[] {\n const timetables = mergeTimetablesWithSameId(getTimetables());\n const routes = getRoutes();\n const formattedTimetables = timetables.map((timetable) => {\n return {\n ...timetable,\n routes: routes.filter((route) =>\n timetable.route_ids.includes(route.route_id),\n ),\n } as FormattedTimetable;\n });\n\n // If no timetables, build each route and direction into a timetable.\n if (timetables.length === 0) {\n return convertRoutesToTimetablePages(config);\n }\n\n const timetablePages = getTimetablePages(\n {},\n [],\n [['timetable_page_id', 'ASC']],\n );\n\n // Check if there are any timetable pages defined in `timetable_pages.txt`.\n if (timetablePages.length === 0) {\n // If no timetablepages, use timetables\n return formattedTimetables.map((timetable) =>\n createTimetablePage({\n timetablePageId: timetable.timetable_id,\n timetables: [timetable],\n config,\n }),\n );\n }\n\n // Otherwise, use timetable pages defined in `timetable_pages.txt`.\n return timetablePages.map((timetablePage) => {\n return {\n ...timetablePage,\n timetables: sortBy(\n formattedTimetables.filter(\n (timetable) =>\n timetable.timetable_page_id === timetablePage.timetable_page_id,\n ),\n 'timetable_sequence',\n ),\n } as FormattedTimetablePage;\n });\n}\n\nconst getDataForTimetablePageById = (timetablePageId: string) => {\n let calendarCode;\n let calendars;\n let calendarDates;\n let serviceId;\n let directionId: number | string | null = '';\n const parts = timetablePageId?.split('|') ?? [];\n if (parts.length > 2) {\n directionId = Number.parseInt(parts.pop(), 10);\n calendarCode = parts.pop();\n } else if (parts.length > 1) {\n directionId = null;\n calendarCode = parts.pop();\n }\n\n const routeId = parts.join('|');\n\n const routes = getRoutes({\n route_id: routeId,\n });\n\n const trips = getTrips(\n {\n route_id: routeId,\n direction_id: directionId,\n },\n ['trip_headsign', 'direction_id'],\n );\n const uniqueTripDirections = uniqBy(trips, (trip) => trip.direction_id);\n\n if (uniqueTripDirections.length === 0) {\n throw new Error(\n `No trips found for timetable_page_id=${timetablePageId} route_id=${routeId} direction_id=${directionId}`,\n );\n }\n\n if (/^[01]*$/.test(calendarCode ?? '')) {\n calendars = getCalendars({\n ...calendarCodeToCalendar(calendarCode),\n });\n } else {\n serviceId = calendarCode;\n calendarDates = getCalendarDates({\n exception_type: 1,\n service_id: serviceId,\n });\n }\n\n return {\n calendars,\n calendarDates,\n route: routes[0],\n directionId: uniqueTripDirections[0].direction_id,\n tripHeadsign: uniqueTripDirections[0].trip_headsign,\n };\n};\n\n/*\n * Get a timetable_page by id.\n */\nconst getTimetablePageById = (timetablePageId: string, config: Config) => {\n // Check if there are any timetable pages defined in `timetable_pages.txt`.\n const timetablePages = getTimetablePages({\n timetable_page_id: timetablePageId,\n });\n\n const timetables = mergeTimetablesWithSameId(\n getTimetables(),\n ) as FormattedTimetable[];\n\n if (timetablePages.length > 1) {\n throw new Error(\n `Multiple timetable_pages found for timetable_page_id=${timetablePageId}`,\n );\n }\n\n if (timetablePages.length === 1) {\n // Use timetablePage defined in `timetable_pages.txt`.\n const timetablePage = timetablePages[0];\n timetablePage.timetables = sortBy(\n timetables.filter(\n (timetable) => timetable.timetable_page_id === timetablePageId,\n ),\n 'timetable_sequence',\n );\n\n // Add routes for each timetable\n for (const timetable of timetablePage.timetables) {\n timetable.routes = getRoutes({\n route_id: timetable.route_ids,\n });\n }\n\n return timetablePage;\n }\n\n if (timetables.length > 0) {\n // If no timetable_page, use timetable defined in `timetables.txt`.\n const timetablePageTimetables = timetables.filter(\n (timetable) => timetable.timetable_id === timetablePageId,\n );\n\n if (timetablePageTimetables.length === 0) {\n throw new Error(\n `No timetable found for timetable_page_id=${timetablePageId}`,\n );\n }\n\n return createTimetablePage({\n timetablePageId: timetablePageId,\n timetables: [timetablePageTimetables[0]],\n config,\n });\n }\n\n // If no `timetables.txt` in GTFS and timetable_page_id starts with \"route_\", build the route into a timetable page using all calendars and directions.\n if (timetablePageId.startsWith('route_')) {\n const routes = getRoutes({\n route_short_name: timetablePageId.split('_')[1],\n });\n\n if (routes.length === 0) {\n throw new Error(\n `No route found for timetable_page_id=${timetablePageId}`,\n );\n }\n\n const { calendars, calendarDates } = getCalendarsFromConfig(config);\n\n const trips = getTrips(\n {\n route_id: routes[0].route_id,\n },\n ['trip_headsign', 'direction_id', 'trip_id', 'service_id'],\n );\n const uniqueTripDirections = orderBy(\n uniqBy(trips, (trip) => trip.direction_id),\n 'direction_id',\n );\n const sortedCalendars = orderBy(calendars, calendarToCalendarCode, 'desc');\n const calendarGroups = groupBy(sortedCalendars, calendarToCalendarCode);\n const calendarDateGroups = groupBy(calendarDates, 'service_id');\n\n const timetables: FormattedTimetable[] = [];\n\n for (const uniqueTripDirection of uniqueTripDirections) {\n for (const calendars of Object.values(calendarGroups)) {\n const tripsForCalendars = trips.filter((trip) =>\n some(calendars, { service_id: trip.service_id }),\n );\n if (tripsForCalendars.length > 0) {\n timetables.push(\n createTimetable({\n route: routes[0],\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendars,\n }),\n );\n }\n }\n\n for (const calendarDates of Object.values(calendarDateGroups)) {\n const tripsForCalendarDates = trips.filter((trip) =>\n some(calendarDates, { service_id: trip.service_id }),\n );\n if (tripsForCalendarDates.length > 0) {\n timetables.push(\n createTimetable({\n route: routes[0],\n directionId: uniqueTripDirection.direction_id,\n tripHeadsign: uniqueTripDirection.trip_headsign,\n calendarDates,\n }),\n );\n }\n }\n }\n\n return createTimetablePage({\n timetablePageId,\n timetables,\n config,\n });\n }\n\n // If no `timetables.txt` in GTFS, try to parse the timetable_page_id and build the route and direction into a timetable.\n const { calendars, calendarDates, route, directionId, tripHeadsign } =\n getDataForTimetablePageById(timetablePageId);\n\n const timetable = createTimetable({\n route,\n directionId,\n tripHeadsign,\n calendars,\n calendarDates,\n });\n\n return createTimetablePage({\n timetablePageId,\n timetables: [timetable],\n config,\n });\n};\n\n/*\n * Initialize configuration with defaults.\n */\nexport function setDefaultConfig(initialConfig: Config) {\n const defaults = {\n allowEmptyTimetables: false,\n beautify: false,\n coordinatePrecision: 5,\n dateFormat: 'MMM D, YYYY',\n daysShortStrings: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],\n daysStrings: [\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n 'Sunday',\n ],\n defaultOrientation: 'vertical',\n interpolatedStopSymbol: '•',\n interpolatedStopText: 'Estimated time of arrival',\n groupTimetablesIntoPages: true,\n gtfsToHtmlVersion: version,\n linkStopUrls: false,\n mapStyleUrl: 'https://tiles.openfreemap.org/styles/positron',\n menuType: 'jump',\n noDropoffSymbol: '‡',\n noDropoffText: 'No drop off available',\n noHead: false,\n noPickupSymbol: '**',\n noPickupText: 'No pickup available',\n noRegularServiceDaysText: 'No regular service days',\n noServiceSymbol: '-',\n noServiceText: 'No service at this stop',\n outputFormat: 'html',\n overwriteExistingFiles: true,\n requestDropoffSymbol: '†',\n requestDropoffText: 'Must request drop off',\n requestPickupSymbol: '***',\n requestPickupText: 'Request stop - call for pickup',\n serviceNotProvidedOnText: 'Service not provided on',\n serviceProvidedOnText: 'Service provided on',\n showArrivalOnDifference: 0.2,\n showCalendarExceptions: true,\n showDuplicateTrips: false,\n showMap: false,\n showOnlyTimepoint: false,\n showRouteTitle: true,\n showStopCity: false,\n showStopDescription: false,\n showStoptimesForRequestStops: true,\n skipImport: false,\n sortingAlgorithm: 'common',\n timeFormat: 'h:mma',\n useParentStation: true,\n verbose: true,\n zipOutput: false,\n };\n\n const config = Object.assign(defaults, initialConfig);\n\n if (config.outputFormat === 'pdf') {\n // Force `noHead` to false to false if pdfs are asked for\n config.noHead = false;\n config.menuType = 'none';\n }\n\n // Add values to config if gtfs realtime URLs are present\n config.hasGtfsRealtimeVehiclePositions = config.agencies.some(\n (agency) => agency.realtimeVehiclePositions?.url,\n );\n\n config.hasGtfsRealtimeTripUpdates = config.agencies.some(\n (agency) => agency.realtimeTripUpdates?.url,\n );\n\n config.hasGtfsRealtimeAlerts = config.agencies.some(\n (agency) => agency.realtimeAlerts?.url,\n );\n\n return config;\n}\n\n/*\n * Get a timetable page by id.\n */\nexport function getFormattedTimetablePage(\n timetablePageId: string,\n config: Config,\n) {\n const timetablePage = getTimetablePageById(\n timetablePageId,\n config,\n ) as FormattedTimetablePage;\n\n const consolidatedTimetables = formatTimetables(\n timetablePage.timetables,\n config,\n );\n\n // Get `direction_name` for each timetable.\n for (const timetable of consolidatedTimetables) {\n if (isNullOrEmpty(timetable.direction_name)) {\n timetable.direction_name = getDirectionHeadsignFromTimetable(timetable);\n }\n\n if (!timetable.routes) {\n timetable.routes = getRoutes({\n route_id: timetable.route_ids,\n });\n }\n }\n\n const uniqueRoutes = uniqBy(\n flatMap(consolidatedTimetables, (timetable) => timetable.routes),\n 'route_id',\n );\n\n const formattedTimetablePage = {\n ...timetablePage,\n consolidatedTimetables,\n dayList: formatDays(getDaysFromCalendars(consolidatedTimetables), config),\n dayLists: uniq(\n consolidatedTimetables.map((timetable) => timetable.dayList),\n ),\n route_ids: uniqueRoutes.map((route) => route.route_id),\n agency_ids: uniq(compact(uniqueRoutes.map((route) => route.agency_id))),\n filename:\n timetablePage.filename ?? `${timetablePage.timetable_page_id}.html`,\n timetable_page_label:\n timetablePage.timetable_page_label ??\n formatListForDisplay(uniqueRoutes.map((route) => formatRouteName(route))),\n };\n\n return formattedTimetablePage;\n}\n\n/*\n * Generate stats about timetable page.\n */\nexport const generateStats = (timetablePage: FormattedTimetablePage) => {\n const routeIds: { [key: string]: boolean } = {};\n const serviceIds: { [key: string]: boolean } = {};\n const stats = {\n stops: 0,\n trips: 0,\n routes: 0,\n calendars: 0,\n };\n\n for (const timetable of timetablePage.consolidatedTimetables) {\n stats.stops += timetable.stops.length;\n stats.trips += timetable.orderedTrips.length;\n for (const serviceId of timetable.service_ids) {\n serviceIds[serviceId] = true;\n }\n\n for (const routeId of timetable.route_ids) {\n routeIds[routeId] = true;\n }\n }\n\n stats.routes = size(routeIds);\n stats.calendars = size(serviceIds);\n\n return stats;\n};\n\n/*\n * Generate the HTML timetable for a timetable page.\n */\nexport function generateTimetableHTML(\n timetablePage: FormattedTimetablePage,\n config: Config,\n) {\n const agencies = getAgencies() as { agency_name: string }[];\n const templateVars = {\n timetablePage,\n config,\n title: `${timetablePage.timetable_page_label} | ${formatListForDisplay(agencies.map((agency) => agency.agency_name))}`,\n };\n return renderTemplate('timetablepage', templateVars, config);\n}\n\n/*\n * Generate the CSV timetable for a timetable page.\n */\nexport function generateTimetableCSV(timetable) {\n // Generate horizontal orientation, then transpose if vertical is needed.\n const lines = [];\n\n lines.push([\n '',\n ...timetable.orderedTrips.map((trip) =>\n formatTripNameForCSV(trip, timetable),\n ),\n ]);\n\n if (timetable.has_continues_from_route) {\n lines.push([\n 'Continues from route',\n ...timetable.orderedTrips.map((trip) => formatTripContinuesFrom(trip)),\n ]);\n }\n\n for (const stop of timetable.stops) {\n lines.push([\n formatStopName(stop),\n ...stop.trips.map((stoptime) => stoptime.formatted_time),\n ]);\n }\n\n if (timetable.has_continues_as_route) {\n lines.push([\n 'Continues as route',\n ...timetable.orderedTrips.map((trip) => formatTripContinuesAs(trip)),\n ]);\n }\n\n if (timetable.orientation === 'vertical') {\n return stringify(zip(...lines));\n }\n\n return stringify(lines);\n}\n\n/*\n * Generate the HTML for the agency overview page.\n */\nexport function generateOverviewHTML(\n timetablePages: FormattedTimetablePage[],\n config: Config,\n) {\n const agencies = getAgencies() as { agency_name: string }[];\n if (agencies.length === 0) {\n throw new Error('No agencies found');\n }\n\n const geojson = config.showMap ? getAgencyGeoJSON(config) : undefined;\n\n const templateVars = {\n agency: {\n ...first(agencies),\n geojson,\n }, // Legacy agency object\n agencies,\n geojson,\n config,\n timetablePages,\n title: `${formatListForDisplay(agencies.map((agency) => agency.agency_name))} Timetables`,\n };\n return renderTemplate('overview', templateVars, config);\n}\n","import { getShapesAsGeoJSON, getStopsAsGeoJSON } from 'gtfs';\nimport simplify from '@turf/simplify';\nimport { featureCollection, round } from '@turf/helpers';\nimport { logWarning } from './log-utils.js';\n\n/*\n * Merge any number of geojson objects into one. Only works for `FeatureCollection`.\n */\nconst mergeGeojson = (...geojsons) =>\n featureCollection(geojsons.flatMap((geojson) => geojson.features));\n\n/*\n * Truncate a geojson coordinates to a specific number of decimal places.\n */\nconst truncateGeoJSONDecimals = (geojson, config) => {\n for (const feature of geojson.features) {\n if (feature.geometry.coordinates) {\n if (feature.geometry.type.toLowerCase() === 'point') {\n feature.geometry.coordinates = feature.geometry.coordinates.map(\n (number) => round(number, config.coordinatePrecision),\n );\n } else if (feature.geometry.type.toLowerCase() === 'linestring') {\n feature.geometry.coordinates = feature.geometry.coordinates.map(\n (coordinate) =>\n coordinate.map((number) =>\n round(number, config.coordinatePrecision),\n ),\n );\n } else if (feature.geometry.type.toLowerCase() === 'multilinestring') {\n feature.geometry.coordinates = feature.geometry.coordinates.map(\n (linestring) =>\n linestring.map((coordinate) =>\n coordinate.map((number) =>\n round(number, config.coordinatePrecision),\n ),\n ),\n );\n }\n }\n }\n\n return geojson;\n};\n\n/*\n * Get the geoJSON for a timetable.\n */\nexport function getTimetableGeoJSON(timetable, config) {\n const shapesGeojsons = timetable.route_ids.map((routeId) =>\n getShapesAsGeoJSON({\n route_id: routeId,\n direction_id: timetable.direction_id,\n trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),\n }),\n );\n\n const stopsGeojsons = timetable.route_ids.map((routeId) =>\n getStopsAsGeoJSON({\n route_id: routeId,\n direction_id: timetable.direction_id,\n trip_id: timetable.orderedTrips.map((trip) => trip.trip_id),\n }),\n );\n\n const geojson = mergeGeojson(...shapesGeojsons, ...stopsGeojsons);\n\n let simplifiedGeojson;\n try {\n simplifiedGeojson = simplify(geojson, {\n tolerance: 1 / 10 ** config.coordinatePrecision,\n highQuality: true,\n });\n } catch {\n timetable.warnings.push(\n `Timetable ${timetable.timetable_id} - Unable to simplify geojson`,\n );\n simplifiedGeojson = geojson;\n }\n\n return truncateGeoJSONDecimals(simplifiedGeojson, config);\n}\n\n/*\n * Get the geoJSON for an agency (all routes and stops).\n */\nexport function getAgencyGeoJSON(config) {\n const shapesGeojsons = getShapesAsGeoJSON();\n const stopsGeojsons = getStopsAsGeoJSON();\n\n const geojson = mergeGeojson(shapesGeojsons, stopsGeojsons);\n\n let simplifiedGeojson;\n try {\n simplifiedGeojson = simplify(geojson, {\n tolerance: 1 / 10 ** config.coordinatePrecision,\n highQuality: true,\n });\n } catch {\n logWarning(config)('Unable to simplify geojson');\n simplifiedGeojson = geojson;\n }\n\n return truncateGeoJSONDecimals(simplifiedGeojson, config);\n}\n","import { clearLine, cursorTo } from 'node:readline';\nimport { noop } from 'lodash-es';\nimport * as colors from 'yoctocolors';\nimport { getAgencies, getFeedInfo } from 'gtfs';\nimport Table from 'cli-table';\nimport { Config } from '../types/index.ts';\n\n/*\n * Creates text for a log of output details.\n */\nexport function generateLogText(outputStats, config: Config) {\n const feedInfo = getFeedInfo();\n const agencies = getAgencies();\n const feedVersion =\n feedInfo.length > 0 && feedInfo[0].feed_version\n ? feedInfo[0].feed_version\n : 'Unknown';\n\n const logText = [\n `Agencies: ${agencies.map((agency) => agency.agency_name).join(', ')}`,\n `Feed Version: ${feedVersion}`,\n `GTFS-to-HTML Version: ${config.gtfsToHtmlVersion}`,\n `Date Generated: ${new Date().toISOString()}`,\n `Timetable Page Count: ${outputStats.timetablePages}`,\n `Timetable Count: ${outputStats.timetables}`,\n `Calendar Service ID Count: ${outputStats.calendars}`,\n `Route Count: ${outputStats.routes}`,\n `Trip Count: ${outputStats.trips}`,\n `Stop Count: ${outputStats.stops}`,\n ];\n\n for (const agency of config.agencies) {\n if (agency.url) {\n logText.push(`Source: ${agency.url}`);\n } else if (agency.path) {\n logText.push(`Source: ${agency.path}`);\n }\n }\n\n if (outputStats.warnings.length > 0) {\n logText.push('', 'Warnings:', ...outputStats.warnings);\n }\n\n return logText.join('\\n');\n}\n\n/*\n * Returns a log function based on config settings\n */\nexport function log(config: Config) {\n if (config.verbose === false) {\n return noop;\n }\n\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string, overwrite: boolean) => {\n if (overwrite === true && process.stdout.isTTY) {\n clearLine(process.stdout, 0);\n cursorTo(process.stdout, 0);\n } else {\n process.stdout.write('\\n');\n }\n\n process.stdout.write(text);\n };\n}\n\n/*\n * Returns an warning log function based on config settings\n */\nexport function logWarning(config: Config) {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string) => {\n process.stdout.write(`\\n${formatWarning(text)}\\n`);\n };\n}\n\n/*\n * Returns an error log function based on config settings\n */\nexport function logError(config: Config) {\n if (config.logFunction) {\n return config.logFunction;\n }\n\n return (text: string) => {\n process.stdout.write(`\\n${formatError(text)}\\n`);\n };\n}\n\n/*\n * Format console warning text\n */\nexport function formatWarning(text: string) {\n const warningMessage = `${colors.underline('Warning')}: ${text}`;\n return colors.yellow(warningMessage);\n}\n\n/*\n * Format console error text\n */\nexport function formatError(error: any) {\n const messageText = error instanceof Error ? error.message : error;\n const errorMessage = `${colors.underline('Error')}: ${messageText.replace(\n 'Error: ',\n '',\n )}`;\n return colors.red(errorMessage);\n}\n\n/*\n * Print a table of stats to the console.\n */\nexport function logStats(config: Config) {\n // Hide stats table from custom log functions\n if (config.logFunction) {\n return noop;\n }\n\n return (stats: any) => {\n const table = new Table({\n colWidths: [40, 20],\n head: ['Item', 'Count'],\n });\n\n table.push(\n ['📄 Timetable Pages', stats.timetablePages],\n ['🕑 Timetables', stats.timetables],\n ['📅 Calendar Service IDs', stats.calendars],\n ['🔄 Routes', stats.routes],\n ['🚍 Trips', stats.trips],\n ['🛑 Stops', stats.stops],\n ['⛔️ Warnings', stats.warnings.length],\n );\n\n log(config)(table.toString());\n };\n}\n\n/*\n * Create progress bar text string\n */\nconst generateProgressBarString = (barTotal, barProgress, size = 40) => {\n const line = '-';\n const slider = '=';\n if (!barTotal) {\n throw new Error('Total value is either not provided or invalid');\n }\n\n if (!barProgress && barProgress !== 0) {\n throw new Error('Current value is either not provided or invalid');\n }\n\n if (isNaN(barTotal)) {\n throw new Error('Total value is not an integer');\n }\n\n if (isNaN(barProgress)) {\n throw new Error('Current value is not an integer');\n }\n\n if (isNaN(size)) {\n throw new Error('Size is not an integer');\n }\n\n if (barProgress > barTotal) {\n return slider.repeat(size + 2);\n }\n\n const percentage = barProgress / barTotal;\n const progress = Math.round(size * percentage);\n const emptyProgress = size - progress;\n const progressText = slider.repeat(progress);\n const emptyProgressText = line.repeat(emptyProgress);\n return progressText + emptyProgressText;\n};\n\n/*\n * Print a progress bar to the console.\n */\nexport function progressBar(\n formatString: string,\n barTotal: number,\n config: Config,\n) {\n let barProgress = 0;\n\n if (config.verbose === false) {\n return {\n increment: noop,\n interrupt: noop,\n };\n }\n\n if (barTotal === 0) {\n return null;\n }\n\n const renderProgressString = () =>\n formatString\n .replace('{value}', barProgress)\n .replace('{total}', barTotal)\n .replace('{bar}', generateProgressBarString(barTotal, barProgress));\n\n log(config)(renderProgressString(), true);\n\n return {\n interrupt(text: string) {\n // Log two lines to avoid overwrite by progress bar\n logWarning(config)(text);\n log(config)('');\n },\n increment() {\n barProgress += 1;\n log(config)(renderProgressString(), true);\n },\n };\n}\n","import { every } from 'lodash-es';\n\n/*\n * Discern if a day list should be shown for a specific timetable (if some\n * trips happen on different days).\n */\nexport function timetableHasDifferentDays(timetable) {\n return !every(timetable.orderedTrips, (trip, idx) => {\n if (idx === 0) {\n return true;\n }\n\n return trip.dayList === timetable.orderedTrips[idx - 1].dayList;\n });\n}\n\n/*\n * Discern if a day list should be shown for a specific timetable page's menu (if some\n * timetables are for different days).\n */\nexport function timetablePageHasDifferentDays(timetablePage) {\n return !every(timetablePage.consolidatedTimetables, (timetable, idx) => {\n if (idx === 0) {\n return true;\n }\n\n return (\n timetable.dayListLong ===\n timetablePage.consolidatedTimetables[idx - 1].dayListLong\n );\n });\n}\n\n/*\n * Discern if individual timetable labels should be shown (if some\n * timetables have different labels).\n */\nexport function timetablePageHasDifferentLabels(timetablePage) {\n return !every(timetablePage.consolidatedTimetables, (timetable, idx) => {\n if (idx === 0) {\n return true;\n }\n\n return (\n timetable.timetable_label ===\n timetablePage.consolidatedTimetables[idx - 1].timetable_label\n );\n });\n}\n\n/*\n * Discern if a timetable has any notes or notices to display.\n */\nexport function hasNotesOrNotices(timetable) {\n return (\n timetable.requestPickupSymbolUsed ||\n timetable.noPickupSymbolUsed ||\n timetable.requestDropoffSymbolUsed ||\n timetable.noDropoffSymbolUsed ||\n timetable.noServiceSymbolUsed ||\n timetable.interpolatedStopSymbolUsed ||\n timetable.notes.length > 0\n );\n}\n\n/*\n * Return an array of all timetable notes that relate to the entire timetable or route.\n */\nexport function getNotesForTimetableLabel(notes) {\n return notes.filter((note) => !note.stop_id && !note.trip_id);\n}\n\n/*\n * Return an array of all timetable notes for a specific stop and stop_sequence.\n */\nexport function getNotesForStop(notes, stop) {\n return notes.filter((note) => {\n // Don't show if note applies only to a specific trip.\n if (note.trip_id) {\n return false;\n }\n\n // Don't show if note applies only to a specific stop_sequence that is not found.\n if (\n note.stop_sequence &&\n !stop.trips.some((trip) => trip.stop_sequence === note.stop_sequence)\n ) {\n return false;\n }\n\n return note.stop_id === stop.stop_id;\n });\n}\n\n/*\n * Return an array of all timetable notes for a specific trip.\n */\nexport function getNotesForTrip(notes, trip) {\n return notes.filter((note) => {\n // Don't show if note applies only to a specific stop.\n if (note.stop_id) {\n return false;\n }\n\n return note.trip_id === trip.trip_id;\n });\n}\n\n/*\n * Return an array of all timetable notes for a specific stoptime.\n */\nexport function getNotesForStoptime(notes, stoptime) {\n return notes.filter((note) => {\n // Show notes that apply to all trips at this stop if `show_on_stoptime` is true.\n if (\n !note.trip_id &&\n note.stop_id === stoptime.stop_id &&\n note.show_on_stoptime === 1\n ) {\n return true;\n }\n\n // Show notes that apply to all stops of this trip if `show_on_stoptime` is true.\n if (\n !note.stop_id &&\n note.trip_id === stoptime.trip_id &&\n note.show_on_stoptime === 1\n ) {\n return true;\n }\n\n return (\n note.trip_id === stoptime.trip_id && note.stop_id === stoptime.stop_id\n );\n });\n}\n\n/*\n * Formats a trip name for HTML timetable.\n * Deprecated, use `formatTripName` in formatting_functions.pug instead.\n */\nexport function formatTripName(trip, index, timetable) {\n let tripName;\n if (timetable.routes.length > 1) {\n tripName = trip.route_short_name;\n } else if (timetable.orientation === 'horizontal') {\n // Only add this to horizontal timetables.\n if (trip.trip_short_name) {\n tripName = trip.trip_short_name;\n } else {\n tripName = `Run #${index + 1}`;\n }\n }\n\n if (timetableHasDifferentDays(timetable)) {\n tripName += ` ${trip.dayList}`;\n }\n\n return tripName;\n}\n\n/*\n * Formats a trip name for CSV export.\n */\nexport function formatTripNameForCSV(trip, timetable) {\n let tripName = '';\n if (timetable.routes.length > 1) {\n tripName += `${trip.route_short_name} - `;\n }\n\n if (trip.trip_short_name) {\n tripName += trip.trip_short_name;\n } else {\n tripName += trip.trip_id;\n }\n\n if (trip.trip_headsign) {\n tripName += ` - ${trip.trip_headsign}`;\n }\n\n if (timetableHasDifferentDays(timetable)) {\n tripName += ` - ${trip.dayList}`;\n }\n\n return tripName;\n}\n","{\n \"name\": \"gtfs-to-html\",\n \"version\": \"2.12.3\",\n \"private\": false,\n \"description\": \"Build human readable transit timetables as HTML, PDF or CSV from GTFS\",\n \"keywords\": [\n \"transit\",\n \"gtfs\",\n \"gtfs-realtime\",\n \"transportation\",\n \"timetables\"\n ],\n \"homepage\": \"https://gtfstohtml.com\",\n \"bugs\": {\n \"url\": \"https://github.com/blinktaginc/gtfs-to-html/issues\"\n },\n \"repository\": \"git://github.com/blinktaginc/gtfs-to-html\",\n \"license\": \"MIT\",\n \"author\": \"Brendan Nee <brendan@blinktag.com>\",\n \"contributors\": [\n \"Evan Siroky <evan.siroky@yahoo.com>\",\n \"Nathan Selikoff\",\n \"Aaron Antrim <aaron@trilliumtransit.com>\",\n \"Thomas Craig <thomas@trilliumtransit.com>\",\n \"Holly Kvalheim\",\n \"Pawajoro\",\n \"Andrea Mignone\",\n \"Evo Stamatov\",\n \"Sebastian Knopf\"\n ],\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"docker\",\n \"examples\",\n \"scripts\",\n \"views/default\",\n \"config-sample.json\"\n ],\n \"bin\": {\n \"gtfs-to-html\": \"dist/bin/gtfs-to-html.js\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"postbuild\": \"node scripts/postinstall.js\",\n \"start\": \"node ./dist/app\",\n \"prepare\": \"husky && npm run build\",\n \"postinstall\": \"node scripts/postinstall.js\"\n },\n \"dependencies\": {\n \"@maplibre/maplibre-gl-geocoder\": \"^1.9.1\",\n \"@turf/helpers\": \"^7.3.1\",\n \"@turf/simplify\": \"^7.3.1\",\n \"anchorme\": \"^3.0.8\",\n \"archiver\": \"^7.0.1\",\n \"cli-table\": \"^0.3.11\",\n \"css.escape\": \"^1.5.1\",\n \"csv-stringify\": \"^6.6.0\",\n \"express\": \"^5.2.1\",\n \"gtfs\": \"^4.18.2\",\n \"gtfs-realtime-pbf-js-module\": \"^1.0.0\",\n \"js-beautify\": \"^1.15.4\",\n \"lodash-es\": \"^4.17.21\",\n \"maplibre-gl\": \"^5.14.0\",\n \"marked\": \"^17.0.1\",\n \"moment\": \"^2.30.1\",\n \"pbf\": \"^4.0.1\",\n \"pretty-error\": \"^4.0.0\",\n \"pug\": \"^3.0.3\",\n \"puppeteer\": \"^24.32.0\",\n \"sanitize-filename\": \"^1.6.3\",\n \"sanitize-html\": \"^2.17.0\",\n \"sqlstring\": \"^2.3.3\",\n \"toposort\": \"^2.0.2\",\n \"yargs\": \"^18.0.0\",\n \"yoctocolors\": \"^2.1.2\"\n },\n \"devDependencies\": {\n \"@types/archiver\": \"^7.0.0\",\n \"@types/cli-table\": \"^0.3.4\",\n \"@types/express\": \"^5.0.6\",\n \"@types/insane\": \"^1.0.0\",\n \"@types/js-beautify\": \"^1.14.3\",\n \"@types/lodash-es\": \"^4.17.12\",\n \"@types/morgan\": \"^1.9.10\",\n \"@types/node\": \"^24\",\n \"@types/pug\": \"^2.0.10\",\n \"@types/sanitize-html\": \"^2.16.0\",\n \"@types/sqlstring\": \"^2.3.2\",\n \"@types/toposort\": \"^2.0.7\",\n \"@types/yargs\": \"^17.0.35\",\n \"husky\": \"^9.1.7\",\n \"lint-staged\": \"^16.2.7\",\n \"prettier\": \"^3.7.4\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.9.3\"\n },\n \"engines\": {\n \"node\": \">= 22\"\n },\n \"release-it\": {\n \"github\": {\n \"release\": true\n },\n \"plugins\": {\n \"@release-it/keep-a-changelog\": {\n \"filename\": \"CHANGELOG.md\"\n }\n },\n \"hooks\": {\n \"after:bump\": \"npm run build\"\n }\n },\n \"prettier\": {\n \"singleQuote\": true\n },\n \"lint-staged\": {\n \"*.js\": \"prettier --write\",\n \"*.ts\": \"prettier --write\",\n \"*.json\": \"prettier --write\"\n }\n}\n"],"mappings":";;;;;;;AAAA,OAAO,UAAU;AACjB,SAAS,SAAAA,QAAO,iBAAiB;AAEjC,SAAS,UAAAC,SAAQ,kBAAgC;AACjD,OAAOC,eAAc;;;ACJrB,SAAS,SAAS,MAAM,eAAe;AACvC,OAAO,eAAe;AACtB,SAAS,yBAAyB;AAClC,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,eAAe;AAGxB,YAAY,OAAO;AACnB,SAAS,UAAAC,eAAc;AACvB,OAAO,cAAc;AACrB,OAAO,cAAc;AACrB,OAAO,kBAAkB;AACzB,SAAS,kBAAkB;AAC3B,OAAO,eAAe;AACtB,OAAO,cAAc;AACrB,SAAS,cAAc;;;ACxBvB;AAAA,EACE;AAAA,EACA,QAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA;AAAA,EACA,UAAAC;AAAA,EACA;AAAA,OACK;AACP,OAAOC,aAAY;;;ACVnB,OAAO,YAAY;AASZ,SAAS,aAAa,YAAY;AACvC,QAAM,WAAW,OAAO,SAAS,UAAU;AAE3C,SAAO,OAAO;AAAA,IACZ,MAAM,SAAS,MAAM;AAAA,IACrB,QAAQ,SAAS,QAAQ;AAAA,IACzB,QAAQ,SAAS,QAAQ;AAAA,EAC3B,CAAC;AACH;AAKO,SAAS,WAAW,MAAM;AAC/B,SAAO,KAAK,OAAO,UAAU;AAC/B;AAKO,SAAS,uBAAuB,UAQjB;AACpB,MAAI,OAAO,OAAO,QAAQ,EAAE,MAAM,CAAC,UAAU,UAAU,IAAI,GAAG;AAC5D,WAAO;AAAA,EACT;AAEA,SAAO,GAAG,SAAS,UAAU,GAAG,GAAG,SAAS,WAAW,GAAG,GAAG,SAAS,aAAa,GAAG,GAAG,SAAS,YAAY,GAAG,GAAG,SAAS,UAAU,GAAG,GAAG,SAAS,YAAY,GAAG,GAAG,SAAS,UAAU,GAAG;AAChM;AAKO,SAAS,uBAAuB,MAAoB;AACzD,QAAMC,QAAO;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,WAQF,CAAC;AAEL,aAAW,CAAC,OAAO,GAAG,KAAKA,MAAK,QAAQ,GAAG;AACzC,aAAS,GAAG,IAAI,KAAK,KAAK;AAAA,EAC5B;AAEA,SAAO;AACT;AAGO,SAAS,mBACd,UASA,WACA,SACA;AACA,MAAI,CAAC,aAAa,CAAC,SAAS;AAC1B,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,iBAAiB;AAAA,IACrB,SAAS,WAAW,IAAI,IAAI;AAAA,IAC5B,SAAS,YAAY,IAAI,IAAI;AAAA,IAC7B,SAAS,cAAc,IAAI,IAAI;AAAA,IAC/B,SAAS,aAAa,IAAI,IAAI;AAAA,IAC9B,SAAS,WAAW,IAAI,IAAI;AAAA,IAC5B,SAAS,aAAa,IAAI,IAAI;AAAA,IAC9B,SAAS,WAAW,IAAI,IAAI;AAAA,EAC9B,EAAE,OAAO,CAAC,YAA+B,YAAY,IAAI;AAEzD,MAAI,eAAe,WAAW,GAAG;AAC/B,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,mBAAmB,IAAI,IAAI,cAAc;AAC/C,QAAM,QAAQ,oBAAI,IAAY;AAC9B,QAAM,OAAO,OAAO,UAAU,SAAS,GAAG,UAAU;AACpD,QAAM,gBAAgB,OAAO,QAAQ,SAAS,GAAG,UAAU;AAE3D,SAAO,KAAK,eAAe,aAAa,GAAG;AACzC,UAAM,aAAa,KAAK,WAAW;AACnC,QAAI,iBAAiB,IAAI,UAAU,GAAG;AACpC,YAAM,IAAI,SAAS,KAAK,OAAO,UAAU,GAAG,EAAE,CAAC;AAAA,IACjD;AACA,SAAK,IAAI,GAAG,KAAK;AAAA,EACnB;AAEA,SAAO,MAAM,KAAK,KAAK;AACzB;AAKO,SAAS,qBAAqB,YAAY;AAC/C,SAAO,OAAO,SAAS,UAAU,EAAE,UAAU;AAC/C;AAKO,SAAS,qBAAqB,YAAY;AAC/C,SAAO,OAAO,SAAS,UAAU,EAAE,UAAU;AAC/C;AAKO,SAAS,mBAAmB,YAAY,eAAe;AAC5D,QAAM,UAAU,aAAa,UAAU;AACvC,SAAO,WAAW,QAAQ,IAAI,eAAe,SAAS,CAAC;AACzD;;;AC/IA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAAC;AAAA,EACA;AAAA,OAQK;AACP,SAAS,iBAAiB;AAC1B,OAAOC,aAAY;AACnB,OAAO,eAAe;AACtB,OAAO,cAAc;;;ACrDrB,SAAS,oBAAoB,yBAAyB;AACtD,OAAO,cAAc;AACrB,SAAS,mBAAmB,aAAa;;;ACFzC,SAAS,WAAW,gBAAgB;AACpC,SAAS,YAAY;AACrB,YAAY,YAAY;AACxB,SAAS,aAAa,mBAAmB;AACzC,OAAO,WAAW;AAMX,SAAS,gBAAgB,aAAa,QAAgB;AAC3D,QAAM,WAAW,YAAY;AAC7B,QAAM,WAAW,YAAY;AAC7B,QAAM,cACJ,SAAS,SAAS,KAAK,SAAS,CAAC,EAAE,eAC/B,SAAS,CAAC,EAAE,eACZ;AAEN,QAAM,UAAU;AAAA,IACd,aAAa,SAAS,IAAI,CAAC,WAAW,OAAO,WAAW,EAAE,KAAK,IAAI,CAAC;AAAA,IACpE,iBAAiB,WAAW;AAAA,IAC5B,yBAAyB,OAAO,iBAAiB;AAAA,IACjD,oBAAmB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,IAC3C,yBAAyB,YAAY,cAAc;AAAA,IACnD,oBAAoB,YAAY,UAAU;AAAA,IAC1C,8BAA8B,YAAY,SAAS;AAAA,IACnD,gBAAgB,YAAY,MAAM;AAAA,IAClC,eAAe,YAAY,KAAK;AAAA,IAChC,eAAe,YAAY,KAAK;AAAA,EAClC;AAEA,aAAW,UAAU,OAAO,UAAU;AACpC,QAAI,OAAO,KAAK;AACd,cAAQ,KAAK,WAAW,OAAO,GAAG,EAAE;AAAA,IACtC,WAAW,OAAO,MAAM;AACtB,cAAQ,KAAK,WAAW,OAAO,IAAI,EAAE;AAAA,IACvC;AAAA,EACF;AAEA,MAAI,YAAY,SAAS,SAAS,GAAG;AACnC,YAAQ,KAAK,IAAI,aAAa,GAAG,YAAY,QAAQ;AAAA,EACvD;AAEA,SAAO,QAAQ,KAAK,IAAI;AAC1B;AAKO,SAAS,IAAI,QAAgB;AAClC,MAAI,OAAO,YAAY,OAAO;AAC5B,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,aAAa;AACtB,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO,CAAC,MAAc,cAAuB;AAC3C,QAAI,cAAc,QAAQ,QAAQ,OAAO,OAAO;AAC9C,gBAAU,QAAQ,QAAQ,CAAC;AAC3B,eAAS,QAAQ,QAAQ,CAAC;AAAA,IAC5B,OAAO;AACL,cAAQ,OAAO,MAAM,IAAI;AAAA,IAC3B;AAEA,YAAQ,OAAO,MAAM,IAAI;AAAA,EAC3B;AACF;AAKO,SAAS,WAAW,QAAgB;AACzC,MAAI,OAAO,aAAa;AACtB,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO,CAAC,SAAiB;AACvB,YAAQ,OAAO,MAAM;AAAA,EAAK,cAAc,IAAI,CAAC;AAAA,CAAI;AAAA,EACnD;AACF;AAKO,SAAS,SAAS,QAAgB;AACvC,MAAI,OAAO,aAAa;AACtB,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO,CAAC,SAAiB;AACvB,YAAQ,OAAO,MAAM;AAAA,EAAK,YAAY,IAAI,CAAC;AAAA,CAAI;AAAA,EACjD;AACF;AAKO,SAAS,cAAc,MAAc;AAC1C,QAAM,iBAAiB,GAAU,iBAAU,SAAS,CAAC,KAAK,IAAI;AAC9D,SAAc,cAAO,cAAc;AACrC;AAKO,SAAS,YAAY,OAAY;AACtC,QAAM,cAAc,iBAAiB,QAAQ,MAAM,UAAU;AAC7D,QAAM,eAAe,GAAU,iBAAU,OAAO,CAAC,KAAK,YAAY;AAAA,IAChE;AAAA,IACA;AAAA,EACF,CAAC;AACD,SAAc,WAAI,YAAY;AAChC;AAKO,SAAS,SAAS,QAAgB;AAEvC,MAAI,OAAO,aAAa;AACtB,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,UAAe;AACrB,UAAM,QAAQ,IAAI,MAAM;AAAA,MACtB,WAAW,CAAC,IAAI,EAAE;AAAA,MAClB,MAAM,CAAC,QAAQ,OAAO;AAAA,IACxB,CAAC;AAED,UAAM;AAAA,MACJ,CAAC,6BAAsB,MAAM,cAAc;AAAA,MAC3C,CAAC,wBAAiB,MAAM,UAAU;AAAA,MAClC,CAAC,kCAA2B,MAAM,SAAS;AAAA,MAC3C,CAAC,oBAAa,MAAM,MAAM;AAAA,MAC1B,CAAC,mBAAY,MAAM,KAAK;AAAA,MACxB,CAAC,mBAAY,MAAM,KAAK;AAAA,MACxB,CAAC,yBAAe,MAAM,SAAS,MAAM;AAAA,IACvC;AAEA,QAAI,MAAM,EAAE,MAAM,SAAS,CAAC;AAAA,EAC9B;AACF;AAKA,IAAM,4BAA4B,CAAC,UAAU,aAAaC,QAAO,OAAO;AACtE,QAAM,OAAO;AACb,QAAM,SAAS;AACf,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,MAAI,CAAC,eAAe,gBAAgB,GAAG;AACrC,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,MAAI,MAAM,QAAQ,GAAG;AACnB,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,iCAAiC;AAAA,EACnD;AAEA,MAAI,MAAMA,KAAI,GAAG;AACf,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,MAAI,cAAc,UAAU;AAC1B,WAAO,OAAO,OAAOA,QAAO,CAAC;AAAA,EAC/B;AAEA,QAAM,aAAa,cAAc;AACjC,QAAM,WAAW,KAAK,MAAMA,QAAO,UAAU;AAC7C,QAAM,gBAAgBA,QAAO;AAC7B,QAAM,eAAe,OAAO,OAAO,QAAQ;AAC3C,QAAM,oBAAoB,KAAK,OAAO,aAAa;AACnD,SAAO,eAAe;AACxB;AAKO,SAAS,YACd,cACA,UACA,QACA;AACA,MAAI,cAAc;AAElB,MAAI,OAAO,YAAY,OAAO;AAC5B,WAAO;AAAA,MACL,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,EACF;AAEA,MAAI,aAAa,GAAG;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,uBAAuB,MAC3B,aACG,QAAQ,WAAW,WAAW,EAC9B,QAAQ,WAAW,QAAQ,EAC3B,QAAQ,SAAS,0BAA0B,UAAU,WAAW,CAAC;AAEtE,MAAI,MAAM,EAAE,qBAAqB,GAAG,IAAI;AAExC,SAAO;AAAA,IACL,UAAU,MAAc;AAEtB,iBAAW,MAAM,EAAE,IAAI;AACvB,UAAI,MAAM,EAAE,EAAE;AAAA,IAChB;AAAA,IACA,YAAY;AACV,qBAAe;AACf,UAAI,MAAM,EAAE,qBAAqB,GAAG,IAAI;AAAA,IAC1C;AAAA,EACF;AACF;;;ADvNA,IAAM,eAAe,IAAI,aACvB,kBAAkB,SAAS,QAAQ,CAAC,YAAY,QAAQ,QAAQ,CAAC;AAKnE,IAAM,0BAA0B,CAAC,SAAS,WAAW;AACnD,aAAW,WAAW,QAAQ,UAAU;AACtC,QAAI,QAAQ,SAAS,aAAa;AAChC,UAAI,QAAQ,SAAS,KAAK,YAAY,MAAM,SAAS;AACnD,gBAAQ,SAAS,cAAc,QAAQ,SAAS,YAAY;AAAA,UAC1D,CAAC,WAAW,MAAM,QAAQ,OAAO,mBAAmB;AAAA,QACtD;AAAA,MACF,WAAW,QAAQ,SAAS,KAAK,YAAY,MAAM,cAAc;AAC/D,gBAAQ,SAAS,cAAc,QAAQ,SAAS,YAAY;AAAA,UAC1D,CAAC,eACC,WAAW;AAAA,YAAI,CAAC,WACd,MAAM,QAAQ,OAAO,mBAAmB;AAAA,UAC1C;AAAA,QACJ;AAAA,MACF,WAAW,QAAQ,SAAS,KAAK,YAAY,MAAM,mBAAmB;AACpE,gBAAQ,SAAS,cAAc,QAAQ,SAAS,YAAY;AAAA,UAC1D,CAAC,eACC,WAAW;AAAA,YAAI,CAAC,eACd,WAAW;AAAA,cAAI,CAAC,WACd,MAAM,QAAQ,OAAO,mBAAmB;AAAA,YAC1C;AAAA,UACF;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,oBAAoB,WAAW,QAAQ;AACrD,QAAM,iBAAiB,UAAU,UAAU;AAAA,IAAI,CAAC,YAC9C,mBAAmB;AAAA,MACjB,UAAU;AAAA,MACV,cAAc,UAAU;AAAA,MACxB,SAAS,UAAU,aAAa,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,IAC5D,CAAC;AAAA,EACH;AAEA,QAAM,gBAAgB,UAAU,UAAU;AAAA,IAAI,CAAC,YAC7C,kBAAkB;AAAA,MAChB,UAAU;AAAA,MACV,cAAc,UAAU;AAAA,MACxB,SAAS,UAAU,aAAa,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,IAC5D,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,aAAa,GAAG,gBAAgB,GAAG,aAAa;AAEhE,MAAI;AACJ,MAAI;AACF,wBAAoB,SAAS,SAAS;AAAA,MACpC,WAAW,IAAI,MAAM,OAAO;AAAA,MAC5B,aAAa;AAAA,IACf,CAAC;AAAA,EACH,QAAQ;AACN,cAAU,SAAS;AAAA,MACjB,aAAa,UAAU,YAAY;AAAA,IACrC;AACA,wBAAoB;AAAA,EACtB;AAEA,SAAO,wBAAwB,mBAAmB,MAAM;AAC1D;AAKO,SAAS,iBAAiB,QAAQ;AACvC,QAAM,iBAAiB,mBAAmB;AAC1C,QAAM,gBAAgB,kBAAkB;AAExC,QAAM,UAAU,aAAa,gBAAgB,aAAa;AAE1D,MAAI;AACJ,MAAI;AACF,wBAAoB,SAAS,SAAS;AAAA,MACpC,WAAW,IAAI,MAAM,OAAO;AAAA,MAC5B,aAAa;AAAA,IACf,CAAC;AAAA,EACH,QAAQ;AACN,eAAW,MAAM,EAAE,4BAA4B;AAC/C,wBAAoB;AAAA,EACtB;AAEA,SAAO,wBAAwB,mBAAmB,MAAM;AAC1D;;;AEvGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,aAAa;AAMf,SAAS,0BAA0B,WAAW;AACnD,SAAO,CAAC,MAAM,UAAU,cAAc,CAAC,MAAM,QAAQ;AACnD,QAAI,QAAQ,GAAG;AACb,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,YAAY,UAAU,aAAa,MAAM,CAAC,EAAE;AAAA,EAC1D,CAAC;AACH;AAMO,SAAS,8BAA8B,eAAe;AAC3D,SAAO,CAAC,MAAM,cAAc,wBAAwB,CAAC,WAAW,QAAQ;AACtE,QAAI,QAAQ,GAAG;AACb,aAAO;AAAA,IACT;AAEA,WACE,UAAU,gBACV,cAAc,uBAAuB,MAAM,CAAC,EAAE;AAAA,EAElD,CAAC;AACH;AAMO,SAAS,gCAAgC,eAAe;AAC7D,SAAO,CAAC,MAAM,cAAc,wBAAwB,CAAC,WAAW,QAAQ;AACtE,QAAI,QAAQ,GAAG;AACb,aAAO;AAAA,IACT;AAEA,WACE,UAAU,oBACV,cAAc,uBAAuB,MAAM,CAAC,EAAE;AAAA,EAElD,CAAC;AACH;AAKO,SAAS,kBAAkB,WAAW;AAC3C,SACE,UAAU,2BACV,UAAU,sBACV,UAAU,4BACV,UAAU,uBACV,UAAU,uBACV,UAAU,8BACV,UAAU,MAAM,SAAS;AAE7B;AAKO,SAAS,0BAA0B,OAAO;AAC/C,SAAO,MAAM,OAAO,CAAC,SAAS,CAAC,KAAK,WAAW,CAAC,KAAK,OAAO;AAC9D;AAKO,SAAS,gBAAgB,OAAO,MAAM;AAC3C,SAAO,MAAM,OAAO,CAAC,SAAS;AAE5B,QAAI,KAAK,SAAS;AAChB,aAAO;AAAA,IACT;AAGA,QACE,KAAK,iBACL,CAAC,KAAK,MAAM,KAAK,CAAC,SAAS,KAAK,kBAAkB,KAAK,aAAa,GACpE;AACA,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,YAAY,KAAK;AAAA,EAC/B,CAAC;AACH;AAKO,SAAS,gBAAgB,OAAO,MAAM;AAC3C,SAAO,MAAM,OAAO,CAAC,SAAS;AAE5B,QAAI,KAAK,SAAS;AAChB,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,YAAY,KAAK;AAAA,EAC/B,CAAC;AACH;AAKO,SAAS,oBAAoB,OAAO,UAAU;AACnD,SAAO,MAAM,OAAO,CAAC,SAAS;AAE5B,QACE,CAAC,KAAK,WACN,KAAK,YAAY,SAAS,WAC1B,KAAK,qBAAqB,GAC1B;AACA,aAAO;AAAA,IACT;AAGA,QACE,CAAC,KAAK,WACN,KAAK,YAAY,SAAS,WAC1B,KAAK,qBAAqB,GAC1B;AACA,aAAO;AAAA,IACT;AAEA,WACE,KAAK,YAAY,SAAS,WAAW,KAAK,YAAY,SAAS;AAAA,EAEnE,CAAC;AACH;AAMO,SAAS,eAAe,MAAM,OAAO,WAAW;AACrD,MAAI;AACJ,MAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,eAAW,KAAK;AAAA,EAClB,WAAW,UAAU,gBAAgB,cAAc;AAEjD,QAAI,KAAK,iBAAiB;AACxB,iBAAW,KAAK;AAAA,IAClB,OAAO;AACL,iBAAW,QAAQ,QAAQ,CAAC;AAAA,IAC9B;AAAA,EACF;AAEA,MAAI,0BAA0B,SAAS,GAAG;AACxC,gBAAY,IAAI,KAAK,OAAO;AAAA,EAC9B;AAEA,SAAO;AACT;AAKO,SAAS,qBAAqB,MAAM,WAAW;AACpD,MAAI,WAAW;AACf,MAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,gBAAY,GAAG,KAAK,gBAAgB;AAAA,EACtC;AAEA,MAAI,KAAK,iBAAiB;AACxB,gBAAY,KAAK;AAAA,EACnB,OAAO;AACL,gBAAY,KAAK;AAAA,EACnB;AAEA,MAAI,KAAK,eAAe;AACtB,gBAAY,MAAM,KAAK,aAAa;AAAA,EACtC;AAEA,MAAI,0BAA0B,SAAS,GAAG;AACxC,gBAAY,MAAM,KAAK,OAAO;AAAA,EAChC;AAEA,SAAO;AACT;;;ACzLA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,SAAW;AAAA,EACX,aAAe;AAAA,EACf,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAY;AAAA,EACZ,MAAQ;AAAA,IACN,KAAO;AAAA,EACT;AAAA,EACA,YAAc;AAAA,EACd,SAAW;AAAA,EACX,QAAU;AAAA,EACV,cAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAQ;AAAA,EACR,MAAQ;AAAA,EACR,OAAS;AAAA,EACT,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,KAAO;AAAA,IACL,gBAAgB;AAAA,EAClB;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,WAAa;AAAA,IACb,OAAS;AAAA,IACT,SAAW;AAAA,IACX,aAAe;AAAA,EACjB;AAAA,EACA,cAAgB;AAAA,IACd,kCAAkC;AAAA,IAClC,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,UAAY;AAAA,IACZ,UAAY;AAAA,IACZ,aAAa;AAAA,IACb,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,SAAW;AAAA,IACX,MAAQ;AAAA,IACR,+BAA+B;AAAA,IAC/B,eAAe;AAAA,IACf,aAAa;AAAA,IACb,eAAe;AAAA,IACf,QAAU;AAAA,IACV,QAAU;AAAA,IACV,KAAO;AAAA,IACP,gBAAgB;AAAA,IAChB,KAAO;AAAA,IACP,WAAa;AAAA,IACb,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,WAAa;AAAA,IACb,UAAY;AAAA,IACZ,OAAS;AAAA,IACT,aAAe;AAAA,EACjB;AAAA,EACA,iBAAmB;AAAA,IACjB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,wBAAwB;AAAA,IACxB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,OAAS;AAAA,IACT,eAAe;AAAA,IACf,UAAY;AAAA,IACZ,MAAQ;AAAA,IACR,YAAc;AAAA,EAChB;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,cAAc;AAAA,IACZ,QAAU;AAAA,MACR,SAAW;AAAA,IACb;AAAA,IACA,SAAW;AAAA,MACT,gCAAgC;AAAA,QAC9B,UAAY;AAAA,MACd;AAAA,IACF;AAAA,IACA,OAAS;AAAA,MACP,cAAc;AAAA,IAChB;AAAA,EACF;AAAA,EACA,UAAY;AAAA,IACV,aAAe;AAAA,EACjB;AAAA,EACA,eAAe;AAAA,IACb,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AACF;;;AJ9BA,IAAM,EAAE,QAAQ,IAAI;AAWb,IAAM,cAAc,CAAC,aAAuB;AACjD,MAAI,cAAc,SAAS,SAAS,GAAG;AACrC,WACE,CAAC,cAAc,SAAS,YAAY,KACpC,CAAC,cAAc,SAAS,cAAc;AAAA,EAE1C;AAEA,SAAO,SAAS,cAAc;AAChC;AAKA,IAAM,0BAA0B,CAAC,OAAwB,WAAmB;AAC1E,QAAM,wBAAwB,MAAM;AAAA,IAAI,CAAC,SACvC,KAAK,UAAU,OAAO,CAAC,aAAa;AAElC,UAAI,OAAO,sBAAsB,MAAM;AACrC,eAAO,YAAY,QAAQ;AAAA,MAC7B;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO,MAAM,uBAAuB,CAAC,cAAc,KAAK,SAAS,CAAC;AACpE;AAMA,IAAM,mBAAmB,CAAC,OAAwB,WAAmB;AACnE,QAAM,uBAAuB,wBAAwB,OAAO,MAAM;AAElE,MAAI,CAAC,sBAAsB;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,qBAAqB,KAAK,CAAC,UAAU,QAAQ;AAElE,QAAI,QAAQ,KAAK,SAAS,YAAY,KAAK,oBAAoB,GAAG,SAAS;AACzE,aAAO;AAAA,IACT;AAGA,QAAI,cAAc,SAAS,YAAY,GAAG;AACxC,aAAO;AAAA,IACT;AAGA,WAAOC;AAAA,MAAM;AAAA,MAAO,CAAC,SACnB,KAAK,UAAU;AAAA,QACb,CAAC,iBACC,aAAa,YAAY,SAAS,WAClC,aAAa,iBAAiB;AAAA,MAClC;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO,iBAAiB,eAAe,UAAU;AACnD;AAKA,IAAM,mBAAmB,CAAC,UAA2B;AACnD,MAAI,MAAM,UAAU,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,oBAAI,IAA2B;AAEnD,aAAW,QAAQ,OAAO;AAExB,UAAM,gBAAgB,KAAK,UACxB;AAAA,MACC,CAAC,aACC,GAAG,SAAS,OAAO,IAAI,SAAS,cAAc,IAAI,SAAS,YAAY;AAAA,IAC3E,EACC,KAAK,GAAG;AAEX,QAAI,CAAC,YAAY,IAAI,aAAa,GAAG;AACnC,kBAAY,IAAI,eAAe,IAAI;AAAA,IACrC;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,YAAY,OAAO,CAAC;AACxC;AAKA,IAAM,YAAY,CAAC,OAAwB,WAAoC;AAC7E,MAAI;AACJ,MAAI;AAEJ,MAAI,OAAO,qBAAqB,UAAU;AAGxC,mBAAe,iBAAiB,OAAO,MAAM;AAE7C,QAAI,cAAc;AAChB,oBAAc,0BAA0B,OAAO,YAAY;AAAA,IAC7D,OAAO;AAEL,oBAAc,UAAU,OAAO;AAAA,QAC7B,GAAG;AAAA,QACH,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF,WAAW,OAAO,qBAAqB,aAAa;AAGlD,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,UAAU,WAAW,GAAG;AAC/B;AAAA,MACF;AAEA,WAAK,gBAAgB,cAAc,KAAK,UAAU,CAAC,EAAE,cAAc;AACnE,WAAK,eAAe;AAAA,QAClB,KAAK,UAAU,KAAK,UAAU,SAAS,CAAC,EAAE;AAAA,MAC5C;AAAA,IACF;AAEA,kBAAc,OAAO,OAAO,CAAC,iBAAiB,cAAc,CAAC;AAAA,EAC/D,WAAW,OAAO,qBAAqB,OAAO;AAG5C,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,UAAU,WAAW,GAAG;AAC/B;AAAA,MACF;AAEA,WAAK,gBAAgB,cAAc,KAAK,UAAU,CAAC,EAAE,cAAc;AACnE,WAAK,eAAe;AAAA,QAClB,KAAK,UAAU,KAAK,UAAU,SAAS,CAAC,EAAE;AAAA,MAC5C;AAAA,IACF;AAEA,kBAAc,OAAO,OAAO,CAAC,gBAAgB,eAAe,CAAC;AAAA,EAC/D,WAAW,OAAO,qBAAqB,SAAS;AAG9C,UAAM,uBAAuB,wBAAwB,OAAO,MAAM;AAClE,UAAM,cAAc,MAAM,oBAAoB,EAAE;AAChD,kBAAc,0BAA0B,OAAO,WAAW;AAAA,EAC5D,WAAW,OAAO,qBAAqB,QAAQ;AAG7C,UAAM,uBAAuB,wBAAwB,OAAO,MAAM;AAClE,UAAM,aAAa,KAAK,oBAAoB,EAAE;AAC9C,kBAAc,0BAA0B,OAAO,UAAU;AAAA,EAC3D;AAEA,SAAO,eAAe,CAAC;AACzB;AAKA,IAAM,4BAA4B,CAAC,OAAwB,WACzD,OAAO,OAAO,CAAC,SAAS;AACtB,QAAM,WAAW,KAAK,KAAK,WAAW,EAAE,SAAS,OAAO,CAAC;AACzD,SAAO,WAAW,cAAc,SAAS,cAAc,IAAI;AAC7D,CAAC;AAKH,IAAM,+BAA+B,CACnC,WACA,WACG;AACH,QAAM,gBAAgB;AAAA,IACpB;AAAA,MACE,YAAY,UAAU;AAAA,IACxB;AAAA,IACA,CAAC;AAAA,IACD,CAAC,CAAC,QAAQ,KAAK,CAAC;AAAA,EAClB;AACA,QAAM,QAAQC,QAAO,UAAU,YAAY,UAAU;AACrD,QAAM,MAAMA,QAAO,UAAU,UAAU,UAAU;AACjD,QAAM,gBAAgB,oBAAI,IAAI;AAC9B,QAAM,gBAAgB,oBAAI,IAAI;AAE9B,aAAW,gBAAgB,eAAe;AACxC,QACEA,QAAO,aAAa,MAAM,UAAU,EAAE;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,GACA;AACA,UAAI,aAAa,mBAAmB,GAAG;AACrC,sBAAc,IAAI,WAAW,cAAc,OAAO,UAAU,CAAC;AAAA,MAC/D,WAAW,aAAa,mBAAmB,GAAG;AAC5C,sBAAc,IAAI,WAAW,cAAc,OAAO,UAAU,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAGA,QAAM,2BAA2B,IAAI;AAAA,IACnC,CAAC,GAAG,aAAa,EAAE,OAAO,CAAC,SAAS,cAAc,IAAI,IAAI,CAAC;AAAA,EAC7D;AAEA,SAAO;AAAA,IACL,eAAe,CAAC,GAAG,aAAa,EAAE;AAAA,MAChC,CAAC,SAAS,CAAC,yBAAyB,IAAI,IAAI;AAAA,IAC9C;AAAA,IACA,eAAe,CAAC,GAAG,aAAa,EAAE;AAAA,MAChC,CAAC,SAAS,CAAC,yBAAyB,IAAI,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;AAKA,IAAM,uBAAuB,CAAC,cAA0B;AACtD,QAAMC,QAAO;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AAEA,aAAW,YAAY,WAAW;AAChC,eAAW,OAAO,OAAO,KAAKA,KAAI,GAA4B;AAE5D,MAAAA,MAAK,GAAG,IAAIA,MAAK,GAAG,IAAI,SAAS,GAAG;AAAA,IACtC;AAAA,EACF;AAEA,SAAOA;AACT;AAKA,IAAM,oCAAoC,CAAC,cAAkC;AAC3E,QAAM,QAAQ;AAAA,IACZ;AAAA,MACE,cAAc,UAAU;AAAA,MACxB,UAAU,UAAU;AAAA,IACtB;AAAA,IACA,CAAC,eAAe;AAAA,EAClB;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,aAAa,OAAO,IAAI;AAAA,IACxB;AAAA,EACF,EAAE,QAAQ,MAAM,IAAI,CAAC,SAAS,KAAK,aAAa,CAAC,CAAC;AAElD,SAAO;AACT;AAKA,IAAM,gCAAgC,CACpC,WACA,WACG;AACH,QAAM,iBAAiB;AAAA;AAAA,IAErB,GAAG,4BAA4B;AAAA,MAC7B,cAAc,UAAU;AAAA,IAC1B,CAAC;AAAA;AAAA,IAGD,GAAG,4BAA4B;AAAA,MAC7B,UAAU,UAAU,OAAO,IAAI,CAAC,UAAU,MAAM,QAAQ;AAAA,MACxD,cAAc;AAAA,IAChB,CAAC;AAAA;AAAA,IAGD,GAAG,4BAA4B;AAAA,MAC7B,SAAS,UAAU,aAAa,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,IAC5D,CAAC;AAAA;AAAA,IAGD,GAAG,4BAA4B;AAAA,MAC7B,SAAS,UAAU,MAAM,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,MACnD,SAAS;AAAA,MACT,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,QAAM,qBAAqB,CAAC;AAE5B,aAAW,iBAAiB,gBAAgB;AAC1C,QACE,cAAc,kBAAkB,MAChC,cAAc,kBAAkB,MAChC;AACA,yBAAmB,KAAK,aAAa;AACrC;AAAA,IACF;AAGA,QAAI,cAAc,YAAY,MAAM,cAAc,YAAY,MAAM;AAClE,gBAAU,SAAS;AAAA,QACjB,wCAAwC,cAAc,OAAO;AAAA,MAC/D;AACA;AAAA,IACF;AAEA,UAAM,OAAO,UAAU,MAAM;AAAA,MAC3B,CAACC,UAASA,MAAK,YAAY,cAAc;AAAA,IAC3C;AAEA,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AAEA,UAAM,+BAA+B,KAAK,MAAM;AAAA,MAC9C,CAAC,SAAS,KAAK,kBAAkB,cAAc;AAAA,IACjD;AAEA,QAAI,8BAA8B;AAChC,yBAAmB,KAAK,aAAa;AAAA,IACvC;AAAA,EACF;AAEA,QAAM,QAAQ,kBAAkB;AAAA,IAC9B,SAAS,mBAAmB,IAAI,CAAC,kBAAkB,cAAc,OAAO;AAAA,EAC1E,CAAC;AAGD,QAAM,UAAU,6BAA6B,MAAM,EAAE;AACrD,MAAI,cAAc;AAClB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,WAAW,MAAM,KAAK,WAAW,MAAM;AAC9C,WAAK,SACH,cAAc,QAAQ,SAAS,IAC3B,QAAQ,WAAW,IACnB,cAAc,QAAQ;AAC5B,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,iBAAiB,mBAAmB,IAAI,CAAC,mBAAmB;AAAA,IAChE,GAAG;AAAA,IACH,GAAG,MAAM,KAAK,CAAC,SAAS,KAAK,YAAY,cAAc,OAAO;AAAA,EAChE,EAAE;AAEF,SAAO,OAAO,gBAAgB,QAAQ;AACxC;AAMA,IAAM,sBAAsB,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AACF,MAIM;AACJ,QAAM,oBAAoB,WAAW,IAAI,CAAC,cAAc;AACtD,QAAI,CAAC,UAAU,QAAQ;AACrB,gBAAU,SAAS,UAAU;AAAA,QAC3B,UAAU,UAAU;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,gBAAgB;AAAA,IACpB,mBAAmB;AAAA,IACnB,YAAY;AAAA,IACZ,QAAQ,kBAAkB,QAAQ,CAAC,cAAc,UAAU,MAAM;AAAA,EACnE;AAEA,QAAM,WAAW,8BAA8B,eAAe,MAAM;AAEpE,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EACF;AACF;AAKA,IAAM,kBAAkB,CAAC;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAM0B;AACxB,QAAM,aAAa,KAAK;AAAA,IACtB,GAAI,WAAW,IAAI,CAAC,aAAa,SAAS,UAAU,KAAK,CAAC;AAAA,IAC1D,GAAI,eAAe,IAAI,CAAC,iBAAiB,aAAa,UAAU,KAAK,CAAC;AAAA,EACxE,CAAC;AAED,QAAMD,QAQF;AAAA,IACF,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW;AAAA,IACX,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,EACV;AACA,MAAI,YAA2B;AAC/B,MAAI,UAAyB;AAE7B,MAAI,aAAa,UAAU,SAAS,GAAG;AACrC,WAAO,OAAOA,OAAM,qBAAqB,SAAS,CAAC;AAEnD,gBAAY;AAAA,MACVD,QACG;AAAA,QACC,UAAU,IAAI,CAAC,aAAaA,QAAO,SAAS,YAAY,UAAU,CAAC;AAAA,MACrE,EACC,OAAO,UAAU;AAAA,MACpB;AAAA,IACF;AAEA,cAAU;AAAA,MACRA,QACG,IAAI,UAAU,IAAI,CAAC,aAAaA,QAAO,SAAS,UAAU,UAAU,CAAC,CAAC,EACtE,OAAO,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,kBAAkB;AAAA,IACpC,UAAU,CAAC,MAAM,QAAQ;AAAA,IACzB;AAAA,IACA,MAAMC;AAAA,IACN,OAAO,eAAe,IAAI,CAAC,iBAAiB,aAAa,IAAI;AAAA,EAC/D,CAAC;AAED,SAAO;AAAA,IACL,cAAc;AAAA,IACd,WAAW,CAAC,MAAM,QAAQ;AAAA,IAC1B,cAAc,gBAAgB,OAAO,OAAO;AAAA,IAC5C,gBAAgB,iBAAiB,OAAO,OAAO;AAAA,IAC/C,QAAQ,CAAC,KAAK;AAAA,IACd,oBAAoB,iBAAiB,cAAc,SAAS,IAAI,IAAI;AAAA,IACpE,aAAa;AAAA,IACb,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,GAAGA;AAAA,EACL;AACF;AAMA,IAAM,gCAAgC,CAAC,WAAmB;AACxD,QAAM,SAAS,UAAU;AACzB,QAAM,iBAA2C,CAAC;AAClD,QAAM,EAAE,WAAW,cAAc,IAAI,uBAAuB,MAAM;AAElE,aAAW,SAAS,QAAQ;AAC1B,UAAM,QAAQ;AAAA,MACZ;AAAA,QACE,UAAU,MAAM;AAAA,MAClB;AAAA,MACA,CAAC,iBAAiB,gBAAgB,WAAW,YAAY;AAAA,IAC3D;AACA,UAAM,uBAAuB;AAAA,MAC3B,OAAO,OAAO,CAAC,SAAS,KAAK,YAAY;AAAA,MACzC;AAAA,IACF;AACA,UAAM,kBAAkB,QAAQ,WAAW,wBAAwB,MAAM;AACzE,UAAM,iBAAiB,QAAQ,iBAAiB,sBAAsB;AACtE,UAAM,qBAAqB,QAAQ,eAAe,YAAY;AAE9D,UAAM,aAA0B,CAAC;AAEjC,eAAW,uBAAuB,sBAAsB;AACtD,iBAAWE,cAAa,OAAO,OAAO,cAAc,GAAG;AACrD,cAAM,oBAAoB,MAAM;AAAA,UAAO,CAAC,SACtC,KAAKA,YAAW,EAAE,YAAY,KAAK,WAAW,CAAC;AAAA,QACjD;AACA,YAAI,kBAAkB,SAAS,GAAG;AAChC,qBAAW;AAAA,YACT,gBAAgB;AAAA,cACd;AAAA,cACA,aAAa,oBAAoB;AAAA,cACjC,cAAc,oBAAoB;AAAA,cAClC,WAAAA;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,iBAAWC,kBAAiB,OAAO,OAAO,kBAAkB,GAAG;AAC7D,cAAM,wBAAwB,MAAM;AAAA,UAAO,CAAC,SAC1C,KAAKA,gBAAe,EAAE,YAAY,KAAK,WAAW,CAAC;AAAA,QACrD;AACA,YAAI,sBAAsB,SAAS,GAAG;AACpC,qBAAW;AAAA,YACT,gBAAgB;AAAA,cACd;AAAA,cACA,aAAa,oBAAoB;AAAA,cACjC,cAAc,oBAAoB;AAAA,cAClC,eAAAA;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW,WAAW,GAAG;AAC3B;AAAA,IACF;AAEA,QAAI,OAAO,6BAA6B,MAAM;AAC5C,qBAAe;AAAA,QACb,oBAAoB;AAAA,UAClB,iBAAiB,SAAS,MAAM,oBAAoB,MAAM,eAAe;AAAA,UACzE;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,iBAAW,aAAa,YAAY;AAClC,uBAAe;AAAA,UACb,oBAAoB;AAAA,YAClB,iBAAiB,UAAU;AAAA,YAC3B,YAAY,CAAC,SAAS;AAAA,YACtB;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,IAAM,6BAA6B,CACjC,MACA,aACA,WACG;AACH,QAAM,uBAAuB,YAAY;AAAA,IAAI,CAAC,cAC5C,gBAAgB,WAAW,MAAM;AAAA,EACnC;AACA,QAAM,YAAY,yBAAyB,IAAI;AAC/C,QAAM,QAAQ,CAAC;AAEf,aAAW,aAAa,sBAAsB;AAC5C,UAAM,eAAe,qBAAqB,UAAU,UAAU;AAC9D,UAAM,aAAa,qBAAqB,UAAU,QAAQ;AAE1D,aACM,SAAS,cACb,SAAS,YACT,UAAU,UAAU,cACpB;AACA,YAAM,UAAU,UAAU,SAAS;AACnC,YAAM,KAAK;AAAA,QACT,GAAG;AAAA,QACH,SAAS,GAAG,UAAU,OAAO,SAAS,MAAM,MAAM;AAAA,QAClD,WAAW,wBAAwB,SAAS,MAAM;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAMA,IAAM,6CAA6C,CACjD,SACA,WACA,WACG;AACH,MACE,OAAO,4BAA4B,QACnC,OAAO,4BAA4B,QACnC;AACA,WAAO;AAAA,EACT;AAEA,aAAW,QAAQ,UAAU,cAAc;AACzC,eAAW,YAAY,KAAK,WAAW;AACrC,YAAM,sBAAsB,aAAa,SAAS,cAAc,EAAE;AAAA,QAChE,aAAa,SAAS,YAAY;AAAA,QAClC;AAAA,MACF;AAEA,UAAI,sBAAsB,OAAO,yBAAyB;AACxD;AAAA,MACF;AAEA,YAAM,QAAQ,QAAQ,QAAQ,SAAS,OAAO;AAC9C,UAAI,UAAU,KAAK,UAAU,QAAQ,SAAS,GAAG;AAC/C;AAAA,MACF;AAEA,UACE,SAAS,YAAY,QAAQ,QAAQ,CAAC,KACtC,SAAS,YAAY,QAAQ,QAAQ,CAAC,GACtC;AACA;AAAA,MACF;AAEA,cAAQ,OAAO,OAAO,GAAG,SAAS,OAAO;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO;AACT;AAKA,IAAM,eAAe,CAAC,WAAsB,WAAmB;AAE7D,QAAM,sBAAsB;AAAA,IAC1B;AAAA,MACE,cAAc,UAAU;AAAA,IAC1B;AAAA,IACA,CAAC,SAAS;AAAA,IACV,CAAC,CAAC,iBAAiB,KAAK,CAAC;AAAA,EAC3B;AAEA,MAAI,oBAAoB,SAAS,GAAG;AAClC,WAAO,oBAAoB;AAAA,MACzB,CAAC,uBAAuB,mBAAmB;AAAA,IAC7C;AAAA,EACF;AAGA,MAAI;AACF,UAAM,YAAY,CAAC;AAGnB,UAAM,mBAAmB,IAAI;AAAA,MAC3B,UAAU,aAAa;AAAA,QAAQ,CAAC,SAC9B,KAAK,UACF,OAAO,CAAC,aAAa,YAAY,QAAQ,CAAC,EAC1C,IAAI,CAAC,aAAa,SAAS,OAAO;AAAA,MACvC;AAAA,IACF;AAEA,eAAW,QAAQ,UAAU,cAAc;AACzC,YAAM,gBAAgB,KAAK,UACxB,OAAO,CAAC,aAAa;AAEpB,YAAI,OAAO,sBAAsB,MAAM;AACrC,iBAAO,iBAAiB,IAAI,SAAS,OAAO;AAAA,QAC9C;AACA,eAAO;AAAA,MACT,CAAC,EACA,IAAI,CAAC,aAAa,SAAS,OAAO;AAErC,iBAAW,CAAC,OAAO,MAAM,KAAK,cAAc,QAAQ,GAAG;AACrD,YAAI,UAAU,cAAc,SAAS,GAAG;AACtC;AAAA,QACF;AAEA,kBAAU,KAAK,CAAC,QAAQ,cAAc,QAAQ,CAAC,CAAC,CAAC;AAAA,MACnD;AAAA,IACF;AAEA,QAAI,UAAU,WAAW,KAAK,OAAO,sBAAsB,MAAM;AAC/D,gBAAU,SAAS;AAAA,QACjB,aAAa,UAAU,YAAY;AAAA,MACrC;AAAA,IACF;AAEA,UAAM,UAAU,SAAS,SAAS;AAElC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AAIN,UAAM,uBAAuB;AAAA,MAC3B,UAAU;AAAA,MACV;AAAA,IACF;AACA,UAAM,UAAU,qBAAqB;AAAA,MACnC,CAAC,aAAa,SAAS;AAAA,IACzB;AAEA,UAAM,iBAAiB;AAAA,MACrB,IAAI;AAAA,QACF,UAAU,aAAa;AAAA,UAAQ,CAAC,SAC9B,KAAK,UAAU,IAAI,CAAC,aAAuB,SAAS,OAAO;AAAA,QAC7D;AAAA,MACF;AAAA,MACA,IAAI,IAAI,OAAO;AAAA,IACjB;AAEA,QAAI,eAAe,SAAS,GAAG;AAC7B,gBAAU,SAAS;AAAA,QACjB,aAAa,UAAU,YAAY,0MAA0M,qBAAqB,cAAc,CAAC;AAAA,MACnR;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAKA,IAAM,uBAAuB,CAAC,WAAsB,WAAmB;AACrE,MAAI,UAAU,aAAa,WAAW,GAAG;AACvC,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,iBAAiB,aAAa,WAAW,MAAM;AACrD,QAAM,eAAe,eAAe,IAAI,CAAC,QAAQ,UAAU;AACzD,UAAM,QAAQ,SAAS;AAAA,MACrB,SAAS;AAAA,IACX,CAAC;AAED,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI;AAAA,QACR,mCAAmC,MAAM,oBAAoB,UAAU,YAAY;AAAA,MACrF;AAAA,IACF;AAEA,UAAM,OAAO;AAAA,MACX,GAAG,MAAM,CAAC;AAAA,MACV,OAAO,CAAC;AAAA,IACV;AAEA,QACE,QAAQ,eAAe,SAAS,KAChC,WAAW,eAAe,QAAQ,CAAC,GACnC;AACA,WAAK,OAAO;AAAA,IACd,WAAW,QAAQ,KAAK,WAAW,eAAe,QAAQ,CAAC,GAAG;AAC5D,WAAK,OAAO;AAAA,IACd;AAEA,WAAO;AAAA,EACT,CAAC;AAGD,MAAI,OAAO,cAAc;AACvB,UAAM,iBAAiB,kBAAkB;AAAA,MACvC,SAAS;AAAA,IACX,CAAC;AAED,eAAW,iBAAiB,gBAAgB;AAC1C,YAAM,OAAO,aAAa;AAAA,QACxB,CAACF,UAASA,MAAK,YAAY,cAAc;AAAA,MAC3C;AAEA,UAAI,MAAM;AACR,aAAK,YAAY,cAAc;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,yBAAyB,CAAC,WAAmB;AACjD,QAAM,KAAK,OAAO;AAClB,MAAI,cAAc;AAClB,QAAM,eAAe,CAAC;AAEtB,MAAI,OAAO,SAAS;AAElB,QAAI,CAACF,QAAO,OAAO,OAAO,EAAE,QAAQ,GAAG;AACrC,YAAM,IAAI,MAAM,mBAAmB,OAAO,OAAO,iBAAiB;AAAA,IACpE;AAEA,iBAAa;AAAA,MACX,iBAAiB,UAAU,OAAOA,QAAO,OAAO,OAAO,EAAE,OAAO,UAAU,CAAC,CAAC;AAAA,IAC9E;AAAA,EACF;AAEA,MAAI,OAAO,WAAW;AAEpB,QAAI,CAACA,QAAO,OAAO,SAAS,EAAE,QAAQ,GAAG;AACvC,YAAM,IAAI,MAAM,qBAAqB,OAAO,SAAS,iBAAiB;AAAA,IACxE;AAEA,iBAAa;AAAA,MACX,eAAe,UAAU,OAAOA,QAAO,OAAO,SAAS,EAAE,OAAO,UAAU,CAAC,CAAC;AAAA,IAC9E;AAAA,EACF;AAEA,MAAI,aAAa,SAAS,GAAG;AAC3B,kBAAc,SAAS,aAAa,KAAK,OAAO,CAAC;AAAA,EACnD;AAEA,QAAM,YAAwB,GAC3B,QAAQ,0BAA0B,WAAW,EAAE,EAC/C,IAAI;AAGP,QAAM,aAAa,UAAU,IAAI,CAAC,aAAa,SAAS,UAAU;AAClE,QAAM,gBAAgB,GACnB;AAAA,IACC,gFAAgF,WAC7E,IAAI,CAAC,cAAc,IAAI,SAAS,GAAG,EACnC,KAAK,IAAI,CAAC;AAAA,EACf,EACC,IAAI;AAEP,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAKA,IAAM,4BAA4B,CAAC,cAAyB;AAC1D,QAAM,KAAK,OAAO;AAClB,MAAI,cAAc;AAClB,QAAM,eAAe,CAAC;AAEtB,MAAI,UAAU,UAAU;AAEtB,QAAI,CAACA,QAAO,UAAU,UAAU,YAAY,IAAI,EAAE,QAAQ,GAAG;AAC3D,YAAM,IAAI;AAAA,QACR,oBAAoB,UAAU,QAAQ,qBAAqB,UAAU,YAAY;AAAA,MACnF;AAAA,IACF;AAEA,iBAAa,KAAK,iBAAiB,UAAU,OAAO,UAAU,QAAQ,CAAC,EAAE;AAAA,EAC3E;AAEA,MAAI,UAAU,YAAY;AAExB,QAAI,CAACA,QAAO,UAAU,YAAY,YAAY,IAAI,EAAE,QAAQ,GAAG;AAC7D,YAAM,IAAI;AAAA,QACR,sBAAsB,UAAU,UAAU,qBAAqB,UAAU,YAAY;AAAA,MACvF;AAAA,IACF;AAEA,iBAAa,KAAK,eAAe,UAAU,OAAO,UAAU,UAAU,CAAC,EAAE;AAAA,EAC3E;AAEA,QAAMC,QAAO,qBAAqB,CAAC,SAAS,CAAC;AAE7C,QAAM,aAAa;AAAA,IACjBA;AAAA,IACA,CAAC,MAAgB,OAAe,QAAgB;AAC9C,UAAI,UAAU,GAAG;AACf,aAAK,KAAK,GAAG,GAAG,MAAM;AAAA,MACxB;AAEA,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAEA,MAAI,WAAW,SAAS,GAAG;AACzB,iBAAa,KAAK,IAAI,WAAW,KAAK,MAAM,CAAC,GAAG;AAAA,EAClD;AAEA,MAAI,aAAa,SAAS,GAAG;AAC3B,kBAAc,SAAS,aAAa,KAAK,OAAO,CAAC;AAAA,EACnD;AAEA,SAAO,GAAG,QAAQ,0BAA0B,WAAW,EAAE,EAAE,IAAI;AACjE;AAKA,IAAM,+BAA+B,CACnC,WACA,YACG;AACH,QAAM,KAAK,OAAO;AAClB,QAAM,eAAe,CAAC;AAEtB,MAAI,SAAS;AACX,iBAAa,KAAK,WAAW,UAAU,OAAO,OAAO,CAAC,EAAE;AAAA,EAC1D;AAEA,MAAI,WAAW;AACb,iBAAa,KAAK,WAAW,UAAU,OAAO,SAAS,CAAC,EAAE;AAAA,EAC5D;AAEA,QAAM,gBAAgC,GACnC;AAAA,IACC,qEAAqE,aAAa;AAAA,MAChF;AAAA,IACF,CAAC;AAAA,EACH,EACC,IAAI;AACP,SAAO;AACT;AAOA,IAAM,uBAAuB,CAAC,WAAmB;AAC/C,QAAM,QAAQ,SAAS;AAAA,IACrB,SAAS;AAAA,EACX,CAAC;AAED,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,6BAA6B,MAAM,EAAE;AAAA,EACvD;AAEA,QAAM,OAAO,MAAM,CAAC;AAEpB,MAAI,cAAc,KAAK,cAAc,GAAG;AACtC,WAAO,CAAC,MAAM;AAAA,EAChB;AAEA,QAAM,uBAAuB;AAAA,IAC3B;AAAA,MACE,gBAAgB,KAAK;AAAA,IACvB;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,SAAO;AAAA,IACL,KAAK;AAAA,IACL,GAAG,qBAAqB,IAAI,CAACC,UAASA,MAAK,OAAO;AAAA,EACpD;AACF;AAKA,IAAM,wBAAwB,CAAC,MAAqB,cAAyB;AAC3E,QAAM,QAAQ;AAAA,IACZ;AAAA,MACE,UAAU,KAAK;AAAA,MACf,YAAY,UAAU;AAAA,IACxB;AAAA,IACA,CAAC,WAAW,UAAU;AAAA,EACxB;AAEA,aAAW,aAAa,OAAO;AAC7B,UAAM,YAAY;AAAA,MAChB;AAAA,QACE,SAAS,UAAU;AAAA,MACrB;AAAA,MACA,CAAC;AAAA,MACD,CAAC,CAAC,iBAAiB,KAAK,CAAC;AAAA,IAC3B;AAEA,QAAI,UAAU,WAAW,GAAG;AAC1B,YAAM,IAAI;AAAA,QACR,wCAAwC,UAAU,OAAO;AAAA,MAC3D;AAAA,IACF;AAEA,cAAU,gBAAgB,MAAM,SAAS;AACzC,cAAU,eAAe,KAAK,SAAS;AAAA,EACzC;AAEA,SAAO,OAAO,OAAO,CAACG,UAASA,MAAK,cAAc,mBAAmB;AACvE;AAMA,IAAM,sBAAsB,CAAC,MAAqB,cAAyB;AACzE,MAAI,CAAC,KAAK,YAAY,KAAK,UAAU,WAAW,GAAG;AACjD;AAAA,EACF;AAEA,QAAM,mCAAmC,KAAK;AAE9C,QAAM,gBAAgB,MAAM,KAAK,SAAS;AAC1C,QAAM,eAAe,qBAAqB,cAAc,OAAO;AAC/D,QAAM,eAAe,KAAK,KAAK,SAAS;AACxC,QAAM,cAAc,qBAAqB,aAAa,OAAO;AAC7D,QAAM,aAAa,sBAAsB,MAAM,SAAS;AAGxD,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,CAAC,cACC,UAAU,aAAa,qBACvB,cAAc;AAAA,EAClB;AAQA,MACE,gBACA,aAAa,aAAa,KAAK,YAC/B,aAAa,aAAa,qBACxB,cAAc,sBAAsB,oCACtC,aAAa,SAAS,aAAa,aAAa,OAAO,GACvD;AACA,UAAM,SAAS,UAAU;AAAA,MACvB,UAAU,aAAa;AAAA,IACzB,CAAC;AAED,iBAAa,QAAQ,OAAO,CAAC;AAE7B,SAAK,uBAAuB;AAAA,EAC9B;AAGA,QAAM,WAAW;AAAA,IACf;AAAA,IACA,CAAC,cACC,UAAU,cAAc,uBACxB,aAAa;AAAA,EACjB;AASA,MACE,YACA,SAAS,aAAa,KAAK,YAC3B,SAAS,cAAc,uBACrB,aAAa,oBAAoB,oCACnC,YAAY,SAAS,SAAS,cAAc,OAAO,GACnD;AACA,UAAM,SAAS,UAAU;AAAA,MACvB,UAAU,SAAS;AAAA,IACrB,CAAC;AAED,aAAS,QAAQ,OAAO,CAAC;AACzB,SAAK,qBAAqB;AAAA,EAC5B;AACF;AAMA,IAAM,cAAc,CAAC,WAA+B,WAAmB;AACrE,MAAI,gBAAgB,UAAU;AAG9B,aAAW,QAAQ,eAAe;AAChC,UAAM,oBAAoB,CAAC;AAE3B,eAAW,CAAC,OAAO,QAAQ,KAAK,KAAK,UAAU,QAAQ,GAAG;AACxD,UACE,UAAU,KACV,SAAS,YAAY,KAAK,UAAU,QAAQ,CAAC,EAAE,SAC/C;AACA,0BAAkB,KAAK,QAAQ;AAAA,MACjC,OAAO;AAEL,0BAAkB,kBAAkB,SAAS,CAAC,EAAE,iBAC9C,SAAS;AAAA,MACb;AAAA,IACF;AAEA,SAAK,YAAY;AAAA,EACnB;AAGA,QAAM,mBAAmB,IAAI;AAAA,IAC3B,UAAU,MAAM,IAAI,CAAC,SAAe,KAAK,OAAO;AAAA,EAClD;AACA,aAAW,QAAQ,eAAe;AAChC,SAAK,YAAY,KAAK,UAAU;AAAA,MAAO,CAAC,aACtC,iBAAiB,IAAI,SAAS,OAAO;AAAA,IACvC;AAAA,EACF;AAGA,kBAAgB,cAAc;AAAA,IAC5B,CAAC,SAAe,KAAK,UAAU,SAAS;AAAA,EAC1C;AAEA,MAAI,OAAO,uBAAuB,OAAO;AACvC,oBAAgB,iBAAiB,aAAa;AAAA,EAChD;AAEA,SAAO;AACT;AAOA,IAAM,uBAAuB,CAC3B,WACA,WACA,WACG;AACH,QAAM,YAIF;AAAA,IACF,UAAU,UAAU;AAAA,IACpB,YAAY,UAAU;AAAA,EACxB;AAEA,MAAI,CAAC,cAAc,UAAU,YAAY,GAAG;AAC1C,cAAU,eAAe,UAAU;AAAA,EACrC;AAEA,QAAM,QAAQ,SAAS,SAAS;AAEhC,MAAI,MAAM,WAAW,GAAG;AACtB,cAAU,SAAS;AAAA,MACjB,+BAA+B,UAAU,UAAU;AAAA,QACjD;AAAA,MACF,CAAC,kBAAkB,UAAU,YAAY,iBAAiB,KAAK;AAAA,QAC7D,UAAU;AAAA,MACZ,CAAC,kBAAkB,UAAU,YAAY;AAAA,IAC3C;AAAA,EACF;AAEA,QAAM,cAAc,eAAe;AAAA,IACjC,SAAS,MAAM,IAAI,CAAC,SAAS,KAAK,OAAO;AAAA,EAC3C,CAAC;AAGD,YAAU,cAAc,KAAK,MAAM,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC;AAEjE,QAAM,iBAAiB,CAAC;AAExB,aAAW,QAAQ,OAAO;AACxB,UAAM,gBAAgB,WAAW,MAAM,WAAW,WAAW,MAAM;AACnE,kBAAc,YAAY;AAAA,MACxB;AAAA,QACE,SAAS,cAAc;AAAA,MACzB;AAAA,MACA,CAAC;AAAA,MACD,CAAC,CAAC,iBAAiB,KAAK,CAAC;AAAA,IAC3B;AAEA,QAAI,cAAc,UAAU,WAAW,GAAG;AACxC,gBAAU,SAAS;AAAA,QACjB,kCACE,cAAc,OAChB,cAAc,UAAU,UAAU,KAAK,GAAG,CAAC,kBACzC,UAAU,YACZ;AAAA,MACF;AAAA,IACF;AAGA,QACE,UAAU,oBAAoB,MAC9B,UAAU,oBAAoB,QAC9B,UAAU,oBAAoB,UAC9B,KAAK,UAAU,CAAC,EAAE,oBAAoB,UAAU,iBAChD;AACA;AAAA,IACF;AAGA,QACE,UAAU,kBAAkB,MAC5B,UAAU,kBAAkB,QAC5B,UAAU,kBAAkB,UAC5B,KAAK,UAAU,CAAC,EAAE,qBAAqB,UAAU,eACjD;AACA;AAAA,IACF;AAEA,QAAI,UAAU,wBAAwB;AACpC,0BAAoB,eAAe,SAAS;AAE5C,UAAI,cAAc,oBAAoB;AACpC,kBAAU,yBAAyB;AAAA,MACrC;AAEA,UAAI,cAAc,sBAAsB;AACtC,kBAAU,2BAA2B;AAAA,MACvC;AAAA,IACF;AAEA,UAAM,kBAAkB,YAAY;AAAA,MAClC,CAAC,cAAc,UAAU,YAAY,KAAK;AAAA,IAC5C;AAEA,QAAI,gBAAgB,WAAW,GAAG;AAChC,qBAAe,KAAK,aAAa;AAAA,IACnC,OAAO;AACL,YAAM,iBAAiB;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,qBAAe,KAAK,GAAG,cAAc;AACrC,gBAAU,cAAc;AACxB,gBAAU,sBAAsB,KAAK,aAAa;AAAA,QAChD,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,OAAO,kBAAkB;AAC3B,UAAM,UAAU,CAAC;AAEjB,eAAW,QAAQ,gBAAgB;AACjC,iBAAW,YAAY,KAAK,WAAW;AACrC,gBAAQ,KAAK,SAAS,OAAO;AAAA,MAC/B;AAAA,IACF;AAEA,UAAM,QAAQ;AAAA,MACZ;AAAA,QACE,SAAS,KAAK,OAAO;AAAA,MACvB;AAAA,MACA,CAAC,kBAAkB,SAAS;AAAA,IAC9B;AAEA,eAAW,QAAQ,gBAAgB;AACjC,iBAAW,YAAY,KAAK,WAAW;AACrC,cAAM,OAAO,MAAM,KAAK,CAACH,UAASA,MAAK,YAAY,SAAS,OAAO;AAEnE,YAAI,MAAM,gBAAgB;AACxB,mBAAS,UAAU,KAAK;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,UAAU,gBAAgB,MAAM;AACzC;AAMA,IAAM,mBAAmB,CAAC,YAAyB,WAAmB;AACpE,QAAM,sBAAsB,WAAW,IAAI,CAAC,cAAc;AACxD,cAAU,WAAW,CAAC;AACtB,UAAM,UAAU,WAAW,WAAW,MAAM;AAC5C,UAAM,YAAY,0BAA0B,SAAS;AACrD,UAAM,aAAa,oBAAI,IAAI;AAG3B,eAAW,YAAY,WAAW;AAChC,iBAAW,IAAI,SAAS,UAAU;AAAA,IACpC;AAEA,QAAI,UAAU,uBAAuB,GAAG;AACtC,YAAM,gBAAgB;AAAA,QACpB,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAEA,YAAM,qBAAqB,QAAQ,eAAe,YAAY;AAE9D,iBAAW,CAAC,WAAW,iBAAiB,KAAK,OAAO;AAAA,QAClD;AAAA,MACF,GAAG;AAED,cAAM,WAAW,UAAU;AAAA,UACzB,CAAC,MAAgB,EAAE,eAAe;AAAA,QACpC;AAGA,YACE,kBAAkB;AAAA,UAChB,CAAC,iBAAiB,aAAa,mBAAmB;AAAA,QACpD,GACA;AACA,qBAAW,IAAI,SAAS;AAAA,QAC1B;AAEA,cAAM,kCAAkC,kBAAkB;AAAA,UACxD,CAAC,iBAAiB,aAAa,mBAAmB;AAAA,QACpD;AAGA,YACE,UAAU,cACV,UAAU,YACV,YACA,gCAAgC,SAAS,GACzC;AACA,gBAAM,uBAAuB;AAAA,YAC3B;AAAA,YACA,UAAU;AAAA,YACV,UAAU;AAAA,UACZ;AAGA,cAAI,qBAAqB,WAAW,GAAG;AACrC,uBAAW,OAAO,SAAS;AAAA,UAC7B;AAGA,gBAAM,sBAAsB,qBAAqB;AAAA,YAC/C,CAAC,wBACC,gCAAgC;AAAA,cAC9B,CAAC,iBAAiB,aAAa,SAAS;AAAA,YAC1C;AAAA,UACJ;AAEA,cAAI,qBAAqB;AACvB,uBAAW,OAAO,SAAS;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO,OAAO,WAAW;AAAA,MACvB,qBAAqB;AAAA,MACrB,0BAA0B;AAAA,MAC1B,qBAAqB;AAAA,MACrB,yBAAyB;AAAA,MACzB,oBAAoB;AAAA,MACpB,4BAA4B;AAAA,MAC5B,cAAc,OAAO;AAAA,MACrB,qBAAqB,OAAO;AAAA,MAC5B,iBAAiB,OAAO;AAAA,MACxB,sBAAsB,OAAO;AAAA,MAC7B,iBAAiB,OAAO;AAAA,MACxB,qBAAqB,OAAO;AAAA,MAC5B,gBAAgB,OAAO;AAAA,MACvB,wBAAwB,OAAO;AAAA,MAC/B,aAAa,UAAU,eAAe,OAAO;AAAA,MAC7C,aAAa,MAAM,KAAK,UAAU;AAAA,MAClC;AAAA,MACA,aAAa,eAAe,SAAS,MAAM;AAAA,IAC7C,CAAC;AAED,cAAU,eAAe,qBAAqB,WAAW,WAAW,MAAM;AAC1E,cAAU,QAAQ,qBAAqB,WAAW,MAAM;AACxD,cAAU,gBAAgB,6BAA6B,WAAW,MAAM;AACxE,cAAU,kBAAkB,qBAAqB,SAAS;AAC1D,cAAU,QAAQ,8BAA8B,WAAW,MAAM;AAEjE,QAAI,OAAO,SAAS;AAClB,gBAAU,UAAU,oBAAoB,WAAW,MAAM;AAAA,IAC3D;AAEA,cAAU,WAAW;AAAA,MACnB,UAAU,aAAa,IAAI,CAAC,SAAe,KAAK,OAAO;AAAA,IACzD;AAGA,cAAU,eAAe,YAAY,WAAW,MAAM;AAGtD,cAAU,QAAQ,YAAY,WAAW,MAAM;AAE/C,WAAO;AAAA,EACT,CAAC;AAED,MAAI,OAAO,sBAAsB;AAC/B,WAAO;AAAA,EACT;AAEA,SAAO,oBAAoB;AAAA,IACzB,CAAC,cAAc,UAAU,aAAa,SAAS;AAAA,EACjD;AACF;AAKO,SAAS,2BACd,QAC0B;AAC1B,QAAM,aAAa,0BAA0B,cAAc,CAAC;AAC5D,QAAM,SAAS,UAAU;AACzB,QAAM,sBAAsB,WAAW,IAAI,CAAC,cAAc;AACxD,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,OAAO;AAAA,QAAO,CAAC,UACrB,UAAU,UAAU,SAAS,MAAM,QAAQ;AAAA,MAC7C;AAAA,IACF;AAAA,EACF,CAAC;AAGD,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,8BAA8B,MAAM;AAAA,EAC7C;AAEA,QAAM,iBAAiB;AAAA,IACrB,CAAC;AAAA,IACD,CAAC;AAAA,IACD,CAAC,CAAC,qBAAqB,KAAK,CAAC;AAAA,EAC/B;AAGA,MAAI,eAAe,WAAW,GAAG;AAE/B,WAAO,oBAAoB;AAAA,MAAI,CAAC,cAC9B,oBAAoB;AAAA,QAClB,iBAAiB,UAAU;AAAA,QAC3B,YAAY,CAAC,SAAS;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO,eAAe,IAAI,CAAC,kBAAkB;AAC3C,WAAO;AAAA,MACL,GAAG;AAAA,MACH,YAAY;AAAA,QACV,oBAAoB;AAAA,UAClB,CAAC,cACC,UAAU,sBAAsB,cAAc;AAAA,QAClD;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,IAAM,8BAA8B,CAAC,oBAA4B;AAC/D,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI,cAAsC;AAC1C,QAAM,QAAQ,iBAAiB,MAAM,GAAG,KAAK,CAAC;AAC9C,MAAI,MAAM,SAAS,GAAG;AACpB,kBAAc,OAAO,SAAS,MAAM,IAAI,GAAG,EAAE;AAC7C,mBAAe,MAAM,IAAI;AAAA,EAC3B,WAAW,MAAM,SAAS,GAAG;AAC3B,kBAAc;AACd,mBAAe,MAAM,IAAI;AAAA,EAC3B;AAEA,QAAM,UAAU,MAAM,KAAK,GAAG;AAE9B,QAAM,SAAS,UAAU;AAAA,IACvB,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,QAAQ;AAAA,IACZ;AAAA,MACE,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IACA,CAAC,iBAAiB,cAAc;AAAA,EAClC;AACA,QAAM,uBAAuB,OAAO,OAAO,CAAC,SAAS,KAAK,YAAY;AAEtE,MAAI,qBAAqB,WAAW,GAAG;AACrC,UAAM,IAAI;AAAA,MACR,wCAAwC,eAAe,aAAa,OAAO,iBAAiB,WAAW;AAAA,IACzG;AAAA,EACF;AAEA,MAAI,UAAU,KAAK,gBAAgB,EAAE,GAAG;AACtC,gBAAY,aAAa;AAAA,MACvB,GAAG,uBAAuB,YAAY;AAAA,IACxC,CAAC;AAAA,EACH,OAAO;AACL,gBAAY;AACZ,oBAAgB,iBAAiB;AAAA,MAC/B,gBAAgB;AAAA,MAChB,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,OAAO,CAAC;AAAA,IACf,aAAa,qBAAqB,CAAC,EAAE;AAAA,IACrC,cAAc,qBAAqB,CAAC,EAAE;AAAA,EACxC;AACF;AAKA,IAAM,uBAAuB,CAAC,iBAAyB,WAAmB;AAExE,QAAM,iBAAiB,kBAAkB;AAAA,IACvC,mBAAmB;AAAA,EACrB,CAAC;AAED,QAAM,aAAa;AAAA,IACjB,cAAc;AAAA,EAChB;AAEA,MAAI,eAAe,SAAS,GAAG;AAC7B,UAAM,IAAI;AAAA,MACR,wDAAwD,eAAe;AAAA,IACzE;AAAA,EACF;AAEA,MAAI,eAAe,WAAW,GAAG;AAE/B,UAAM,gBAAgB,eAAe,CAAC;AACtC,kBAAc,aAAa;AAAA,MACzB,WAAW;AAAA,QACT,CAACI,eAAcA,WAAU,sBAAsB;AAAA,MACjD;AAAA,MACA;AAAA,IACF;AAGA,eAAWA,cAAa,cAAc,YAAY;AAChD,MAAAA,WAAU,SAAS,UAAU;AAAA,QAC3B,UAAUA,WAAU;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,SAAS,GAAG;AAEzB,UAAM,0BAA0B,WAAW;AAAA,MACzC,CAACA,eAAcA,WAAU,iBAAiB;AAAA,IAC5C;AAEA,QAAI,wBAAwB,WAAW,GAAG;AACxC,YAAM,IAAI;AAAA,QACR,4CAA4C,eAAe;AAAA,MAC7D;AAAA,IACF;AAEA,WAAO,oBAAoB;AAAA,MACzB;AAAA,MACA,YAAY,CAAC,wBAAwB,CAAC,CAAC;AAAA,MACvC;AAAA,IACF,CAAC;AAAA,EACH;AAGA,MAAI,gBAAgB,WAAW,QAAQ,GAAG;AACxC,UAAM,SAAS,UAAU;AAAA,MACvB,kBAAkB,gBAAgB,MAAM,GAAG,EAAE,CAAC;AAAA,IAChD,CAAC;AAED,QAAI,OAAO,WAAW,GAAG;AACvB,YAAM,IAAI;AAAA,QACR,wCAAwC,eAAe;AAAA,MACzD;AAAA,IACF;AAEA,UAAM,EAAE,WAAAH,YAAW,eAAAC,eAAc,IAAI,uBAAuB,MAAM;AAElE,UAAM,QAAQ;AAAA,MACZ;AAAA,QACE,UAAU,OAAO,CAAC,EAAE;AAAA,MACtB;AAAA,MACA,CAAC,iBAAiB,gBAAgB,WAAW,YAAY;AAAA,IAC3D;AACA,UAAM,uBAAuB;AAAA,MAC3B,OAAO,OAAO,CAAC,SAAS,KAAK,YAAY;AAAA,MACzC;AAAA,IACF;AACA,UAAM,kBAAkB,QAAQD,YAAW,wBAAwB,MAAM;AACzE,UAAM,iBAAiB,QAAQ,iBAAiB,sBAAsB;AACtE,UAAM,qBAAqB,QAAQC,gBAAe,YAAY;AAE9D,UAAMG,cAAmC,CAAC;AAE1C,eAAW,uBAAuB,sBAAsB;AACtD,iBAAWJ,cAAa,OAAO,OAAO,cAAc,GAAG;AACrD,cAAM,oBAAoB,MAAM;AAAA,UAAO,CAAC,SACtC,KAAKA,YAAW,EAAE,YAAY,KAAK,WAAW,CAAC;AAAA,QACjD;AACA,YAAI,kBAAkB,SAAS,GAAG;AAChC,UAAAI,YAAW;AAAA,YACT,gBAAgB;AAAA,cACd,OAAO,OAAO,CAAC;AAAA,cACf,aAAa,oBAAoB;AAAA,cACjC,cAAc,oBAAoB;AAAA,cAClC,WAAAJ;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,iBAAWC,kBAAiB,OAAO,OAAO,kBAAkB,GAAG;AAC7D,cAAM,wBAAwB,MAAM;AAAA,UAAO,CAAC,SAC1C,KAAKA,gBAAe,EAAE,YAAY,KAAK,WAAW,CAAC;AAAA,QACrD;AACA,YAAI,sBAAsB,SAAS,GAAG;AACpC,UAAAG,YAAW;AAAA,YACT,gBAAgB;AAAA,cACd,OAAO,OAAO,CAAC;AAAA,cACf,aAAa,oBAAoB;AAAA,cACjC,cAAc,oBAAoB;AAAA,cAClC,eAAAH;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO,oBAAoB;AAAA,MACzB;AAAA,MACA,YAAAG;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,EAAE,WAAW,eAAe,OAAO,aAAa,aAAa,IACjE,4BAA4B,eAAe;AAE7C,QAAM,YAAY,gBAAgB;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,oBAAoB;AAAA,IACzB;AAAA,IACA,YAAY,CAAC,SAAS;AAAA,IACtB;AAAA,EACF,CAAC;AACH;AAKO,SAAS,iBAAiB,eAAuB;AACtD,QAAM,WAAW;AAAA,IACf,sBAAsB;AAAA,IACtB,UAAU;AAAA,IACV,qBAAqB;AAAA,IACrB,YAAY;AAAA,IACZ,kBAAkB,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAAA,IAClE,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,0BAA0B;AAAA,IAC1B,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,0BAA0B;AAAA,IAC1B,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,0BAA0B;AAAA,IAC1B,uBAAuB;AAAA,IACvB,yBAAyB;AAAA,IACzB,wBAAwB;AAAA,IACxB,oBAAoB;AAAA,IACpB,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,8BAA8B;AAAA,IAC9B,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AAEA,QAAM,SAAS,OAAO,OAAO,UAAU,aAAa;AAEpD,MAAI,OAAO,iBAAiB,OAAO;AAEjC,WAAO,SAAS;AAChB,WAAO,WAAW;AAAA,EACpB;AAGA,SAAO,kCAAkC,OAAO,SAAS;AAAA,IACvD,CAAC,WAAW,OAAO,0BAA0B;AAAA,EAC/C;AAEA,SAAO,6BAA6B,OAAO,SAAS;AAAA,IAClD,CAAC,WAAW,OAAO,qBAAqB;AAAA,EAC1C;AAEA,SAAO,wBAAwB,OAAO,SAAS;AAAA,IAC7C,CAAC,WAAW,OAAO,gBAAgB;AAAA,EACrC;AAEA,SAAO;AACT;AAKO,SAAS,0BACd,iBACA,QACA;AACA,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,EACF;AAEA,QAAM,yBAAyB;AAAA,IAC7B,cAAc;AAAA,IACd;AAAA,EACF;AAGA,aAAW,aAAa,wBAAwB;AAC9C,QAAI,cAAc,UAAU,cAAc,GAAG;AAC3C,gBAAU,iBAAiB,kCAAkC,SAAS;AAAA,IACxE;AAEA,QAAI,CAAC,UAAU,QAAQ;AACrB,gBAAU,SAAS,UAAU;AAAA,QAC3B,UAAU,UAAU;AAAA,MACtB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,eAAe;AAAA,IACnB,QAAQ,wBAAwB,CAAC,cAAc,UAAU,MAAM;AAAA,IAC/D;AAAA,EACF;AAEA,QAAM,yBAAyB;AAAA,IAC7B,GAAG;AAAA,IACH;AAAA,IACA,SAAS,WAAW,qBAAqB,sBAAsB,GAAG,MAAM;AAAA,IACxE,UAAU;AAAA,MACR,uBAAuB,IAAI,CAAC,cAAc,UAAU,OAAO;AAAA,IAC7D;AAAA,IACA,WAAW,aAAa,IAAI,CAAC,UAAU,MAAM,QAAQ;AAAA,IACrD,YAAY,KAAK,QAAQ,aAAa,IAAI,CAAC,UAAU,MAAM,SAAS,CAAC,CAAC;AAAA,IACtE,UACE,cAAc,YAAY,GAAG,cAAc,iBAAiB;AAAA,IAC9D,sBACE,cAAc,wBACd,qBAAqB,aAAa,IAAI,CAAC,UAAU,gBAAgB,KAAK,CAAC,CAAC;AAAA,EAC5E;AAEA,SAAO;AACT;AAKO,IAAM,gBAAgB,CAAC,kBAA0C;AACtE,QAAM,WAAuC,CAAC;AAC9C,QAAM,aAAyC,CAAC;AAChD,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,EACb;AAEA,aAAW,aAAa,cAAc,wBAAwB;AAC5D,UAAM,SAAS,UAAU,MAAM;AAC/B,UAAM,SAAS,UAAU,aAAa;AACtC,eAAW,aAAa,UAAU,aAAa;AAC7C,iBAAW,SAAS,IAAI;AAAA,IAC1B;AAEA,eAAW,WAAW,UAAU,WAAW;AACzC,eAAS,OAAO,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,SAAS,KAAK,QAAQ;AAC5B,QAAM,YAAY,KAAK,UAAU;AAEjC,SAAO;AACT;AAKO,SAAS,sBACd,eACA,QACA;AACA,QAAM,WAAWC,aAAY;AAC7B,QAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA,OAAO,GAAG,cAAc,oBAAoB,MAAM,qBAAqB,SAAS,IAAI,CAAC,WAAW,OAAO,WAAW,CAAC,CAAC;AAAA,EACtH;AACA,SAAO,eAAe,iBAAiB,cAAc,MAAM;AAC7D;AAKO,SAAS,qBAAqB,WAAW;AAE9C,QAAM,QAAQ,CAAC;AAEf,QAAM,KAAK;AAAA,IACT;AAAA,IACA,GAAG,UAAU,aAAa;AAAA,MAAI,CAAC,SAC7B,qBAAqB,MAAM,SAAS;AAAA,IACtC;AAAA,EACF,CAAC;AAED,MAAI,UAAU,0BAA0B;AACtC,UAAM,KAAK;AAAA,MACT;AAAA,MACA,GAAG,UAAU,aAAa,IAAI,CAAC,SAAS,wBAAwB,IAAI,CAAC;AAAA,IACvE,CAAC;AAAA,EACH;AAEA,aAAW,QAAQ,UAAU,OAAO;AAClC,UAAM,KAAK;AAAA,MACT,eAAe,IAAI;AAAA,MACnB,GAAG,KAAK,MAAM,IAAI,CAAC,aAAa,SAAS,cAAc;AAAA,IACzD,CAAC;AAAA,EACH;AAEA,MAAI,UAAU,wBAAwB;AACpC,UAAM,KAAK;AAAA,MACT;AAAA,MACA,GAAG,UAAU,aAAa,IAAI,CAAC,SAAS,sBAAsB,IAAI,CAAC;AAAA,IACrE,CAAC;AAAA,EACH;AAEA,MAAI,UAAU,gBAAgB,YAAY;AACxC,WAAO,UAAU,IAAI,GAAG,KAAK,CAAC;AAAA,EAChC;AAEA,SAAO,UAAU,KAAK;AACxB;AAKO,SAAS,qBACd,gBACA,QACA;AACA,QAAM,WAAWA,aAAY;AAC7B,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,IAAI,MAAM,mBAAmB;AAAA,EACrC;AAEA,QAAM,UAAU,OAAO,UAAU,iBAAiB,MAAM,IAAI;AAE5D,QAAM,eAAe;AAAA,IACnB,QAAQ;AAAA,MACN,GAAG,MAAM,QAAQ;AAAA,MACjB;AAAA,IACF;AAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,GAAG,qBAAqB,SAAS,IAAI,CAAC,WAAW,OAAO,WAAW,CAAC,CAAC;AAAA,EAC9E;AACA,SAAO,eAAe,YAAY,cAAc,MAAM;AACxD;;;AF19DA,SAAS,WAAW,QAAQ,WAAW;AACrC,QAAM,KAAK,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,KAAK,GAAG,GAAG,IAAI;AAC5D,SAAO,OAAO,QAAQ,IAAI,CAAC,YAAY,UAAU,OAAO,CAAC;AAC3D;AAKO,SAAS,cAAc,OAAO;AACnC,SAAO,UAAU,QAAQ,UAAU;AACrC;AAKO,SAAS,WAAW,MAAM,YAAY;AAC3C,MAAI,KAAK,cAAc;AACrB,WAAO,KAAK;AAAA,EACd;AAEA,SAAOC,QAAO,KAAK,MAAM,UAAU,EAAE,OAAO,UAAU;AACxD;AAKO,SAAS,cAAc,MAAM;AAClC,SAAOA,QAAO,SAAS,IAAI,EAAE,UAAU;AACzC;AAMA,SAAS,eAAe,UAAU,WAAW,QAAQ;AACnD,WAAS,UAAU,CAAC;AAEpB,MAAI,SAAS,SAAS,aAAa,SAAS,cAAc;AACxD,UAAM,cAAc,aAAa,SAAS,YAAY;AACtD,aAAS,iBAAiB,YAAY,OAAO,OAAO,UAAU;AAC9D,aAAS,QAAQ,KAAK,YAAY,OAAO,GAAG,CAAC;AAAA,EAC/C,WAAW,SAAS,SAAS,eAAe,SAAS,gBAAgB;AACnE,UAAM,gBAAgB,aAAa,SAAS,cAAc;AAC1D,aAAS,iBAAiB,cAAc,OAAO,OAAO,UAAU;AAChE,aAAS,QAAQ,KAAK,cAAc,OAAO,GAAG,CAAC;AAAA,EACjD;AAEA,MAAI,SAAS,gBAAgB,GAAG;AAC9B,aAAS,WAAW;AACpB,aAAS,QAAQ,KAAK,WAAW;AACjC,QAAI,UAAU,mBAAmB,MAAM;AACrC,gBAAU,qBAAqB;AAAA,IACjC;AAAA,EACF,WAAW,SAAS,gBAAgB,KAAK,SAAS,gBAAgB,GAAG;AACnE,aAAS,gBAAgB;AACzB,aAAS,QAAQ,KAAK,gBAAgB;AACtC,QAAI,UAAU,wBAAwB,MAAM;AAC1C,gBAAU,0BAA0B;AAAA,IACtC;AAAA,EACF;AAEA,MAAI,SAAS,kBAAkB,GAAG;AAChC,aAAS,YAAY;AACrB,aAAS,QAAQ,KAAK,aAAa;AACnC,QAAI,UAAU,oBAAoB,MAAM;AACtC,gBAAU,sBAAsB;AAAA,IAClC;AAAA,EACF,WAAW,SAAS,kBAAkB,KAAK,SAAS,kBAAkB,GAAG;AACvE,aAAS,iBAAiB;AAC1B,aAAS,QAAQ,KAAK,kBAAkB;AACxC,QAAI,UAAU,yBAAyB,MAAM;AAC3C,gBAAU,2BAA2B;AAAA,IACvC;AAAA,EACF;AAEA,MAAI,SAAS,cAAc,KAAK,SAAS,mBAAmB,IAAI;AAC9D,aAAS,eAAe;AACxB,aAAS,QAAQ,KAAK,cAAc;AACpC,QAAI,UAAU,2BAA2B,MAAM;AAC7C,gBAAU,6BAA6B;AAAA,IACzC;AAAA,EACF;AAEA,MACE,SAAS,cAAc,QACvB,SAAS,mBAAmB,QAC5B,SAAS,kBAAkB,MAC3B;AACA,aAAS,UAAU;AACnB,aAAS,QAAQ,KAAK,SAAS;AAC/B,QAAI,UAAU,oBAAoB,MAAM;AACtC,gBAAU,sBAAsB;AAAA,IAClC;AAAA,EACF;AAEA,MAAI,SAAS,cAAc,GAAG;AAC5B,aAAS,QAAQ,KAAK,WAAW;AAAA,EACnC;AAEA,SAAO;AACT;AAMA,SAAS,kBAAkB,OAAO;AAEhC,QAAM,iBAAiB,CAAC;AACxB,QAAM,mBAAmB,qBAAqB,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,YAAY;AAC5E,aAAW,QAAQ,MAAM,CAAC,EAAE,OAAO;AACjC,UAAM,UAAU,qBAAqB,KAAK,YAAY;AACtD,QAAI,WAAW,mBAAmB,IAAI;AACpC;AAAA,IACF;AAEA,mBAAe,KAAK,aAAa,KAAK,YAAY,CAAC;AAAA,EACrD;AAGA,QAAM,yBAAyB,eAAe,IAAI,CAAC,MAAM,SAAS;AAAA,IAChE;AAAA,IACA;AAAA,EACF,EAAE;AACF,QAAM,+BAA+BC;AAAA,IAAO;AAAA,IAAwB,CAAC,SACnE,OAAO,SAAS,KAAK,KAAK,OAAO,GAAG,GAAG,EAAE;AAAA,EAC3C;AAGA,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,SAAK,cAAc,6BAA6B;AAAA,MAAI,CAAC,SACnD,aAAa,KAAK,MAAM,KAAK,GAAG,EAAE,YAAY,EAAE,OAAO,KAAK;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT,CAAC;AACH;AAKA,IAAM,OAAO;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACO,SAAS,WAAW,UAAU,QAAQ;AAC3C,QAAM,YAAY,OAAO;AACzB,MAAI,aAAa;AACjB,MAAI,YAAY;AAEhB,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,WAAS,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG;AAC9B,UAAM,sBAAsB,SAAS,KAAK,CAAC,CAAC,MAAM;AAClD,UAAM,uBAAuB,IAAI,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI;AACnE,UAAM,mBAAmB,IAAI,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI;AAE/D,QAAI,qBAAqB;AACvB,UAAI,UAAU,SAAS,GAAG;AACxB,YAAI,CAAC,sBAAsB;AACzB,uBAAa;AAAA,QACf,WAAW,eAAe,GAAG;AAC3B,uBAAa;AAAA,QACf;AAAA,MACF;AAEA,oBAAc;AAEd,UACE,UAAU,WAAW,KACrB,CAAC,oBACD,MAAM,KACN,CAAC,sBACD;AACA,qBAAa,UAAU,CAAC;AAAA,MAC1B;AAAA,IACF,OAAO;AACL,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,gBAAY,OAAO;AAAA,EACrB;AAEA,SAAO;AACT;AAKO,SAAS,eAAe,SAAS,QAAQ;AAC9C,QAAM,YAAY,UAAU,OAAO,kBAAkB,OAAO,WAAW;AAEvE,SAAO,WAAW,SAAS,SAAS;AACtC;AAKO,SAAS,WAAW,MAAM,WAAW,WAAW,QAAQ;AAC7D,OAAK,WAAWC,MAAK,WAAW;AAAA,IAC9B,YAAY,KAAK;AAAA,EACnB,CAAC;AACD,OAAK,UAAU,WAAW,KAAK,UAAU,MAAM;AAC/C,OAAK,cAAc,eAAe,KAAK,SAAS,MAAM;AAEtD,MAAI,UAAU,OAAO,WAAW,GAAG;AACjC,SAAK,mBAAmB,UAAU,OAAO,CAAC,EAAE;AAAA,EAC9C,OAAO;AACL,UAAM,QAAQ,UAAU,OAAO;AAAA,MAC7B,CAACC,WAAUA,OAAM,aAAa,KAAK;AAAA,IACrC;AACA,SAAK,mBAAmB,MAAM;AAAA,EAChC;AAEA,SAAO;AACT;AAKO,SAAS,gBAAgB,WAAW,QAAQ;AACjD,QAAM,YAAY,aAAa,UAAU,UAAU;AACnD,QAAM,UAAU,aAAa,UAAU,QAAQ;AAC/C,QAAM,UAAUH,QAAO,SAAS,UAAU,cAAc,SAAS;AACjE,YAAU,uBAAuB,UAAU,OAAO,OAAO,UAAU;AACnE,YAAU,qBAAqB,QAAQ,OAAO,OAAO,UAAU;AAC/D,YAAU,cAAc,KAAK,MAAM,QAAQ,UAAU,CAAC;AACtD,SAAO;AACT;AAKO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,MAAAI;AAAA,EACA;AACF,GAaG;AACD,MAAI,cAAc,SAAS,KAAK,GAAG;AAEnC,MAAI,uBAAuBA,KAAI,GAAG;AAChC,mBAAe,IAAI,uBAAuBA,KAAI,CAAC;AAAA,EACjD,WAAW,SAAS,MAAM,SAAS,GAAG;AACpC,mBAAe,IAAI,MAAM,KAAK,GAAG,CAAC;AAAA,EACpC;AAEA,MAAI,CAAC,cAAc,WAAW,GAAG;AAC/B,mBAAe,IAAI,WAAW;AAAA,EAChC;AAEA,SAAO;AACT;AAEA,SAAS,oBAAoB,QAAQ,QAAQ;AAC3C,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,WAAW;AAAA,EACb;AACF;AAKO,SAAS,YAAY,WAAW,QAAQ;AAC7C,aAAW,QAAQ,UAAU,cAAc;AACzC,QAAI,YAAY;AAChB,eAAW,CAAC,KAAK,QAAQ,KAAK,KAAK,UAAU,QAAQ,GAAG;AAEtD,YAAM,OAAOF,MAAK,UAAU,OAAO,CAAC,IAAIG,SAAQ;AAC9C,YAAI,GAAG,YAAY,SAAS,WAAWA,OAAM,WAAW;AACtD,sBAAYA;AACZ,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,MACT,CAAC;AAED,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AAGA,UAAI,QAAQ,GAAG;AACb,iBAAS,gBAAgB;AAAA,MAC3B;AAGA,UAAI,QAAQ,KAAK,UAAU,SAAS,GAAG;AACrC,iBAAS,cAAc;AAAA,MACzB;AAIA,UAAI,KAAK,SAAS,aAAa,MAAM,KAAK,UAAU,SAAS,GAAG;AAC9D,cAAM,oBAAoB,MAAM,QAAQ;AACxC,0BAAkB,OAAO;AACzB,kBAAU,MAAM,YAAY,CAAC,EAAE,MAAM;AAAA,UACnC,eAAe,mBAAmB,WAAW,MAAM;AAAA,QACrD;AAAA,MACF;AAGA,UAAI,EAAE,KAAK,SAAS,aAAa,QAAQ,IAAI;AAC3C,iBAAS,OAAO;AAChB,aAAK,MAAM,KAAK,eAAe,UAAU,WAAW,MAAM,CAAC;AAAA,MAC7D;AAAA,IACF;AAGA,eAAW,QAAQ,UAAU,OAAO;AAClC,YAAM,eAAeC,MAAK,KAAK,KAAK;AACpC,UAAI,CAAC,gBAAgB,aAAa,YAAY,KAAK,SAAS;AAC1D,aAAK,MAAM;AAAA,UACT;AAAA,YACE,oBAAoB,KAAK,SAAS,KAAK,OAAO;AAAA,YAC9C;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,UAAU,gBAAgB,UAAU;AACtC,cAAU,QAAQ,kBAAkB,UAAU,KAAK;AAAA,EACrD;AAEA,aAAW,QAAQ,UAAU,OAAO;AAClC,SAAK,eAAe,KAAK,MAAM,KAAK,CAAC,aAAa,YAAY,QAAQ,CAAC;AAAA,EACzE;AAEA,SAAO,UAAU;AACnB;AAKO,SAAS,eAAe,MAAM;AACnC,SAAO,GAAG,KAAK,SAAS,GACtB,KAAK,SAAS,YACV,eACA,KAAK,SAAS,cACZ,iBACA,EACR;AACF;AAKO,SAAS,wBAAwB,MAAM;AAC5C,SAAO,KAAK,uBACR,KAAK,qBAAqB,MAAM,mBAChC;AACN;AAKO,SAAS,sBAAsB,MAAM;AAC1C,SAAO,KAAK,qBACR,KAAK,mBAAmB,MAAM,mBAC9B;AACN;AAMO,SAAS,yBAAyB,MAAM;AAC7C,QAAM,gBAAgB;AAAA,IACpBC,OAAM,KAAK,SAAS,EAAE;AAAA,EACxB;AACA,MAAI,gBAAgB,GAAG;AACrB,eAAW,YAAY,KAAK,WAAW;AACrC,eAAS,iBAAiB;AAAA,QACxB,aAAa,SAAS,cAAc,EAAE;AAAA,UACpC;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,eAAS,eAAe;AAAA,QACtB,aAAa,SAAS,YAAY,EAAE,SAAS,eAAe,SAAS;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,wBAAwB,MAAM,eAAe;AAC3D,SAAO,KAAK,UAAU,IAAI,CAAC,aAAa;AACtC,WAAO,SAAS;AAChB,aAAS,iBAAiB;AAAA,MACxB,SAAS;AAAA,MACT;AAAA,IACF;AACA,aAAS,eAAe;AAAA,MACtB,SAAS;AAAA,MACT;AAAA,IACF;AACA,aAAS,UAAU,KAAK;AACxB,WAAO;AAAA,EACT,CAAC;AACH;AAKO,SAAS,iBAAiB,OAAO;AAEtC,SAAO,MAAM,cAAc,IAAI,MAAM,WAAW,KAAK;AACvD;AAKO,SAAS,qBAAqB,OAAO;AAE1C,SAAO,MAAM,mBAAmB,IAAI,MAAM,gBAAgB,KAAK;AACjE;AAKO,SAAS,qBAAqB,WAAW;AAC9C,MAAI,CAAC,cAAc,UAAU,eAAe,GAAG;AAC7C,WAAO,UAAU;AAAA,EACnB;AAEA,MAAI,iBAAiB;AAErB,MAAI,UAAU,UAAU,UAAU,OAAO,SAAS,GAAG;AACnD,sBAAkB;AAClB,QAAI,CAAC,cAAc,UAAU,OAAO,CAAC,EAAE,gBAAgB,GAAG;AACxD,wBAAkB,UAAU,OAAO,CAAC,EAAE;AAAA,IACxC,WAAW,CAAC,cAAc,UAAU,OAAO,CAAC,EAAE,eAAe,GAAG;AAC9D,wBAAkB,UAAU,OAAO,CAAC,EAAE;AAAA,IACxC;AAAA,EACF;AAEA,MAAI,UAAU,SAAS,UAAU,MAAM,SAAS,GAAG;AACjD,UAAM,YAAY,UAAU,MAAM,CAAC,EAAE;AACrC,UAAM,WAAW,UAAU,MAAM,UAAU,MAAM,SAAS,CAAC,EAAE;AAC7D,QAAI,cAAc,UAAU;AAC1B,UAAI,CAAC,cAAc,UAAU,OAAO,CAAC,EAAE,eAAe,GAAG;AACvD,0BAAkB,MAAM,UAAU,OAAO,CAAC,EAAE,eAAe;AAAA,MAC7D;AAEA,wBAAkB;AAAA,IACpB,OAAO;AACL,wBAAkB,MAAM,SAAS,OAAO,QAAQ;AAAA,IAClD;AAAA,EACF,WAAW,UAAU,mBAAmB,MAAM;AAC5C,sBAAkB,OAAO,UAAU,cAAc;AAAA,EACnD;AAEA,SAAO;AACT;AAKO,IAAM,kBAAkB,CAAC,UAAiB;AAC/C,MAAI,MAAM,oBAAoB,QAAQ,MAAM,oBAAoB,IAAI;AAClE,WAAO,SAAS,MAAM,gBAAgB;AAAA,EACxC;AAEA,SAAO,MAAM,mBAAmB;AAClC;AAKO,IAAM,6BAA6B,CAAC,UAAiB;AAC1D,MAAI,MAAM,kBAAkB;AAC1B,WAAO,MAAM,iBAAiB,QAAQ,OAAO,GAAG;AAAA,EAClD,WAAW,MAAM,iBAAiB;AAChC,WAAO,MAAM,gBAAgB,QAAQ,OAAO,GAAG;AAAA,EACjD;AAEA,SAAO;AACT;AAKO,IAAM,uBAAuB,CAAC,SAAmB;AACtD,SAAO,IAAI,KAAK,WAAW,SAAS;AAAA,IAClC,OAAO;AAAA,IACP,MAAM;AAAA,EACR,CAAC,EAAE,OAAO,IAAI;AAChB;AAKO,SAAS,0BAA0B,YAAY;AACpD,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,mBAAmBC,SAAQ,YAAY,cAAc;AAE3D,SAAO,OAAO,OAAO,gBAAgB,EAAE,IAAI,CAAC,mBAAmB;AAC7D,UAAM,kBAAkB,KAAK,eAAe,CAAC,GAAG,UAAU;AAE1D,oBAAgB,YAAY,eAAe;AAAA,MACzC,CAAC,cAAc,UAAU;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT,CAAC;AACH;;;ADxhBA,IAAM,gBAAgB,QAAQ;AAuCvB,SAAS,4BAA4B;AAC1C,QAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAGxD,MAAI;AACJ,MAAI,UAAU,SAAS,WAAW,KAAK,UAAU,SAAS,WAAW,GAAG;AAEtE,qBAAiB,QAAQ,WAAW,QAAQ;AAAA,EAC9C,WAAW,UAAU,SAAS,OAAO,GAAG;AAEtC,qBAAiB,QAAQ,WAAW,KAAK;AAAA,EAC3C,OAAO;AAEL,qBAAiB,QAAQ,WAAW,QAAQ;AAAA,EAC9C;AAEA,SAAO;AACT;AAKO,SAAS,qBAAqB,QAAgB;AACnD,MAAI,OAAO,cAAc;AACvB,WAAO,UAAU,OAAO,YAAY;AAAA,EACtC;AAEA,SAAO,KAAK,0BAA0B,GAAG,eAAe;AAC1D;AAKA,SAAS,sBAAsB,kBAA0B,QAAgB;AACvE,QAAM,uBACJ,OAAO,WAAW,OACd,GAAG,gBAAgB,cACnB,GAAG,gBAAgB;AAEzB,SAAO,KAAK,qBAAqB,MAAM,GAAG,oBAAoB;AAChE;AAKA,eAAsB,cAAc,YAAoB,QAAgB;AAEtE,MAAI;AACF,UAAM,OAAO,UAAU;AAAA,EACzB,SAAS,OAAY;AACnB,QAAI;AACF,YAAM,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,IAC7C,SAASC,QAAY;AACnB,UAAIA,QAAO,SAAS,UAAU;AAC5B,cAAM,IAAI;AAAA,UACR,sBAAsB,UAAU;AAAA,QAClC;AAAA,MACF;AAEA,YAAMA;AAAA,IACR;AAAA,EACF;AAGA,QAAM,QAAQ,MAAM,QAAQ,UAAU;AACtC,MAAI,OAAO,2BAA2B,SAAS,MAAM,SAAS,GAAG;AAC/D,UAAM,IAAI;AAAA,MACR,oBAAoB,UAAU;AAAA,IAChC;AAAA,EACF;AAGA,MAAI,OAAO,2BAA2B,MAAM;AAC1C,UAAM,GAAG,KAAK,YAAY,GAAG,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EAClE;AACF;AAKA,eAAsB,iBAAiB,QAAgB,YAAoB;AACzE,QAAM,kBAAkB,qBAAqB,MAAM;AACnD,QAAM,uBAAuB,0BAA0B;AAEvD,QAAM,gBAAgB,CAAC,OAAO,MAAM,KAAK;AAEzC,aAAW,UAAU,eAAe;AAClC,QACE,MAAM,OAAO,KAAK,iBAAiB,MAAM,CAAC,EACvC,KAAK,MAAM,IAAI,EACf,MAAM,MAAM,KAAK,GACpB;AACA,YAAM,GAAG,KAAK,iBAAiB,MAAM,GAAG,KAAK,YAAY,MAAM,GAAG;AAAA,QAChE,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MACE,OAAO,mCACP,OAAO,8BACP,OAAO,uBACP;AACA,UAAM;AAAA,MACJ,KAAK,sBAAsB,gCAAgC;AAAA,MAC3D,KAAK,YAAY,WAAW;AAAA,IAC9B;AAEA,UAAM;AAAA,MACJ;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA,KAAK,YAAY,mCAAmC;AAAA,IACtD;AAAA,EACF;AAEA,MAAI,OAAO,uBAAuB;AAChC,UAAM;AAAA,MACJ,KAAK,sBAAsB,yCAAyC;AAAA,MACpE,KAAK,YAAY,oBAAoB;AAAA,IACvC;AAAA,EACF;AAEA,MAAI,OAAO,SAAS;AAClB,UAAM;AAAA,MACJ,KAAK,sBAAsB,wCAAwC;AAAA,MACnE,KAAK,YAAY,mBAAmB;AAAA,IACtC;AAEA,UAAM;AAAA,MACJ,KAAK,sBAAsB,yCAAyC;AAAA,MACpE,KAAK,YAAY,qBAAqB;AAAA,IACxC;AAEA,UAAM;AAAA,MACJ;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA,KAAK,YAAY,4BAA4B;AAAA,IAC/C;AAEA,UAAM;AAAA,MACJ;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA,KAAK,YAAY,8BAA8B;AAAA,IACjD;AAAA,EACF;AACF;AAKO,SAAS,UAAU,YAAY;AACpC,QAAM,SAAS,kBAAkB,KAAK,YAAY,gBAAgB,CAAC;AACnE,QAAM,UAAU,SAAS,KAAK;AAE9B,SAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,WAAO,GAAG,SAASA,QAAO;AAC1B,YAAQ,GAAG,SAAS,MAAM;AAC1B,YAAQ,KAAK,MAAM;AACnB,YAAQ,KAAK,mDAAmD;AAAA,MAC9D,KAAK;AAAA,IACP,CAAC;AACD,YAAQ,SAAS;AAAA,EACnB,CAAC;AACH;AAKO,SAAS,8BACd,eACA,QACA;AAEA,MAAI,cAAc,UAAU;AAC1B,WAAO,SAAS,cAAc,QAAQ;AAAA,EACxC;AAGA,MACE,OAAO,6BAA6B,QACpCC,QAAO,cAAc,YAAY,UAAU,EAAE,WAAW,GACxD;AACA,UAAM,QAAQ,cAAc,WAAW,CAAC,EAAE,OAAO,CAAC;AAClD,WAAO,SAAS,GAAG,2BAA2B,KAAK,EAAE,YAAY,CAAC,OAAO;AAAA,EAC3E;AAEA,QAAM,YAAY,cAAc,WAAW,CAAC;AAG5C,MAAI,UAAU,cAAc;AAC1B,WAAO;AAAA,MACL,GAAG,UAAU,aAAa,QAAQ,OAAO,GAAG,EAAE,YAAY,CAAC;AAAA,IAC7D;AAAA,EACF;AAGA,MAAI,WAAW;AAEf,aAAW,SAAS,UAAU,QAAQ;AACpC,gBAAY,IAAI,2BAA2B,KAAK,CAAC;AAAA,EACnD;AAEA,MAAI,CAAC,cAAc,UAAU,YAAY,GAAG;AAC1C,gBAAY,IAAI,UAAU,YAAY;AAAA,EACxC;AAEA,cAAY,IAAI,WAAW,WAAW,MAAM,EAAE,QAAQ,OAAO,EAAE,CAAC;AAEhE,SAAO,SAAS,SAAS,YAAY,CAAC;AACxC;AAKO,SAAS,oBACd,WACA,QACA;AACA,MAAI,WAAW,UAAU,gBAAgB;AAEzC,aAAW,SAAS,UAAU,QAAQ;AACpC,gBAAY,IAAI,2BAA2B,KAAK,CAAC;AAAA,EACnD;AAEA,MAAI,CAAC,cAAc,UAAU,YAAY,GAAG;AAC1C,gBAAY,IAAI,UAAU,YAAY;AAAA,EACxC;AAEA,cAAY,IAAI,WAAW,WAAW,MAAM,EAAE,QAAQ,OAAO,EAAE,CAAC;AAEhE,SAAO,SAAS,QAAQ,EAAE,YAAY;AACxC;AAKO,SAAS,mBAAmB,eAAe;AAEhD,QAAM,YAAY,cAAc,uBAAuB,CAAC;AACxD,MAAI,CAAC,UAAU,cAAc,CAAC,UAAU,UAAU;AAChD,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,GAAG,UAAU,UAAU,IAAI,UAAU,QAAQ,EAAE;AACjE;AAKA,eAAsB,eACpB,kBACA,cACA,QACA;AACA,QAAM,eAAe,sBAAsB,kBAAkB,MAAM;AAGnE,QAAM,OAAO,MAAM,WAAW,cAAc;AAAA,IAC1C;AAAA,IACA;AAAA,IACA,IAAI,CAAC,SAAiB,aAAa,OAAO,YAAY,IAAI,CAAW;AAAA,IACrE,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AAGD,MAAI,OAAO,aAAa,MAAM;AAC5B,WAAO,SAAS,cAAc,MAAM;AAAA,MAClC,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAKA,eAAsB,UAAU,UAAkB;AAChD,QAAM,UAAU,SAAS,QAAQ,SAAS,KAAK;AAC/C,QAAM,UAAU,MAAM,UAAU,OAAO;AACvC,QAAM,OAAO,MAAM,QAAQ,QAAQ;AACnC,QAAM,KAAK,iBAAiB,OAAO;AACnC,QAAM,KAAK,KAAK,UAAU,QAAQ,IAAI;AAAA,IACpC,WAAW;AAAA,EACb,CAAC;AACD,QAAM,KAAK,IAAI;AAAA,IACb,MAAM;AAAA,EACR,CAAC;AAED,QAAM,QAAQ,MAAM;AACtB;AAOO,SAAS,UAAU,eAA+B;AACvD,SAAO,gBACH,cAAc,QAAQ,iBAAiB,aAAa,IACpD;AACN;;;ADjWA,IAAM,aAAa,OAAO,kBAA0B;AAClD,QAAM,SAAS,iBAAiB,aAAa;AAG7C,QAAM,YAAY,QAAQ,OAAO,OAAO;AAExC,QAAM,YAAY,OAAO,SACtB;AAAA,IACC,CAAC,WACC,OAAO,aAAa,OAAO,cAAc;AAAA,EAC7C,EACC,KAAK,GAAG;AACX,QAAM,aAAa,OAAO,aACtB,UAAU,OAAO,UAAU,IAC3B,KAAK,KAAK,QAAQ,IAAI,GAAG,QAAQC,UAAS,SAAS,CAAC;AAExD,QAAM,cAAc,YAAY,MAAM;AAEtC,MAAI;AACF,IAAAC,QAAO,MAAM;AAAA,EACf,SAAS,OAAY;AACnB,QAAI,OAAO,SAAS,mBAAmB;AACrC,eAAS,MAAM;AAAA,QACb,mCAAmC,OAAO,UAAU;AAAA,MACtD;AAAA,IACF;AAEA,UAAM;AAAA,EACR;AAEA,MAAI,CAAC,OAAO,YAAY,OAAO,SAAS,WAAW,GAAG;AACpD,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AAEA,MAAI,CAAC,OAAO,YAAY;AACtB,UAAM,WAAW,MAAM;AAAA,EACzB;AAEA,QAAM,QASF;AAAA,IACF,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,OAAO;AAAA,IACP,UAAU,CAAC;AAAA,EACb;AAEA,QAAM,iBAAiB,CAAC;AACxB,QAAM,mBAAmB,2BAA2B,MAAM,EAAE;AAAA,IAC1D,CAAC,kBAAkB,cAAc;AAAA,EACnC;AAEA,MAAI,OAAO,WAAW,QAAQ,CAAC,QAAQ,KAAK,EAAE,SAAS,OAAO,YAAY,GAAG;AAC3E,UAAM,iBAAiB,QAAQ,UAAU;AAAA,EAC3C;AAEA,QAAM,MAAM;AAAA,IACV,GAAG,SAAS,gBAAgB,OAAO,aAAa,YAAY,CAAC;AAAA,IAC7D,iBAAiB;AAAA,IACjB;AAAA,EACF;AAGA,aAAW,mBAAmB,kBAAkB;AAC9C,QAAI;AACF,YAAM,gBAAgB,MAAM;AAAA,QAC1B;AAAA,QACA;AAAA,MACF;AAEA,iBAAW,aAAa,cAAc,wBAAwB;AAC5D,YAAI,UAAU,UAAU;AACtB,qBAAW,WAAW,UAAU,UAAU;AACxC,kBAAM,SAAS,KAAK,OAAO;AAC3B,iBAAK,UAAU,OAAO;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AAEA,UAAI,cAAc,uBAAuB,WAAW,GAAG;AACrD,cAAM,IAAI;AAAA,UACR,6CAA6C,cAAc,iBAAiB;AAAA,QAC9E;AAAA,MACF;AAEA,YAAM,cAAc,cAAc,uBAAuB;AACzD,YAAM,kBAAkB;AAExB,YAAM,WAAW,mBAAmB,aAAa;AAGjD,YAAMC,OAAM,KAAK,KAAK,YAAY,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChE,aAAO,YAAY;AAEnB,oBAAc,eAAe,KAAK;AAAA,QAChC;AAAA,QACAF,UAAS,cAAc,QAAQ;AAAA,MACjC;AAEA,UAAI,OAAO,iBAAiB,OAAO;AACjC,mBAAW,aAAa,cAAc,wBAAwB;AAC5D,gBAAM,MAAM,MAAM,qBAAqB,SAAS;AAChD,gBAAM,UAAU,KAAK;AAAA,YACnB;AAAA,YACA;AAAA,YACA,oBAAoB,WAAW,MAAM;AAAA,UACvC;AACA,gBAAM,UAAU,SAAS,GAAG;AAAA,QAC9B;AAAA,MACF,OAAO;AACL,cAAM,OAAO,MAAM,sBAAsB,eAAe,MAAM;AAC9D,cAAM,WAAW,KAAK;AAAA,UACpB;AAAA,UACA;AAAA,UACAA,UAAS,cAAc,QAAQ;AAAA,QACjC;AACA,cAAM,UAAU,UAAU,IAAI;AAE9B,YAAI,OAAO,iBAAiB,OAAO;AACjC,gBAAM,UAAU,QAAQ;AAAA,QAC1B;AAAA,MACF;AAEA,qBAAe,KAAK,aAAa;AACjC,YAAM,iBAAiB,cAAc,aAAa;AAElD,YAAM,SAAS,eAAe;AAC9B,YAAM,UAAU,eAAe;AAC/B,YAAM,SAAS,eAAe;AAC9B,YAAM,aAAa,eAAe;AAAA,IACpC,SAAS,OAAY;AACnB,YAAM,SAAS,KAAK,OAAO,OAAO;AAClC,WAAK,UAAU,MAAM,OAAO;AAAA,IAC9B;AAEA,SAAK,UAAU;AAAA,EACjB;AAGA,MAAI,OAAO,iBAAiB,QAAQ;AAElC,WAAO,YAAY;AACnB,UAAM,OAAO,MAAM,qBAAqB,gBAAgB,MAAM;AAC9D,UAAM,UAAU,KAAK,KAAK,YAAY,YAAY,GAAG,IAAI;AAAA,EAC3D;AAGA,QAAM,UAAU,gBAAgB,OAAO,MAAM;AAC7C,QAAM,UAAU,KAAK,KAAK,YAAY,SAAS,GAAG,OAAO;AAGzD,MAAI,OAAO,WAAW;AACpB,UAAM,UAAU,UAAU;AAAA,EAC5B;AAEA,QAAM,iBAAiB,KAAK;AAAA,IAC1B;AAAA,IACA,OAAO,YAAY,oBAAoB;AAAA,EACzC;AAGA,MAAI,MAAM;AAAA,IACR,GAAG,SAAS,KAAK,OAAO,aAAa,YAAY,CAAC,0BAA0B,cAAc;AAAA,EAC5F;AAEA,WAAS,MAAM,EAAE,KAAK;AAEtB,QAAM,UAAU,QAAQ,OAAO,OAAO;AACtC,QAAM,iBAAiB,OAAO,UAAU,SAAS,IAAI;AAErD,MAAI,MAAM;AAAA,IACR,GAAG,SAAS,KAAK,OAAO,aAAa,YAAY,CAAC,kCAAkC,eAAe,QAAQ,CAAC,CAAC;AAAA,EAC/G;AAEA,SAAO;AACT;AAGA,IAAO,uBAAQ;","names":["mkdir","openDb","sanitize","uniqBy","find","first","groupBy","last","sortBy","moment","days","every","getAgencies","moment","size","every","moment","days","stop","calendars","calendarDates","trip","timetable","timetables","getAgencies","moment","sortBy","find","route","days","idx","last","first","groupBy","error","resolve","uniqBy","sanitize","openDb","mkdir"]}