{
  "version": 3,
  "sources": ["route_slope_core.js"],
  "sourcesContent": ["/*\n * static/js/route_slope_core.js \u2014 colouring a saved route by the steepness\n * of the ground it crosses (SNOW-910).\n *\n * The server samples the TERRAIN along a track \u2014 never the track's own\n * elevation, which on a zigzagging skin track is a completely different and\n * far gentler number (see apps/routes/services/slope_segments.py). What\n * arrives on a route feature is the compact form of that record:\n *\n *     properties.slope = { points: [[lon, lat], \u2026],   // N + 1\n *                          angles: [34.2, null, \u2026] }  // N\n *\n * with `null` for a segment the terrain had no answer for. This module\n * turns that into LineStrings, and decides which colour bucket an angle\n * falls in.\n *\n * SEGMENTS FOLLOW THE TRACK (SNOW-1053). A segment used to be the straight\n * chord `points[i]` \u2192 `points[i + 1]`, and the leg casing under it is drawn\n * from the route's real coordinates, so at high zoom the two parted \u2014 by\n * up to 9.9 m on a bend. The record now carries `seams`, one index per\n * boundary into the feature's own `geometry.coordinates` (the last\n * coordinate at or before that boundary), and `segmentPaths` draws a\n * segment as its two boundary points with the coordinates between them.\n * Without valid `seams` \u2014 a payload cached before the key, or a record\n * the server could not place on the geometry \u2014 it falls back to the chord.\n *\n * WHO READS IT NOW. SNOW-1017 took the slope-coloured line off the home\n * map below z14 \u2014 a route there draws as its legs (route_legs_core.js,\n * and docs/decisions/legs-not-slope-classes-on-the-map.md) \u2014 and from z14\n * map.js paints the route's core in these classes again, through\n * route_legs_core.js's slopeSegmentCollection, which builds on\n * `segmentFeatures`, and `colourExpression`. The trip page (trip_map.js)\n * paints the slope-coloured line with `segmentCollection` and\n * `colourExpression`; the rail and the elevation profile read `CLASSES`\n * and `classify`. The route detail sheet read the record in words until\n * SNOW-1095 removed it, and the functions that wrote those words with it.\n *\n * THREE STATES, AND THEY MUST NOT COLLAPSE INTO TWO:\n *\n *   - NO `slope` PROPERTY AT ALL \u2014 the route has never been sampled. It\n *     produces NOTHING here, and the trip page draws it as the flat line\n *     it has always been. An unsampled route is not an unknown one, and drawing\n *     a dashed \"we looked and could not tell\" over a track nothing has\n *     looked at would be a claim we have not earned.\n *   - A NULL ANGLE \u2014 sampled, no answer. That becomes an `unknown: true`\n *     feature, which the trip page paints dashed and grey, and it NEVER carries\n *     a `slope_class`: a step expression given a class for an unknown is\n *     one refactor away from painting it green.\n *   - A NUMBER \u2014 one of six buckets, below.\n *\n * THE PALETTE IS THE SLOPE LAYER'S, verbatim. The five painted classes\n * are `slope_classes_core.js`'s CLASSES (SNOW-1073) \u2014 the same hexes the\n * terrain filter's slope-class mode paints the map with and the same\n * `--color-slope-*` tokens the legend swatches use, so a route crossing a\n * shaded face is the colour of the shading under it. `gentle` is the sixth,\n * and has no layer counterpart because the layer paints nothing under\n * 30\u00B0 \u2014 but a LINE cannot be transparent where the layer is blank without\n * the track appearing to break, so the gentle band gets an explicit colour\n * of its own.\n *\n * Reads `self.pwaSlopeClassesCore` at parse time, so slope_classes_core.js\n * must load first on every page that loads this.\n *\n * Hex literals rather than CSS variables throughout: MapLibre paint\n * properties take literal colours and cannot reference a custom property.\n * Each names the token it mirrors, the same convention `ROUTE_LINE_COLOUR`\n * and the EAWS danger scale already follow in `map.js`.\n *\n * Every function here is pure.\n *\n * Exports (frozen `self.pwaRouteSlopeCore`):\n *\n *   CLASSES                \u2014 the six buckets, gentlest first\n *   UNKNOWN_COLOUR         \u2014 the dashed line's colour\n *   UNKNOWN_TOKEN          \u2014 and the token that colour mirrors\n *   PASSAGE_CORE_COLOUR    \u2014 the no-fall split line's core (SNOW-964)\n *   PASSAGE_CORE_TOKEN     \u2014 and the token that colour mirrors\n *   FALL_LINE_COLOUR       \u2014 the fall-line arrow's ink\n *   FALL_LINE_TOKEN        \u2014 and the token that colour mirrors\n *   classify(angle)        \u2014 a bucket index, or null for an unknown\n *   colourExpression()     \u2014 the MapLibre `step` painting a segment by class\n *   segmentPaths(s, c)     \u2014 each segment's [lon, lat] path along c\n *   segmentFeatures(f)     \u2014 one OWNED route feature -> its segments\n *   segmentCollection(fc)  \u2014 a routes FeatureCollection -> all of them\n *   fallLineCollection(fc) \u2014 its fall-line arrows as Points\n *\n * SNOW-964 adds `passages` to the record \u2014 the stretches where the TRACK\n * is on no-fall ground \u2014 and a `passage: true` flag on the segments they\n * name. Only ever `true`, never `false`, and only ever on a segment that\n * already has an angle: a feature can never carry both `unknown` and\n * `passage`, because unsurveyed ground is never inside a passage\n * (apps/routes/services/passages.py).\n *\n * The fall-line marks are the newest key: `fall_lines`, a list of\n * `{i, deg}` \u2014 an index into the same `angles` array, and the compass\n * bearing the ground there FACES, which is the direction downhill. They\n * arrive as a bearing per PLACE rather than as an aspect per segment, so\n * this module PLACES each one and classifies nothing: the server decided\n * where an arrow goes and how many there are\n * (apps/routes/services/fall_line.py), and a client that re-thinned them\n * would be a second opinion about which way a face runs.\n */\n\n// @ts-check\n\n(function () {\n  'use strict';\n\n  /**\n   * The six buckets an angle falls in, gentlest first.\n   *\n   * `from` is inclusive and `to` is exclusive, so a sample of exactly 35\u00B0\n   * is in `slope-35` and not in `slope-30`. That is the ramp's own\n   * convention \u2014 its classes are named for their lower bound \u2014 and getting\n   * it the other way round would put every boundary sample one band too\n   * gentle, which is the direction that matters.\n   *\n   * `token` names the `@theme` custom property the legend swatch is\n   * painted with (`src/css/main.css`) and `hex` is that token's value, so\n   * a test can assert the two agree and the line cannot drift from the key\n   * that explains it.\n   *\n   * The five steep classes are `slope_classes_core.js`'s CLASSES, the\n   * same frozen objects. `gentle` is ours: see the module comment on why\n   * a line needs a colour where the slope layer needs none.\n   */\n  const CLASSES = Object.freeze([\n    Object.freeze({ id: 'slope-gentle', from: 0, to: 30, token: '--color-slope-gentle', hex: '#38bdf8' }),\n    ...self.pwaSlopeClassesCore.CLASSES,\n  ]);\n\n  /**\n   * The colour of a segment the terrain had no answer for.\n   *\n   * A neutral grey, and deliberately NOT one of the six above \u2014 least of\n   * all the gentle one. \"We do not know\" must not be readable as \"not\n   * steep\", which is the whole reason the server keeps a reason rather\n   * than a null (see apps/locations/services/terrain.py). The dash carries\n   * the same meaning for a reader who cannot separate this grey from the\n   * over-50\u00B0 one.\n   *\n   * Mirrors `--color-slope-unknown` in `src/css/main.css`.\n   */\n  const UNKNOWN_COLOUR = '#94a3b8';\n\n  /**\n   * The `@theme` custom property `UNKNOWN_COLOUR` is the value of.\n   *\n   * The six painted classes each carry a `token` beside their `hex`; the\n   * unknown treatment is not one of them and so had nowhere to record its\n   * own. SNOW-960 gave it one, because the popup's elevation profile\n   * paints this same six-plus-one scale as an inline SVG \u2014 where a CSS\n   * variable IS readable, unlike in a MapLibre paint property \u2014 and\n   * reading the token is what keeps the chart from carrying a second copy\n   * of the palette that could drift from this one.\n   */\n  const UNKNOWN_TOKEN = '--color-slope-unknown';\n\n  /**\n   * The light core down the middle of a no-fall passage (SNOW-964).\n   *\n   * A passage is drawn as a SPLIT LINE: the band colour widened, with\n   * this run down its centre. The mark has to be legible over all six\n   * band colours and read as a GAP in the line rather than as a seventh\n   * class of ground, so it is a near-white off the steepness scale\n   * entirely.\n   *\n   * `transparent` is not an option: MapLibre cannot punch a hole through\n   * one line layer to another, so a transparent core would reveal the\n   * dark casing under the route and read as a shadow. A shade off\n   * `#ffffff` rather than pure white, kept from when pure white was\n   * another marker's halo (the crux ring, removed by SNOW-1066).\n   *\n   * Mirrors `--color-passage-core` in `src/css/main.css`; the literal is\n   * here because a MapLibre paint property cannot read a custom\n   * property, the same convention `UNKNOWN_COLOUR` follows.\n   */\n  const PASSAGE_CORE_COLOUR = '#f8fafc';\n\n  /** The `@theme` custom property `PASSAGE_CORE_COLOUR` is the value of. */\n  const PASSAGE_CORE_TOKEN = '--color-passage-core';\n\n  /**\n   * The fall-line arrow's ink.\n   *\n   * Near-black, and deliberately not a hue of its own. An arrow says\n   * which way to look, not how steep the ground is, and a marker tinted\n   * from the ramp reads as a further class of ground \u2014 a colour of its\n   * own would make an arrow look like a seventh band.\n   *\n   * It has a token of its own because a token named for one mark but\n   * used by two is exactly the drift SNOW-969 spent two tickets closing.\n   * `--color-route-line-casing` already carries this same value under\n   * another name, on the same reasoning.\n   *\n   * Registered `sdf: true` in `map.js`, so this value reaches the map as\n   * `icon-color` rather than as pixel data \u2014 the arrow itself is an\n   * alpha mask (`route_markers_core.js`).\n   *\n   * Mirrors `--color-fall-line-arrow` in `src/css/main.css`; the literal\n   * is here because a MapLibre paint property cannot read a custom\n   * property, the convention `UNKNOWN_COLOUR` follows.\n   */\n  const FALL_LINE_COLOUR = '#1a1916';\n\n  /** The `@theme` custom property `FALL_LINE_COLOUR` is the value of. */\n  const FALL_LINE_TOKEN = '--color-fall-line-arrow';\n\n  /**\n   * Which bucket an angle falls in.\n   *\n   * @param {?number} angle Degrees from horizontal, or null/undefined for\n   *   a segment the terrain had no answer for.\n   * @returns {?number} The index into `CLASSES`, or null when there is no\n   *   angle to classify. A non-finite number answers null too \u2014 the\n   *   callers have nowhere to put an exception, and an unknown treatment\n   *   is the honest reading of a number that is not one.\n   */\n  function classify(angle) {\n    if (typeof angle !== 'number' || !Number.isFinite(angle)) return null;\n    // Walked from the top so the open-ended last class needs no special\n    // case, and so a negative angle (which the sampler cannot produce, but\n    // a hand-written record could) still lands in the gentle bucket rather\n    // than falling off the end.\n    for (let i = CLASSES.length - 1; i > 0; i -= 1) {\n      if (angle >= CLASSES[i].from) return i;\n    }\n    return 0;\n  }\n\n  /**\n   * One no-fall passage, as the server sends it (SNOW-964).\n   *\n   * Every field is optional because this arrives from a feature property\n   * and is checked rather than trusted. `fall_line` is ABSENT \u2014 never\n   * null \u2014 on a passage nothing could classify, which is a real state:\n   * steep ground earns the mark, and a missing aspect is a fact about\n   * the survey.\n   *\n   * @typedef {object} Passage\n   * @property {number} [from] First segment index, inclusive.\n   * @property {number} [to] Last segment index, inclusive.\n   * @property {number} [m] Its along-track length, in metres.\n   * @property {string} [fall_line] `descending`, `climbing` or `crossing`.\n   */\n\n  /**\n   * The segment indices the passages name.\n   *\n   * The server sends INDEX PAIRS into the same `angles` array this module\n   * is already pairing into segments, so there is only one geometry and\n   * nothing to disagree with it. A malformed entry is skipped rather than\n   * thrown on: the record arrives from a feature property, and a route\n   * that fails to draw is worse than one drawn without its marks.\n   *\n   * @param {*} passages The record's `passages`, unchecked.\n   * @returns {Set<number>} Every index inside a passage, possibly empty.\n   */\n  function passageIndices(passages) {\n    const marked = new Set();\n    if (!Array.isArray(passages)) return marked;\n    for (let i = 0; i < passages.length; i += 1) {\n      const passage = passages[i] || {};\n      const from = passage.from;\n      const to = passage.to;\n      if (typeof from !== 'number' || typeof to !== 'number') continue;\n      if (!Number.isFinite(from) || !Number.isFinite(to) || to < from) continue;\n      for (let index = from; index <= to; index += 1) marked.add(index);\n    }\n    return marked;\n  }\n\n  /**\n   * One route's slope record, as the server sends it.\n   *\n   * Every field is optional because it arrives from a feature property\n   * and is checked rather than trusted.\n   *\n   * @typedef {object} Slope\n   * @property {Array<Array<number>>} [points] N + 1 boundary coordinates.\n   * @property {Array<?number>} [angles] N segment angles, null unknown.\n   * @property {Array<number>} [seams] N + 1 indices into the feature's\n   *   geometry: the last coordinate at or before each boundary (SNOW-1053).\n   * @property {Array<Passage>} [passages] The no-fall passages.\n   */\n\n  /**\n   * Whether `seams` can place every boundary on `coordinates`.\n   *\n   * One per boundary, each a whole number inside the coordinates array,\n   * and never decreasing \u2014 a seam that went backwards would draw a\n   * segment over ground behind it.\n   *\n   * @param {*} seams The record's `seams`, unchecked.\n   * @param {number} boundaryCount How many boundary points the record has.\n   * @param {number} coordinateCount How many coordinates the geometry has.\n   * @returns {boolean} True when every seam is usable.\n   */\n  function validSeams(seams, boundaryCount, coordinateCount) {\n    if (!Array.isArray(seams) || seams.length !== boundaryCount) return false;\n    for (let i = 0; i < seams.length; i += 1) {\n      const seam = seams[i];\n      if (!Number.isInteger(seam) || seam < 0 || seam >= coordinateCount) return false;\n      if (i > 0 && seam < seams[i - 1]) return false;\n    }\n    return true;\n  }\n\n  /**\n   * A coordinate as a bare `[lon, lat]`, its elevation dropped.\n   *\n   * @param {Array<number>} coordinate `[lon, lat]` or `[lon, lat, ele]`.\n   * @returns {Array<number>} `[lon, lat]`.\n   */\n  function lonLat(coordinate) {\n    return [coordinate[0], coordinate[1]];\n  }\n\n  /**\n   * Whether two coordinates name the same place, elevation aside.\n   *\n   * @param {Array<number>} a A coordinate.\n   * @param {Array<number>} b Another.\n   * @returns {boolean} True when longitude and latitude are equal.\n   */\n  function samePlace(a, b) {\n    return a[0] === b[0] && a[1] === b[1];\n  }\n\n  /**\n   * The path each segment of a slope record is drawn along.\n   *\n   * With valid `seams`, segment i is `points[i]`, then every coordinate\n   * after `seams[i]` up to and including `seams[i + 1]`, then\n   * `points[i + 1]` \u2014 so it lies on the same line the leg casing is drawn\n   * from. A coordinate equal to either boundary point is left out rather\n   * than repeated: on the merged terrain track most boundaries ARE\n   * coordinates, and a doubled vertex is a zero-length step to every\n   * consumer. Elevations are dropped, so a path stays two-dimensional like\n   * the chord it replaces.\n   *\n   * Without valid `seams` every segment is the chord\n   * `[points[i], points[i + 1]]`, which is what was drawn before SNOW-1053.\n   *\n   * @param {?Slope} slope The record, unchecked beyond its shape.\n   * @param {*} coordinates The feature's `geometry.coordinates`.\n   * @returns {Array<Array<Array<number>>>} One path per segment; empty\n   *   when the record's halves do not pair up.\n   */\n  function segmentPaths(slope, coordinates) {\n    const points = slope && slope.points;\n    const angles = slope && slope.angles;\n    if (!Array.isArray(points) || !Array.isArray(angles)) return [];\n    if (points.length !== angles.length + 1) return [];\n\n    const seams = slope && slope.seams;\n    const follow = Array.isArray(coordinates)\n      && validSeams(seams, points.length, coordinates.length);\n\n    const paths = [];\n    for (let i = 0; i < angles.length; i += 1) {\n      const start = points[i];\n      const end = points[i + 1];\n      if (!follow || !seams) {\n        paths.push([start, end]);\n        continue;\n      }\n      const path = [start];\n      for (let c = seams[i] + 1; c <= seams[i + 1]; c += 1) {\n        const coordinate = coordinates[c];\n        if (!Array.isArray(coordinate)) continue;\n        if (samePlace(coordinate, start) || samePlace(coordinate, end)) continue;\n        path.push(lonLat(coordinate));\n      }\n      path.push(end);\n      paths.push(path);\n    }\n    return paths;\n  }\n\n  /**\n   * The LineStrings one route's slope record draws as.\n   *\n   * The record's N + 1 coordinates are shared endpoints: segment i runs\n   * from `points[i]` to `points[i + 1]`. Pairing them back out here is\n   * what lets the payload carry half the coordinates it otherwise would.\n   * Between the two, it follows the feature's own geometry where the\n   * record carries `seams` \u2014 see `segmentPaths`.\n   *\n   * Each feature carries the owning route's `uuid`, so a consumer can get\n   * from the segment back to its route \u2014 `route_legs_core.js` builds the\n   * home map's passage marks from these.\n   *\n   * A PENDING ROUTE IS COLOURED LIKE ANY OTHER (SNOW-1218). A followed\n   * share was drawn as a teal dash until 2026-10-24; a shared route now\n   * reads as the sharer's does. It has no `uuid` \u2014 a non-owner is never\n   * handed one \u2014 so its segments carry the share's `token` instead, the\n   * identifier its feature already carries.\n   *\n   * A route with no `slope` property produces NOTHING \u2014 see the\n   * module comment's three states. So does a record whose halves do not\n   * pair up, which would otherwise draw segments against the wrong ground.\n   *\n   * @param {?{properties?: any, geometry?: any}} feature One route feature\n   *   from the routes payload, as served by `routes:geojson`.\n   * @returns {Array<object>} Its segment features, possibly empty.\n   */\n  function segmentFeatures(feature) {\n    const properties = (feature && feature.properties) || {};\n    const slope = properties.slope;\n    if (!slope) return [];\n\n    const points = slope.points;\n    const angles = slope.angles;\n    if (!Array.isArray(points) || !Array.isArray(angles)) return [];\n    if (points.length !== angles.length + 1) return [];\n\n    const identity = properties.uuid\n      ? { uuid: properties.uuid }\n      : properties.token ? { token: properties.token } : {};\n    const marked = passageIndices(slope.passages);\n    const geometry = feature && feature.geometry;\n    const paths = segmentPaths(slope, geometry && geometry.coordinates);\n\n    const features = [];\n    for (let i = 0; i < angles.length; i += 1) {\n      const slopeClass = classify(angles[i]);\n      features.push({\n        type: 'Feature',\n        geometry: { type: 'LineString', coordinates: paths[i] },\n        // An unknown segment carries `unknown` and NO `slope_class`, and a\n        // known one the reverse. Never both, never neither \u2014 the two\n        // layers filter on exactly this and a segment answering to both\n        // would be painted twice.\n        //\n        // SNOW-964's `passage` joins the KNOWN branch only, and is set\n        // to `true` or left off entirely \u2014 never `false`, the rule\n        // the server's passage pass follows. The server never names an\n        // unknown segment in a passage, and this is the second place\n        // that holds: a feature cannot carry both.\n        properties: slopeClass === null\n          ? Object.assign({ unknown: true }, identity)\n          : Object.assign(\n            { slope_class: slopeClass },\n            marked.has(i) ? { passage: true } : {},\n            identity,\n          ),\n      });\n    }\n    return features;\n  }\n\n  /**\n   * The MapLibre `step` expression painting a segment by its slope class.\n   *\n   * Built from CLASSES rather than written out, so the trip page and the\n   * map page cannot drift: both read this one expression. A `step` takes\n   * the first colour, then a (stop, colour) pair per class after it \u2014 the\n   * stops are the CLASS INDICES `classify` assigns, not angles.\n   *\n   * @returns {Array<*>} The expression.\n   */\n  function colourExpression() {\n    /** @type {Array<*>} */\n    const expression = ['step', ['get', 'slope_class'], CLASSES[0].hex];\n    for (let i = 1; i < CLASSES.length; i += 1) expression.push(i, CLASSES[i].hex);\n    return expression;\n  }\n\n  /**\n   * Every route's segments, as one FeatureCollection.\n   *\n   * The source the trip page hands to MapLibre. Always a valid collection, even\n   * when nothing in the payload has been sampled \u2014 an empty one paints\n   * nothing, where a null would make `setData` throw.\n   *\n   * @param {?{features?: Array<any>}} geojson The routes FeatureCollection.\n   * @returns {{type: string, features: Array<object>}} The segments.\n   */\n  function segmentCollection(geojson) {\n    const features = (geojson && geojson.features) || [];\n    const segments = [];\n    for (let i = 0; i < features.length; i += 1) {\n      const own = segmentFeatures(features[i]);\n      for (let j = 0; j < own.length; j += 1) segments.push(own[j]);\n    }\n    return { type: 'FeatureCollection', features: segments };\n  }\n\n  /**\n   * One fall-line mark, as the server sends it.\n   *\n   * Both fields are optional because this arrives from a feature\n   * property and is checked rather than trusted.\n   *\n   * @typedef {object} FallLineMark\n   * @property {number} [i] The segment index the mark sits on.\n   * @property {number} [deg] The bearing the ground there faces, in\n   *   whole compass degrees \u2014 which is downhill.\n   */\n\n  /**\n   * Every route's fall-line arrows, as one Point FeatureCollection.\n   *\n   * The mark names a SEGMENT and the arrow is placed at that segment's\n   * MIDPOINT, which is where the aspect was sampled \u2014 the \"sample at the\n   * midpoints\" rule in\n   * docs/decisions/a-slope-segment-is-the-shared-record.md. Placing it\n   * on a boundary instead would put the arrow a dozen metres from the\n   * ground it describes.\n   *\n   * A straight average of the two boundary coordinates, not a\n   * great-circle midpoint: over one 25 m stride the two differ by well\n   * under a millimetre, and the spherical form would be arithmetic\n   * nobody could check by eye.\n   *\n   * A PENDING ROUTE PRODUCES NOTHING. No map draws these arrows since\n   * SNOW-1019, so SNOW-1218, which colours a pending route's segments\n   * like any other's, left this as it was: a non-owner's feature carries\n   * nothing but its token, and these carry only a `uuid`.\n   *\n   * Always a valid collection, even when nothing is marked \u2014 `setData`\n   * throws on a null.\n   *\n   * @param {?{features?: Array<any>}} geojson The routes FeatureCollection.\n   * @returns {{type: string, features: Array<object>}} The arrows, each\n   *   carrying `deg` for `icon-rotate` and the owning route's `uuid`.\n   */\n  function fallLineCollection(geojson) {\n    const features = (geojson && geojson.features) || [];\n    const arrows = [];\n    for (let i = 0; i < features.length; i += 1) {\n      const properties = (features[i] && features[i].properties) || {};\n      if (properties.pending) continue;\n      const slope = properties.slope;\n      const marks = slope && slope.fall_lines;\n      const points = (slope && slope.points) || [];\n      if (!Array.isArray(marks) || !Array.isArray(points)) continue;\n      for (let j = 0; j < marks.length; j += 1) {\n        const mark = marks[j] || {};\n        const index = mark.i;\n        const deg = mark.deg;\n        if (typeof index !== 'number' || typeof deg !== 'number') continue;\n        if (!Number.isFinite(index) || !Number.isFinite(deg)) continue;\n        // An index past the end of the geometry is a record whose halves\n        // disagree. Skipping it loses one arrow; trusting it would throw\n        // out of the whole routes overlay.\n        const from = points[index];\n        const to = points[index + 1];\n        if (!Array.isArray(from) || !Array.isArray(to)) continue;\n        arrows.push({\n          type: 'Feature',\n          geometry: {\n            type: 'Point',\n            coordinates: [(from[0] + to[0]) / 2, (from[1] + to[1]) / 2],\n          },\n          properties: Object.assign(\n            { deg: deg },\n            properties.uuid ? { uuid: properties.uuid } : {},\n          ),\n        });\n      }\n    }\n    return { type: 'FeatureCollection', features: arrows };\n  }\n\n  self.pwaRouteSlopeCore = Object.freeze({\n    CLASSES: CLASSES,\n    UNKNOWN_COLOUR: UNKNOWN_COLOUR,\n    UNKNOWN_TOKEN: UNKNOWN_TOKEN,\n    PASSAGE_CORE_COLOUR: PASSAGE_CORE_COLOUR,\n    PASSAGE_CORE_TOKEN: PASSAGE_CORE_TOKEN,\n    FALL_LINE_COLOUR: FALL_LINE_COLOUR,\n    FALL_LINE_TOKEN: FALL_LINE_TOKEN,\n    classify: classify,\n    colourExpression: colourExpression,\n    segmentPaths: segmentPaths,\n    segmentFeatures: segmentFeatures,\n    segmentCollection: segmentCollection,\n    fallLineCollection: fallLineCollection,\n  });\n})();\n"],
  "mappings": "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",
  "names": ["CLASSES", "UNKNOWN_COLOUR", "UNKNOWN_TOKEN", "PASSAGE_CORE_COLOUR", "PASSAGE_CORE_TOKEN", "FALL_LINE_COLOUR", "FALL_LINE_TOKEN", "classify", "angle", "i", "passageIndices", "passages", "marked", "passage", "from", "to", "index", "validSeams", "seams", "boundaryCount", "coordinateCount", "seam", "lonLat", "coordinate", "samePlace", "a", "b", "segmentPaths", "slope", "coordinates", "points", "angles", "follow", "paths", "start", "end", "path", "c", "segmentFeatures", "feature", "properties", "identity", "geometry", "features", "slopeClass", "colourExpression", "expression", "segmentCollection", "geojson", "segments", "own", "j", "fallLineCollection", "arrows", "marks", "mark", "deg"]
}
